@jpp-toolkit/rspack-config 0.0.3 → 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,52 +1,57 @@
1
- import { existsSync } from "node:fs";
2
1
  import path from "node:path";
3
- import { mergeWithRules } from "webpack-merge";
2
+ import { rspack } from "@rspack/core";
3
+ import { existsSync } from "node:fs";
4
4
 
5
- //#region src/utils/merge-config.ts
6
- const mergeConfig = mergeWithRules({ module: { rules: {
7
- test: "match",
8
- use: {
9
- loader: "match",
10
- options: "merge"
11
- }
12
- } } });
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
+ }
13
25
 
14
26
  //#endregion
15
27
  //#region src/create-fivem-rspack-config.ts
16
- function createFivemRspackConfig(overrides = {}) {
17
- const cwd = overrides.context ?? process.cwd();
18
- const mode = overrides.mode ?? (process.env.NODE_ENV === "production" ? "production" : "development");
19
- const isProduction = mode === "production";
20
- const entries = {};
21
- for (const name of [
22
- "client",
23
- "server",
24
- "shared"
25
- ]) for (const file of [`src/${name}/index.ts`, `src/${name}.ts`]) {
26
- const entryPath = path.resolve(cwd, file);
27
- if (existsSync(entryPath)) {
28
- entries[name] = entryPath;
29
- break;
30
- }
31
- }
32
- return mergeConfig({
33
- 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}`,
34
36
  context: cwd,
35
- target: "node16",
37
+ target: isUi ? "web" : "node16",
36
38
  devtool: false,
37
- mode,
38
- entry: entries,
39
+ mode: environment,
40
+ entry,
39
41
  output: {
40
42
  clean: true,
41
- path: path.resolve(cwd, "dist")
43
+ path: path.resolve(cwd, "dist", entryType),
44
+ ...isUi ? { publicPath } : {}
42
45
  },
43
46
  optimization: { minimize: isProduction },
44
47
  resolve: {
45
48
  extensions: [
46
49
  ".js",
50
+ ".jsx",
51
+ ".ts",
52
+ ".tsx",
47
53
  ".json",
48
- ".wasm",
49
- ".ts"
54
+ ".wasm"
50
55
  ],
51
56
  extensionAlias: {
52
57
  ".js": [".ts", ".js"],
@@ -56,13 +61,16 @@ function createFivemRspackConfig(overrides = {}) {
56
61
  tsConfig: path.resolve(cwd, "tsconfig.json")
57
62
  },
58
63
  node: {
59
- global: false,
60
- __filename: false,
61
- __dirname: false
64
+ global: isUi,
65
+ __filename: isUi,
66
+ __dirname: isUi
67
+ },
68
+ externalsPresets: {
69
+ node: !isUi,
70
+ web: isUi
62
71
  },
63
- externalsPresets: { node: true },
64
72
  module: { rules: [{
65
- test: /\.(?:ts|cts|mts)$/iu,
73
+ test: /\.(?:ts|tsx|cts|mts)$/iu,
66
74
  type: "javascript/auto",
67
75
  exclude: [/dist\//u, /node_modules\//u],
68
76
  loader: "builtin:swc-loader",
@@ -70,14 +78,28 @@ function createFivemRspackConfig(overrides = {}) {
70
78
  minify: isProduction,
71
79
  module: { type: "nodenext" },
72
80
  jsc: {
73
- target: "es2021",
74
- parser: { syntax: "typescript" },
75
- 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
+ },
76
90
  keepClassNames: true,
77
91
  externalHelpers: false
78
92
  }
79
93
  }
80
- }] },
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
+ })] } : {},
81
103
  watchOptions: {
82
104
  aggregateTimeout: 200,
83
105
  ignored: [
@@ -90,9 +112,29 @@ function createFivemRspackConfig(overrides = {}) {
90
112
  "**/tmp"
91
113
  ]
92
114
  }
93
- }, 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;
94
136
  }
95
137
 
96
138
  //#endregion
97
- export { createFivemRspackConfig, mergeConfig };
139
+ export { createFivemRspackConfig };
98
140
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["entries: Record<string, string>"],"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 { existsSync } from 'node:fs';\nimport 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 entries: Record<string, string> = {};\n\n for (const name of ['client', 'server', 'shared']) {\n for (const file of [`src/${name}/index.ts`, `src/${name}.ts`]) {\n const entryPath = path.resolve(cwd, file);\n if (existsSync(entryPath)) {\n entries[name] = entryPath;\n break;\n }\n }\n }\n\n const config: RspackOptions = {\n name: 'fivem',\n\n context: cwd,\n\n target: 'node16',\n devtool: false,\n mode,\n\n entry: entries,\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;;;;ACLF,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;CAE9B,MAAMA,UAAkC,EAAE;AAE1C,MAAK,MAAM,QAAQ;EAAC;EAAU;EAAU;EAAS,CAC7C,MAAK,MAAM,QAAQ,CAAC,OAAO,KAAK,YAAY,OAAO,KAAK,KAAK,EAAE;EAC3D,MAAM,YAAY,KAAK,QAAQ,KAAK,KAAK;AACzC,MAAI,WAAW,UAAU,EAAE;AACvB,WAAQ,QAAQ;AAChB;;;AAuFZ,QAAO,YAlFuB;EAC1B,MAAM;EAEN,SAAS;EAET,QAAQ;EACR,SAAS;EACT;EAEA,OAAO;EAEP,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.3",
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,42 +1,46 @@
1
- import { existsSync } from 'node:fs';
2
1
  import path from 'node:path';
3
2
 
3
+ import { rspack } from '@rspack/core';
4
4
  import type { RspackOptions } from '@rspack/core';
5
5
 
6
- import { mergeConfig } from './utils/merge-config';
6
+ import { Environment, FivemEntryType } from './enums';
7
+ import { findFirstExistingPath } from './utils/find-first-existing-path';
7
8
 
8
- export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOptions {
9
- const cwd = overrides.context ?? process.cwd();
10
- const mode =
11
- overrides.mode ?? (process.env.NODE_ENV === 'production' ? 'production' : 'development');
12
- 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
+ };
13
16
 
14
- const entries: Record<string, string> = {};
17
+ function buildConfig(options: BuildConfigOptions): RspackOptions {
18
+ const { cwd, entry, entryType, resourceName, environment } = options;
15
19
 
16
- for (const name of ['client', 'server', 'shared']) {
17
- for (const file of [`src/${name}/index.ts`, `src/${name}.ts`]) {
18
- const entryPath = path.resolve(cwd, file);
19
- if (existsSync(entryPath)) {
20
- entries[name] = entryPath;
21
- break;
22
- }
23
- }
24
- }
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;
25
28
 
26
29
  const config: RspackOptions = {
27
- name: 'fivem',
30
+ name: `fivem-${entryType}`,
28
31
 
29
32
  context: cwd,
30
33
 
31
- target: 'node16',
34
+ target: isUi ? 'web' : 'node16',
32
35
  devtool: false,
33
- mode,
36
+ mode: environment,
34
37
 
35
- entry: entries,
38
+ entry,
36
39
 
37
40
  output: {
38
41
  clean: true,
39
- path: path.resolve(cwd, 'dist'),
42
+ path: path.resolve(cwd, 'dist', entryType),
43
+ ...(isUi ? { publicPath } : {}),
40
44
  },
41
45
 
42
46
  optimization: {
@@ -44,7 +48,7 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
44
48
  },
45
49
 
46
50
  resolve: {
47
- extensions: ['.js', '.json', '.wasm', '.ts'],
51
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.wasm'],
48
52
  extensionAlias: {
49
53
  '.js': ['.ts', '.js'],
50
54
  '.cjs': ['.cts', '.cjs'],
@@ -54,33 +58,34 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
54
58
  },
55
59
 
56
60
  node: {
57
- global: false,
58
- __filename: false,
59
- __dirname: false,
61
+ global: isUi,
62
+ __filename: isUi,
63
+ __dirname: isUi,
60
64
  },
61
65
 
62
66
  externalsPresets: {
63
- node: true,
67
+ node: !isUi,
68
+ web: isUi,
64
69
  },
65
70
 
66
71
  module: {
67
72
  rules: [
68
73
  {
69
- test: /\.(?:ts|cts|mts)$/iu,
74
+ test: /\.(?:ts|tsx|cts|mts)$/iu,
70
75
  type: 'javascript/auto',
71
76
  exclude: [/dist\//u, /node_modules\//u],
72
77
  loader: 'builtin:swc-loader',
73
78
  options: {
74
79
  minify: isProduction,
75
- module: {
76
- type: 'nodenext',
77
- },
80
+ module: { type: 'nodenext' },
78
81
  jsc: {
79
- target: 'es2021',
82
+ target: isUi ? 'es5' : 'es2021',
80
83
  parser: {
81
84
  syntax: 'typescript',
85
+ tsx: true,
82
86
  },
83
87
  transform: {
88
+ react: { runtime: 'automatic' },
84
89
  useDefineForClassFields: true,
85
90
  },
86
91
  keepClassNames: true,
@@ -88,9 +93,23 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
88
93
  },
89
94
  },
90
95
  },
96
+ ...(isUi ?
97
+ [
98
+ {
99
+ test: /\.(?:jpe?g|png|gif|svg)$/iu,
100
+ type: 'asset/resource',
101
+ },
102
+ ]
103
+ : []),
91
104
  ],
92
105
  },
93
106
 
107
+ ...(isUi ? { experiments: { css: true } } : {}),
108
+
109
+ ...(isUi && htmlTemplateFile ?
110
+ { plugins: [new rspack.HtmlRspackPlugin({ template: htmlTemplateFile, publicPath })] }
111
+ : {}),
112
+
94
113
  watchOptions: {
95
114
  aggregateTimeout: 200,
96
115
  ignored: [
@@ -105,5 +124,41 @@ export function createFivemRspackConfig(overrides: RspackOptions = {}): RspackOp
105
124
  },
106
125
  };
107
126
 
108
- 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;
109
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
- });