@jpp-toolkit/rspack-config 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,10 +1,19 @@
1
1
  import { RspackOptions } from "@rspack/core";
2
2
 
3
- //#region src/create-fivem-rspack-config.d.ts
4
- declare function createFivemRspackConfig(overrides?: RspackOptions): RspackOptions;
3
+ //#region src/enums/environment.d.ts
4
+ declare const Environment: {
5
+ readonly DEVELOPMENT: "development";
6
+ readonly PRODUCTION: "production";
7
+ };
8
+ type Environment = (typeof Environment)[keyof typeof Environment];
5
9
  //#endregion
6
- //#region src/utils/merge-config.d.ts
7
- declare const mergeConfig: (firstConfiguration: object | object[], ...configurations: object[]) => object;
10
+ //#region src/create-fivem-rspack-config.d.ts
11
+ type CreateFivemRspackConfigOptions = {
12
+ readonly resourceName?: string | undefined;
13
+ readonly environment?: Environment | undefined;
14
+ readonly cwd?: string | undefined;
15
+ };
16
+ declare function createFivemRspackConfig(options?: CreateFivemRspackConfigOptions): RspackOptions[];
8
17
  //#endregion
9
- export { createFivemRspackConfig, mergeConfig };
18
+ export { CreateFivemRspackConfigOptions, createFivemRspackConfig };
10
19
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,39 +1,57 @@
1
1
  import path from "node:path";
2
- import { mergeWithRules } from "webpack-merge";
2
+ import { rspack } from "@rspack/core";
3
+ import { existsSync } from "node:fs";
3
4
 
4
- //#region src/utils/merge-config.ts
5
- const mergeConfig = mergeWithRules({ module: { rules: {
6
- test: "match",
7
- use: {
8
- loader: "match",
9
- options: "merge"
10
- }
11
- } } });
5
+ //#region src/enums/environment.ts
6
+ const Environment = {
7
+ DEVELOPMENT: "development",
8
+ PRODUCTION: "production"
9
+ };
10
+
11
+ //#endregion
12
+ //#region src/enums/fivem-entry-type.ts
13
+ const FivemEntryType = {
14
+ CLIENT: "client",
15
+ SERVER: "server",
16
+ SHARED: "shared",
17
+ UI: "ui"
18
+ };
19
+
20
+ //#endregion
21
+ //#region src/utils/find-first-existing-path.ts
22
+ function findFirstExistingPath(possiblePaths) {
23
+ for (const p of possiblePaths) if (existsSync(p)) return p;
24
+ }
12
25
 
13
26
  //#endregion
14
27
  //#region src/create-fivem-rspack-config.ts
15
- function createFivemRspackConfig(overrides = {}) {
16
- const cwd = overrides.context ?? process.cwd();
17
- const mode = overrides.mode ?? (process.env.NODE_ENV === "production" ? "production" : "development");
18
- const isProduction = mode === "production";
19
- return mergeConfig({
20
- name: "fivem",
28
+ function buildConfig(options) {
29
+ const { cwd, entry, entryType, resourceName, environment } = options;
30
+ const htmlTemplateFile = findFirstExistingPath([path.resolve(cwd, `src/${entryType}/index.html`), path.resolve(cwd, `src/${entryType}.html`)]);
31
+ const publicPath = `https://cfx-nui-${resourceName}/dist/${entryType}/`;
32
+ const isProduction = environment === "production";
33
+ const isUi = entryType === FivemEntryType.UI;
34
+ return {
35
+ name: `fivem-${entryType}`,
21
36
  context: cwd,
22
- target: "node16",
37
+ target: isUi ? "web" : "node16",
23
38
  devtool: false,
24
- mode,
25
- entry: path.resolve(cwd, "src/index.ts"),
39
+ mode: environment,
40
+ entry,
26
41
  output: {
27
42
  clean: true,
28
- path: path.resolve(cwd, "dist")
43
+ path: path.resolve(cwd, "dist", entryType),
44
+ ...isUi ? { publicPath } : {}
29
45
  },
30
46
  optimization: { minimize: isProduction },
31
47
  resolve: {
32
48
  extensions: [
33
49
  ".js",
50
+ ".jsx",
51
+ ".ts",
52
+ ".tsx",
34
53
  ".json",
35
- ".wasm",
36
- ".ts"
54
+ ".wasm"
37
55
  ],
38
56
  extensionAlias: {
39
57
  ".js": [".ts", ".js"],
@@ -43,13 +61,16 @@ function createFivemRspackConfig(overrides = {}) {
43
61
  tsConfig: path.resolve(cwd, "tsconfig.json")
44
62
  },
45
63
  node: {
46
- global: false,
47
- __filename: false,
48
- __dirname: false
64
+ global: isUi,
65
+ __filename: isUi,
66
+ __dirname: isUi
67
+ },
68
+ externalsPresets: {
69
+ node: !isUi,
70
+ web: isUi
49
71
  },
50
- externalsPresets: { node: true },
51
72
  module: { rules: [{
52
- test: /\.(?:ts|cts|mts)$/iu,
73
+ test: /\.(?:ts|tsx|cts|mts)$/iu,
53
74
  type: "javascript/auto",
54
75
  exclude: [/dist\//u, /node_modules\//u],
55
76
  loader: "builtin:swc-loader",
@@ -57,14 +78,28 @@ function createFivemRspackConfig(overrides = {}) {
57
78
  minify: isProduction,
58
79
  module: { type: "nodenext" },
59
80
  jsc: {
60
- target: "es2021",
61
- parser: { syntax: "typescript" },
62
- transform: { useDefineForClassFields: true },
81
+ target: isUi ? "es5" : "es2021",
82
+ parser: {
83
+ syntax: "typescript",
84
+ tsx: true
85
+ },
86
+ transform: {
87
+ react: { runtime: "automatic" },
88
+ useDefineForClassFields: true
89
+ },
63
90
  keepClassNames: true,
64
91
  externalHelpers: false
65
92
  }
66
93
  }
67
- }] },
94
+ }, ...isUi ? [{
95
+ test: /\.(?:jpe?g|png|gif|svg)$/iu,
96
+ type: "asset/resource"
97
+ }] : []] },
98
+ ...isUi ? { experiments: { css: true } } : {},
99
+ ...isUi && htmlTemplateFile ? { plugins: [new rspack.HtmlRspackPlugin({
100
+ template: htmlTemplateFile,
101
+ publicPath
102
+ })] } : {},
68
103
  watchOptions: {
69
104
  aggregateTimeout: 200,
70
105
  ignored: [
@@ -77,9 +112,29 @@ function createFivemRspackConfig(overrides = {}) {
77
112
  "**/tmp"
78
113
  ]
79
114
  }
80
- }, overrides);
115
+ };
116
+ }
117
+ function createFivemRspackConfig(options = {}) {
118
+ const environment = options.environment ?? (process.env.NODE_ENV === Environment.PRODUCTION ? Environment.PRODUCTION : Environment.DEVELOPMENT);
119
+ const cwd = options.cwd ?? process.cwd();
120
+ const resourceName = options.resourceName ?? path.basename(cwd);
121
+ const configs = [];
122
+ for (const entryType of Object.values(FivemEntryType)) {
123
+ const entry = findFirstExistingPath([path.resolve(cwd, `src/${entryType}/index.ts`), path.resolve(cwd, `src/${entryType}.ts`)]);
124
+ if (!entry) continue;
125
+ const config = buildConfig({
126
+ cwd,
127
+ entry,
128
+ entryType,
129
+ environment,
130
+ resourceName
131
+ });
132
+ configs.push(config);
133
+ }
134
+ if (configs.length === 0) throw new Error("No valid FiveM resource entries found.");
135
+ return configs;
81
136
  }
82
137
 
83
138
  //#endregion
84
- export { createFivemRspackConfig, mergeConfig };
139
+ export { createFivemRspackConfig };
85
140
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/merge-config.ts","../src/create-fivem-rspack-config.ts"],"sourcesContent":["import { mergeWithRules } from 'webpack-merge';\n\nexport const mergeConfig = mergeWithRules({\n module: {\n rules: {\n test: 'match',\n use: {\n loader: 'match',\n options: 'merge',\n },\n },\n },\n});\n","import path from 'node:path';\n\nimport type { RspackOptions } from '@rspack/core';\n\nimport { mergeConfig } from './utils/merge-config';\n\nexport function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOptions {\n const cwd = overrides.context ?? process.cwd();\n const mode =\n overrides.mode ?? (process.env.NODE_ENV === 'production' ? 'production' : 'development');\n const isProduction = mode === 'production';\n\n const config: RspackOptions = {\n name: 'fivem',\n\n context: cwd,\n\n target: 'node16',\n devtool: false,\n mode,\n\n entry: path.resolve(cwd, 'src/index.ts'),\n\n output: {\n clean: true,\n path: path.resolve(cwd, 'dist'),\n },\n\n optimization: {\n minimize: isProduction,\n },\n\n resolve: {\n extensions: ['.js', '.json', '.wasm', '.ts'],\n extensionAlias: {\n '.js': ['.ts', '.js'],\n '.cjs': ['.cts', '.cjs'],\n '.mjs': ['.mts', '.mjs'],\n },\n tsConfig: path.resolve(cwd, 'tsconfig.json'),\n },\n\n node: {\n global: false,\n __filename: false,\n __dirname: false,\n },\n\n externalsPresets: {\n node: true,\n },\n\n module: {\n rules: [\n {\n test: /\\.(?:ts|cts|mts)$/iu,\n type: 'javascript/auto',\n exclude: [/dist\\//u, /node_modules\\//u],\n loader: 'builtin:swc-loader',\n options: {\n minify: isProduction,\n module: {\n type: 'nodenext',\n },\n jsc: {\n target: 'es2021',\n parser: {\n syntax: 'typescript',\n },\n transform: {\n useDefineForClassFields: true,\n },\n keepClassNames: true,\n externalHelpers: false,\n },\n },\n },\n ],\n },\n\n watchOptions: {\n aggregateTimeout: 200,\n ignored: [\n '**/.git',\n '**/.turbo',\n '**/coverage',\n '**/dist',\n '**/generated',\n '**/old',\n '**/tmp',\n ],\n },\n };\n\n return mergeConfig(config, overrides);\n}\n"],"mappings":";;;;AAEA,MAAa,cAAc,eAAe,EACtC,QAAQ,EACJ,OAAO;CACH,MAAM;CACN,KAAK;EACD,QAAQ;EACR,SAAS;EACZ;CACJ,EACJ,EACJ,CAAC;;;;ACNF,SAAgB,wBAAwB,YAA2B,EAAE,EAAiB;CAClF,MAAM,MAAM,UAAU,WAAW,QAAQ,KAAK;CAC9C,MAAM,OACF,UAAU,SAAS,QAAQ,IAAI,aAAa,eAAe,eAAe;CAC9E,MAAM,eAAe,SAAS;AAoF9B,QAAO,YAlFuB;EAC1B,MAAM;EAEN,SAAS;EAET,QAAQ;EACR,SAAS;EACT;EAEA,OAAO,KAAK,QAAQ,KAAK,eAAe;EAExC,QAAQ;GACJ,OAAO;GACP,MAAM,KAAK,QAAQ,KAAK,OAAO;GAClC;EAED,cAAc,EACV,UAAU,cACb;EAED,SAAS;GACL,YAAY;IAAC;IAAO;IAAS;IAAS;IAAM;GAC5C,gBAAgB;IACZ,OAAO,CAAC,OAAO,MAAM;IACrB,QAAQ,CAAC,QAAQ,OAAO;IACxB,QAAQ,CAAC,QAAQ,OAAO;IAC3B;GACD,UAAU,KAAK,QAAQ,KAAK,gBAAgB;GAC/C;EAED,MAAM;GACF,QAAQ;GACR,YAAY;GACZ,WAAW;GACd;EAED,kBAAkB,EACd,MAAM,MACT;EAED,QAAQ,EACJ,OAAO,CACH;GACI,MAAM;GACN,MAAM;GACN,SAAS,CAAC,WAAW,kBAAkB;GACvC,QAAQ;GACR,SAAS;IACL,QAAQ;IACR,QAAQ,EACJ,MAAM,YACT;IACD,KAAK;KACD,QAAQ;KACR,QAAQ,EACJ,QAAQ,cACX;KACD,WAAW,EACP,yBAAyB,MAC5B;KACD,gBAAgB;KAChB,iBAAiB;KACpB;IACJ;GACJ,CACJ,EACJ;EAED,cAAc;GACV,kBAAkB;GAClB,SAAS;IACL;IACA;IACA;IACA;IACA;IACA;IACA;IACH;GACJ;EACJ,EAE0B,UAAU"}
1
+ {"version":3,"file":"index.mjs","names":["configs: RspackOptions[]"],"sources":["../src/enums/environment.ts","../src/enums/fivem-entry-type.ts","../src/utils/find-first-existing-path.ts","../src/create-fivem-rspack-config.ts"],"sourcesContent":["export const Environment = {\n DEVELOPMENT: 'development',\n PRODUCTION: 'production',\n} as const;\nexport type Environment = (typeof Environment)[keyof typeof Environment];\n","export const FivemEntryType = {\n CLIENT: 'client',\n SERVER: 'server',\n SHARED: 'shared',\n UI: 'ui',\n} as const;\nexport type FivemEntryType = (typeof FivemEntryType)[keyof typeof FivemEntryType];\n","import { existsSync } from 'node:fs';\n\nexport function findFirstExistingPath(possiblePaths: string[]): string | undefined {\n for (const p of possiblePaths) if (existsSync(p)) return p;\n return undefined;\n}\n","import path from 'node:path';\n\nimport { rspack } from '@rspack/core';\nimport type { RspackOptions } from '@rspack/core';\n\nimport { Environment, FivemEntryType } from './enums';\nimport { findFirstExistingPath } from './utils/find-first-existing-path';\n\ntype BuildConfigOptions = {\n readonly cwd: string;\n readonly entry: string;\n readonly entryType: FivemEntryType;\n readonly resourceName: string;\n readonly environment: Environment;\n};\n\nfunction buildConfig(options: BuildConfigOptions): RspackOptions {\n const { cwd, entry, entryType, resourceName, environment } = options;\n\n const htmlTemplateFile = findFirstExistingPath([\n path.resolve(cwd, `src/${entryType}/index.html`),\n path.resolve(cwd, `src/${entryType}.html`),\n ]);\n const publicPath = `https://cfx-nui-${resourceName}/dist/${entryType}/`;\n\n const isProduction = environment === 'production';\n const isUi = entryType === FivemEntryType.UI;\n\n const config: RspackOptions = {\n name: `fivem-${entryType}`,\n\n context: cwd,\n\n target: isUi ? 'web' : 'node16',\n devtool: false,\n mode: environment,\n\n entry,\n\n output: {\n clean: true,\n path: path.resolve(cwd, 'dist', entryType),\n ...(isUi ? { publicPath } : {}),\n },\n\n optimization: {\n minimize: isProduction,\n },\n\n resolve: {\n extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.wasm'],\n extensionAlias: {\n '.js': ['.ts', '.js'],\n '.cjs': ['.cts', '.cjs'],\n '.mjs': ['.mts', '.mjs'],\n },\n tsConfig: path.resolve(cwd, 'tsconfig.json'),\n },\n\n node: {\n global: isUi,\n __filename: isUi,\n __dirname: isUi,\n },\n\n externalsPresets: {\n node: !isUi,\n web: isUi,\n },\n\n module: {\n rules: [\n {\n test: /\\.(?:ts|tsx|cts|mts)$/iu,\n type: 'javascript/auto',\n exclude: [/dist\\//u, /node_modules\\//u],\n loader: 'builtin:swc-loader',\n options: {\n minify: isProduction,\n module: { type: 'nodenext' },\n jsc: {\n target: isUi ? 'es5' : 'es2021',\n parser: {\n syntax: 'typescript',\n tsx: true,\n },\n transform: {\n react: { runtime: 'automatic' },\n useDefineForClassFields: true,\n },\n keepClassNames: true,\n externalHelpers: false,\n },\n },\n },\n ...(isUi ?\n [\n {\n test: /\\.(?:jpe?g|png|gif|svg)$/iu,\n type: 'asset/resource',\n },\n ]\n : []),\n ],\n },\n\n ...(isUi ? { experiments: { css: true } } : {}),\n\n ...(isUi && htmlTemplateFile ?\n { plugins: [new rspack.HtmlRspackPlugin({ template: htmlTemplateFile, publicPath })] }\n : {}),\n\n watchOptions: {\n aggregateTimeout: 200,\n ignored: [\n '**/.git',\n '**/.turbo',\n '**/coverage',\n '**/dist',\n '**/generated',\n '**/old',\n '**/tmp',\n ],\n },\n };\n\n return config;\n}\n\nexport type CreateFivemRspackConfigOptions = {\n readonly resourceName?: string | undefined;\n readonly environment?: Environment | undefined;\n readonly cwd?: string | undefined;\n};\n\nexport function createFivemRspackConfig(\n options: CreateFivemRspackConfigOptions = {},\n): RspackOptions[] {\n const environment =\n options.environment\n ?? (process.env.NODE_ENV === Environment.PRODUCTION ?\n Environment.PRODUCTION\n : Environment.DEVELOPMENT);\n const cwd = options.cwd ?? process.cwd();\n const resourceName = options.resourceName ?? path.basename(cwd);\n\n const configs: RspackOptions[] = [];\n\n for (const entryType of Object.values(FivemEntryType)) {\n const entry = findFirstExistingPath([\n path.resolve(cwd, `src/${entryType}/index.ts`),\n path.resolve(cwd, `src/${entryType}.ts`),\n ]);\n\n if (!entry) continue;\n\n const config = buildConfig({ cwd, entry, entryType, environment, resourceName });\n configs.push(config);\n }\n\n if (configs.length === 0) throw new Error('No valid FiveM resource entries found.');\n\n return configs;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jpp-toolkit/rspack-config",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Rspack configurations for JS/TS projects.",
5
5
  "keywords": [
6
6
  "jpp",
@@ -31,9 +31,6 @@
31
31
  "src"
32
32
  ],
33
33
  "dependencies": {
34
- "webpack-merge": "6.0.1"
35
- },
36
- "devDependencies": {
37
34
  "@rspack/core": "1.6.7"
38
35
  },
39
36
  "engines": {
@@ -1,29 +1,46 @@
1
1
  import path from 'node:path';
2
2
 
3
+ import { rspack } from '@rspack/core';
3
4
  import type { RspackOptions } from '@rspack/core';
4
5
 
5
- import { mergeConfig } from './utils/merge-config';
6
+ import { Environment, FivemEntryType } from './enums';
7
+ import { findFirstExistingPath } from './utils/find-first-existing-path';
6
8
 
7
- export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOptions {
8
- const cwd = overrides.context ?? process.cwd();
9
- const mode =
10
- overrides.mode ?? (process.env.NODE_ENV === 'production' ? 'production' : 'development');
11
- const isProduction = mode === 'production';
9
+ type BuildConfigOptions = {
10
+ readonly cwd: string;
11
+ readonly entry: string;
12
+ readonly entryType: FivemEntryType;
13
+ readonly resourceName: string;
14
+ readonly environment: Environment;
15
+ };
16
+
17
+ function buildConfig(options: BuildConfigOptions): RspackOptions {
18
+ const { cwd, entry, entryType, resourceName, environment } = options;
19
+
20
+ const htmlTemplateFile = findFirstExistingPath([
21
+ path.resolve(cwd, `src/${entryType}/index.html`),
22
+ path.resolve(cwd, `src/${entryType}.html`),
23
+ ]);
24
+ const publicPath = `https://cfx-nui-${resourceName}/dist/${entryType}/`;
25
+
26
+ const isProduction = environment === 'production';
27
+ const isUi = entryType === FivemEntryType.UI;
12
28
 
13
29
  const config: RspackOptions = {
14
- name: 'fivem',
30
+ name: `fivem-${entryType}`,
15
31
 
16
32
  context: cwd,
17
33
 
18
- target: 'node16',
34
+ target: isUi ? 'web' : 'node16',
19
35
  devtool: false,
20
- mode,
36
+ mode: environment,
21
37
 
22
- entry: path.resolve(cwd, 'src/index.ts'),
38
+ entry,
23
39
 
24
40
  output: {
25
41
  clean: true,
26
- path: path.resolve(cwd, 'dist'),
42
+ path: path.resolve(cwd, 'dist', entryType),
43
+ ...(isUi ? { publicPath } : {}),
27
44
  },
28
45
 
29
46
  optimization: {
@@ -31,7 +48,7 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
31
48
  },
32
49
 
33
50
  resolve: {
34
- extensions: ['.js', '.json', '.wasm', '.ts'],
51
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.wasm'],
35
52
  extensionAlias: {
36
53
  '.js': ['.ts', '.js'],
37
54
  '.cjs': ['.cts', '.cjs'],
@@ -41,33 +58,34 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
41
58
  },
42
59
 
43
60
  node: {
44
- global: false,
45
- __filename: false,
46
- __dirname: false,
61
+ global: isUi,
62
+ __filename: isUi,
63
+ __dirname: isUi,
47
64
  },
48
65
 
49
66
  externalsPresets: {
50
- node: true,
67
+ node: !isUi,
68
+ web: isUi,
51
69
  },
52
70
 
53
71
  module: {
54
72
  rules: [
55
73
  {
56
- test: /\.(?:ts|cts|mts)$/iu,
74
+ test: /\.(?:ts|tsx|cts|mts)$/iu,
57
75
  type: 'javascript/auto',
58
76
  exclude: [/dist\//u, /node_modules\//u],
59
77
  loader: 'builtin:swc-loader',
60
78
  options: {
61
79
  minify: isProduction,
62
- module: {
63
- type: 'nodenext',
64
- },
80
+ module: { type: 'nodenext' },
65
81
  jsc: {
66
- target: 'es2021',
82
+ target: isUi ? 'es5' : 'es2021',
67
83
  parser: {
68
84
  syntax: 'typescript',
85
+ tsx: true,
69
86
  },
70
87
  transform: {
88
+ react: { runtime: 'automatic' },
71
89
  useDefineForClassFields: true,
72
90
  },
73
91
  keepClassNames: true,
@@ -75,9 +93,23 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
75
93
  },
76
94
  },
77
95
  },
96
+ ...(isUi ?
97
+ [
98
+ {
99
+ test: /\.(?:jpe?g|png|gif|svg)$/iu,
100
+ type: 'asset/resource',
101
+ },
102
+ ]
103
+ : []),
78
104
  ],
79
105
  },
80
106
 
107
+ ...(isUi ? { experiments: { css: true } } : {}),
108
+
109
+ ...(isUi && htmlTemplateFile ?
110
+ { plugins: [new rspack.HtmlRspackPlugin({ template: htmlTemplateFile, publicPath })] }
111
+ : {}),
112
+
81
113
  watchOptions: {
82
114
  aggregateTimeout: 200,
83
115
  ignored: [
@@ -92,5 +124,41 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
92
124
  },
93
125
  };
94
126
 
95
- return mergeConfig(config, overrides);
127
+ return config;
128
+ }
129
+
130
+ export type CreateFivemRspackConfigOptions = {
131
+ readonly resourceName?: string | undefined;
132
+ readonly environment?: Environment | undefined;
133
+ readonly cwd?: string | undefined;
134
+ };
135
+
136
+ export function createFivemRspackConfig(
137
+ options: CreateFivemRspackConfigOptions = {},
138
+ ): RspackOptions[] {
139
+ const environment =
140
+ options.environment
141
+ ?? (process.env.NODE_ENV === Environment.PRODUCTION ?
142
+ Environment.PRODUCTION
143
+ : Environment.DEVELOPMENT);
144
+ const cwd = options.cwd ?? process.cwd();
145
+ const resourceName = options.resourceName ?? path.basename(cwd);
146
+
147
+ const configs: RspackOptions[] = [];
148
+
149
+ for (const entryType of Object.values(FivemEntryType)) {
150
+ const entry = findFirstExistingPath([
151
+ path.resolve(cwd, `src/${entryType}/index.ts`),
152
+ path.resolve(cwd, `src/${entryType}.ts`),
153
+ ]);
154
+
155
+ if (!entry) continue;
156
+
157
+ const config = buildConfig({ cwd, entry, entryType, environment, resourceName });
158
+ configs.push(config);
159
+ }
160
+
161
+ if (configs.length === 0) throw new Error('No valid FiveM resource entries found.');
162
+
163
+ return configs;
96
164
  }
@@ -0,0 +1,5 @@
1
+ export const Environment = {
2
+ DEVELOPMENT: 'development',
3
+ PRODUCTION: 'production',
4
+ } as const;
5
+ export type Environment = (typeof Environment)[keyof typeof Environment];
@@ -0,0 +1,7 @@
1
+ export const FivemEntryType = {
2
+ CLIENT: 'client',
3
+ SERVER: 'server',
4
+ SHARED: 'shared',
5
+ UI: 'ui',
6
+ } as const;
7
+ export type FivemEntryType = (typeof FivemEntryType)[keyof typeof FivemEntryType];
@@ -0,0 +1,2 @@
1
+ export * from './environment';
2
+ export * from './fivem-entry-type';
package/src/index.ts CHANGED
@@ -1,2 +1 @@
1
1
  export * from './create-fivem-rspack-config';
2
- export * from './utils/merge-config';
@@ -0,0 +1,6 @@
1
+ import { existsSync } from 'node:fs';
2
+
3
+ export function findFirstExistingPath(possiblePaths: string[]): string | undefined {
4
+ for (const p of possiblePaths) if (existsSync(p)) return p;
5
+ return undefined;
6
+ }
@@ -1,13 +0,0 @@
1
- import { mergeWithRules } from 'webpack-merge';
2
-
3
- export const mergeConfig = mergeWithRules({
4
- module: {
5
- rules: {
6
- test: 'match',
7
- use: {
8
- loader: 'match',
9
- options: 'merge',
10
- },
11
- },
12
- },
13
- });