@esmx/rspack 3.0.0-rc.54 → 3.0.0-rc.56

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.
@@ -12,44 +12,47 @@ import {
12
12
  type RspackAppOptions,
13
13
  createRspackApp
14
14
  } from '../rspack';
15
+ import { getTargetSetting } from './target-setting';
16
+ import type { TargetSetting } from './target-setting';
15
17
 
18
+ export type { TargetSetting };
16
19
  export interface RspackHtmlAppOptions extends RspackAppOptions {
17
20
  /**
18
- * CSS 输出模式配置
21
+ * CSS output mode configuration
19
22
  *
20
- * @default 根据环境自动选择:
21
- * - 生产环境: 'css',将CSS输出到独立文件中,有利于缓存和并行加载
22
- * - 开发环境: 'js',将CSS打包到JS中以支持热更新(HMR),实现样式的即时更新
23
+ * @default Automatically selected based on environment:
24
+ * - Production: 'css', outputs CSS to separate files for better caching and parallel loading
25
+ * - Development: 'js', bundles CSS into JS to support hot module replacement (HMR) for instant style updates
23
26
  *
24
- * - 'css': CSS 输出到独立的 CSS 文件中
25
- * - 'js': CSS 打包到 JS 文件中,运行时动态插入样式
26
- * - false: 关闭默认的 CSS 处理配置,需要手动配置 loader 规则
27
+ * - 'css': Output CSS to separate CSS files
28
+ * - 'js': Bundle CSS into JS files and dynamically inject styles at runtime
29
+ * - false: Disable default CSS processing configuration, requires manual loader rule configuration
27
30
  *
28
31
  * @example
29
32
  * ```ts
30
- * // 使用环境默认配置
33
+ * // Use environment default configuration
31
34
  * css: undefined
32
35
  *
33
- * // 强制输出到独立的 CSS 文件
36
+ * // Force output to separate CSS files
34
37
  * css: 'css'
35
38
  *
36
- * // 强制打包到 JS
39
+ * // Force bundle into JS
37
40
  * css: 'js'
38
41
  *
39
- * // 自定义 CSS 处理
42
+ * // Custom CSS processing
40
43
  * css: false
41
44
  * ```
42
45
  */
43
46
  css?: 'css' | 'js' | false;
44
47
 
45
48
  /**
46
- * 自定义 loader 配置
49
+ * Custom loader configuration
47
50
  *
48
- * 允许替换默认的 loader 实现,可用于切换到特定框架的 loader
51
+ * Allows replacing default loader implementations, useful for switching to framework-specific loaders
49
52
  *
50
53
  * @example
51
54
  * ```ts
52
- * // 使用 Vue style-loader
55
+ * // Use Vue's style-loader
53
56
  * loaders: {
54
57
  * styleLoader: 'vue-style-loader'
55
58
  * }
@@ -58,9 +61,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
58
61
  loaders?: Partial<Record<keyof typeof RSPACK_LOADER, string>>;
59
62
 
60
63
  /**
61
- * style-loader 配置项
62
- *
63
- * 用于配置样式注入方式,完整选项参考:
64
+ * Configure style injection method. For complete options, see:
64
65
  * https://github.com/webpack-contrib/style-loader
65
66
  *
66
67
  * @example
@@ -74,9 +75,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
74
75
  styleLoader?: Record<string, any>;
75
76
 
76
77
  /**
77
- * css-loader 配置项
78
- *
79
- * 用于配置 CSS 模块化、URL 解析等,完整选项参考:
78
+ * Configure CSS modules, URL resolution, etc. For complete options, see:
80
79
  * https://github.com/webpack-contrib/css-loader
81
80
  *
82
81
  * @example
@@ -90,9 +89,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
90
89
  cssLoader?: Record<string, any>;
91
90
 
92
91
  /**
93
- * less-loader 配置项
94
- *
95
- * 用于配置 Less 编译选项,完整选项参考:
92
+ * Configure Less compilation options. For complete options, see:
96
93
  * https://github.com/webpack-contrib/less-loader
97
94
  *
98
95
  * @example
@@ -108,9 +105,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
108
105
  lessLoader?: Record<string, any>;
109
106
 
110
107
  /**
111
- * style-resources-loader 配置项
112
- *
113
- * 用于自动注入全局的样式资源,完整选项参考:
108
+ * Automatically inject global style resources. For complete options, see:
114
109
  * https://github.com/yenshih/style-resources-loader
115
110
  *
116
111
  * @example
@@ -126,9 +121,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
126
121
  styleResourcesLoader?: Record<string, any>;
127
122
 
128
123
  /**
129
- * SWC loader 配置项
130
- *
131
- * 用于配置 TypeScript/JavaScript 编译选项,完整选项参考:
124
+ * Configure TypeScript/JavaScript compilation options. For complete options, see:
132
125
  * https://rspack.dev/guide/features/builtin-swc-loader
133
126
  *
134
127
  * @example
@@ -149,19 +142,17 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
149
142
  swcLoader?: SwcLoaderOptions;
150
143
 
151
144
  /**
152
- * DefinePlugin 配置项
153
- *
154
- * 用于定义编译时的全局常量,支持针对不同构建目标设置不同的值
155
- * 完整说明参考: https://rspack.dev/plugins/webpack/define-plugin
145
+ * Define compile-time global constants, supports setting different values for different build targets
146
+ * For complete documentation, see: https://rspack.dev/plugins/webpack/define-plugin
156
147
  *
157
148
  * @example
158
149
  * ```ts
159
- * // 统一的值
150
+ * // Unified value
160
151
  * definePlugin: {
161
152
  * 'process.env.APP_ENV': JSON.stringify('production')
162
153
  * }
163
154
  *
164
- * // 针对不同构建目标的值
155
+ * // Values for different build targets
165
156
  * definePlugin: {
166
157
  * 'process.env.IS_SERVER': {
167
158
  * server: 'true',
@@ -176,35 +167,27 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
176
167
  >;
177
168
 
178
169
  /**
179
- * 构建目标配置
180
- *
181
- * 用于设置代码的目标运行环境,影响代码的编译降级和 polyfill 注入
170
+ * Set the target runtime environment for the code, affecting code compilation downgrading and polyfill injection
182
171
  *
183
172
  * @example
184
173
  * ```ts
174
+ * // Global compatible mode
175
+ * target: 'compatible'
176
+ *
177
+ * // Global modern mode
178
+ * target: 'modern'
179
+ *
180
+ * // Global custom targets
181
+ * target: ['chrome>=89', 'edge>=89', 'firefox>=108', 'safari>=16.4', 'node>=24']
182
+ *
183
+ * // Per-build-target configuration
185
184
  * target: {
186
- * // 浏览器构建目标
187
- * web: ['chrome>=87', 'firefox>=78', 'safari>=14'],
188
- * // Node.js 构建目标
189
- * node: ['node>=16']
185
+ * client: 'modern',
186
+ * server: ['node>=18']
190
187
  * }
191
188
  * ```
192
189
  */
193
- target?: {
194
- /**
195
- * 浏览器构建目标
196
- *
197
- * @default ['chrome>=64', 'edge>=79', 'firefox>=67', 'safari>=11.1']
198
- */
199
- web?: string[];
200
-
201
- /**
202
- * Node.js 构建目标
203
- *
204
- * @default ['node>=24']
205
- */
206
- node?: string[];
207
- };
190
+ target?: TargetSetting;
208
191
  }
209
192
 
210
193
  export async function createRspackHtmlApp(
@@ -213,11 +196,6 @@ export async function createRspackHtmlApp(
213
196
  ) {
214
197
  options = {
215
198
  ...options,
216
- target: {
217
- web: ['chrome>=64', 'edge>=79', 'firefox>=67', 'safari>=11.1'],
218
- node: ['node>=24'],
219
- ...options?.target
220
- },
221
199
  css: options?.css ? options.css : esmx.isProd ? 'css' : 'js'
222
200
  };
223
201
  return createRspackApp(esmx, {
@@ -258,7 +236,9 @@ export async function createRspackHtmlApp(
258
236
  function configureAssetRules(chain: RspackChain, esmx: Esmx): void {
259
237
  chain.module
260
238
  .rule('images')
261
- .test(/\.(jpe?g|png|gif|bmp|webp|svg)$/i)
239
+ .test(
240
+ /\.(png|jpg|jpeg|gif|svg|bmp|webp|ico|apng|avif|tif|tiff|jfif|pjpeg|pjp|cur)$/i
241
+ )
262
242
  .type('asset/resource')
263
243
  .set('generator', {
264
244
  filename: filename(esmx, 'images')
@@ -266,15 +246,23 @@ function configureAssetRules(chain: RspackChain, esmx: Esmx): void {
266
246
 
267
247
  chain.module
268
248
  .rule('media')
269
- .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/i)
249
+ .test(/\.(mp4|webm|ogg|mov)$/i)
270
250
  .type('asset/resource')
271
251
  .set('generator', {
272
252
  filename: filename(esmx, 'media')
273
253
  });
274
254
 
255
+ chain.module
256
+ .rule('audio')
257
+ .test(/\.(mp3|wav|flac|aac|m4a|opus)$/i)
258
+ .type('asset/resource')
259
+ .set('generator', {
260
+ filename: filename(esmx, 'audio')
261
+ });
262
+
275
263
  chain.module
276
264
  .rule('fonts')
277
- .test(/\.(woff|woff2|eot|ttf|otf)(\?.*)?$/i)
265
+ .test(/\.(woff|woff2|eot|ttf|otf|ttc)(\?.*)?$/i)
278
266
  .type('asset/resource')
279
267
  .set('generator', {
280
268
  filename: filename(esmx, 'fonts')
@@ -314,10 +302,7 @@ function configureTypeScriptRule(
314
302
  )
315
303
  .options({
316
304
  env: {
317
- targets:
318
- buildTarget === 'client'
319
- ? options?.target?.web
320
- : options?.target?.node,
305
+ targets: getTargetSetting(options?.target, buildTarget),
321
306
  ...options?.swcLoader?.env
322
307
  },
323
308
  jsc: {
@@ -354,7 +339,7 @@ function configureOptimization(
354
339
  .use(rspack.LightningCssMinimizerRspackPlugin, [
355
340
  {
356
341
  minimizerOptions: {
357
- targets: options.target?.web,
342
+ targets: getTargetSetting(options?.target, 'client'),
358
343
  errorRecovery: false
359
344
  }
360
345
  }
@@ -410,11 +395,11 @@ function configureCssInJS(
410
395
  .test(/\.css$/)
411
396
  .use('style-loader')
412
397
  .loader(options.loaders?.styleLoader ?? RSPACK_LOADER.styleLoader)
413
- .options(options.styleLoader || {})
398
+ .options(options.styleLoader ?? {})
414
399
  .end()
415
400
  .use('css-loader')
416
401
  .loader(options.loaders?.cssLoader ?? RSPACK_LOADER.cssLoader)
417
- .options(options.cssLoader || {})
402
+ .options(options.cssLoader ?? {})
418
403
  .end()
419
404
  .use('lightning-css-loader')
420
405
  .loader(
@@ -422,7 +407,7 @@ function configureCssInJS(
422
407
  RSPACK_LOADER.lightningcssLoader
423
408
  )
424
409
  .options({
425
- targets: options.target?.web ?? [],
410
+ targets: getTargetSetting(options?.target, 'client'),
426
411
  minify: esmx.isProd
427
412
  } as LightningcssLoaderOptions)
428
413
  .end()
@@ -433,11 +418,11 @@ function configureCssInJS(
433
418
  .test(/\.less$/)
434
419
  .use('style-loader')
435
420
  .loader(options.loaders?.styleLoader ?? RSPACK_LOADER.styleLoader)
436
- .options(options.styleLoader || {})
421
+ .options(options.styleLoader ?? {})
437
422
  .end()
438
423
  .use('css-loader')
439
424
  .loader(options.loaders?.cssLoader ?? RSPACK_LOADER.cssLoader)
440
- .options(options.cssLoader || {})
425
+ .options(options.cssLoader ?? {})
441
426
  .end()
442
427
  .use('lightning-css-loader')
443
428
  .loader(
@@ -445,13 +430,13 @@ function configureCssInJS(
445
430
  RSPACK_LOADER.lightningcssLoader
446
431
  )
447
432
  .options({
448
- targets: options.target?.web ?? [],
433
+ targets: getTargetSetting(options?.target, 'client'),
449
434
  minify: esmx.isProd
450
435
  } as LightningcssLoaderOptions)
451
436
  .end()
452
437
  .use('less-loader')
453
438
  .loader(options.loaders?.lessLoader ?? RSPACK_LOADER.lessLoader)
454
- .options(options.lessLoader || {})
439
+ .options(options.lessLoader ?? {})
455
440
  .end();
456
441
 
457
442
  if (options.styleResourcesLoader) {
@@ -473,7 +458,7 @@ function configureCssExtract(
473
458
  options: RspackHtmlAppOptions
474
459
  ): void {
475
460
  chain.set('experiments', {
476
- ...(chain.get('experiments') || {}),
461
+ ...(chain.get('experiments') ?? {}),
477
462
  css: true
478
463
  });
479
464
 
@@ -487,7 +472,7 @@ function configureCssExtract(
487
472
  .test(/\.less$/)
488
473
  .use('less-loader')
489
474
  .loader(options.loaders?.lessLoader ?? RSPACK_LOADER.lessLoader)
490
- .options(options.lessLoader || {})
475
+ .options(options.lessLoader ?? {})
491
476
  .end();
492
477
 
493
478
  if (options.styleResourcesLoader) {
@@ -0,0 +1,123 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { BuildTarget } from '../rspack';
3
+ import { PRESET_TARGETS, getTargetSetting } from './target-setting';
4
+ import type { TargetSetting } from './target-setting';
5
+
6
+ describe('getTargetSetting', () => {
7
+ const buildTargets: BuildTarget[] = ['client', 'server', 'node'];
8
+
9
+ describe('when setting is undefined', () => {
10
+ it('should return compatible preset for all build targets', () => {
11
+ buildTargets.forEach((buildTarget) => {
12
+ const result = getTargetSetting(undefined, buildTarget);
13
+ expect(result).toEqual(PRESET_TARGETS.compatible[buildTarget]);
14
+ });
15
+ });
16
+ });
17
+
18
+ describe('when setting is a string preset', () => {
19
+ it('should return compatible preset for all build targets', () => {
20
+ buildTargets.forEach((buildTarget) => {
21
+ const result = getTargetSetting('compatible', buildTarget);
22
+ expect(result).toEqual(PRESET_TARGETS.compatible[buildTarget]);
23
+ });
24
+ });
25
+
26
+ it('should return modern preset for all build targets', () => {
27
+ buildTargets.forEach((buildTarget) => {
28
+ const result = getTargetSetting('modern', buildTarget);
29
+ expect(result).toEqual(PRESET_TARGETS.modern[buildTarget]);
30
+ });
31
+ });
32
+ });
33
+
34
+ describe('when setting is a custom array', () => {
35
+ const customTargets = ['chrome>=90', 'firefox>=80', 'safari>=14'];
36
+
37
+ it('should return the custom array for all build targets', () => {
38
+ buildTargets.forEach((buildTarget) => {
39
+ const result = getTargetSetting(customTargets, buildTarget);
40
+ expect(result).toEqual(customTargets);
41
+ });
42
+ });
43
+ });
44
+
45
+ describe('when setting is an object with specific build targets', () => {
46
+ it('should return specified preset for configured build targets', () => {
47
+ const setting: TargetSetting = {
48
+ client: 'modern',
49
+ server: 'compatible'
50
+ };
51
+
52
+ expect(getTargetSetting(setting, 'client')).toEqual(
53
+ PRESET_TARGETS.modern.client
54
+ );
55
+ expect(getTargetSetting(setting, 'server')).toEqual(
56
+ PRESET_TARGETS.compatible.server
57
+ );
58
+ });
59
+
60
+ it('should return compatible preset for unconfigured build targets', () => {
61
+ const setting: TargetSetting = {
62
+ client: 'modern'
63
+ };
64
+
65
+ expect(getTargetSetting(setting, 'client')).toEqual(
66
+ PRESET_TARGETS.modern.client
67
+ );
68
+ expect(getTargetSetting(setting, 'server')).toEqual(
69
+ PRESET_TARGETS.compatible.server
70
+ );
71
+ expect(getTargetSetting(setting, 'node')).toEqual(
72
+ PRESET_TARGETS.compatible.node
73
+ );
74
+ });
75
+
76
+ it('should return custom array for configured build targets', () => {
77
+ const customClientTargets = ['chrome>=90', 'firefox>=80'];
78
+ const customServerTargets = ['node>=18'];
79
+ const setting: TargetSetting = {
80
+ client: customClientTargets,
81
+ server: customServerTargets
82
+ };
83
+
84
+ expect(getTargetSetting(setting, 'client')).toEqual(
85
+ customClientTargets
86
+ );
87
+ expect(getTargetSetting(setting, 'server')).toEqual(
88
+ customServerTargets
89
+ );
90
+ expect(getTargetSetting(setting, 'node')).toEqual(
91
+ PRESET_TARGETS.compatible.node
92
+ );
93
+ });
94
+
95
+ it('should handle mixed preset and custom configurations', () => {
96
+ const setting: TargetSetting = {
97
+ client: 'modern',
98
+ server: ['node>=18'],
99
+ node: 'compatible'
100
+ };
101
+
102
+ expect(getTargetSetting(setting, 'client')).toEqual(
103
+ PRESET_TARGETS.modern.client
104
+ );
105
+ expect(getTargetSetting(setting, 'server')).toEqual(['node>=18']);
106
+ expect(getTargetSetting(setting, 'node')).toEqual(
107
+ PRESET_TARGETS.compatible.node
108
+ );
109
+ });
110
+ });
111
+
112
+ describe('edge cases', () => {
113
+ it('should handle empty custom array', () => {
114
+ const result = getTargetSetting([], 'client');
115
+ expect(result).toEqual([]);
116
+ });
117
+
118
+ it('should handle single item custom array', () => {
119
+ const result = getTargetSetting(['chrome>=90'], 'client');
120
+ expect(result).toEqual(['chrome>=90']);
121
+ });
122
+ });
123
+ });
@@ -0,0 +1,52 @@
1
+ import type { BuildTarget } from '../rspack/build-target';
2
+
3
+ export type TargetPreset = 'compatible' | 'modern';
4
+
5
+ export type TargetSpec = TargetPreset | string[];
6
+
7
+ export type TargetSetting =
8
+ | TargetSpec
9
+ | Partial<Record<BuildTarget, TargetSpec>>;
10
+
11
+ export const PRESET_TARGETS = {
12
+ compatible: {
13
+ client: ['chrome>=64', 'edge>=79', 'firefox>=67', 'safari>=11.1'],
14
+ server: ['node>=24'],
15
+ node: ['node>=24']
16
+ },
17
+ modern: {
18
+ client: ['chrome>=89', 'edge>=89', 'firefox>=108', 'safari>=16.4'],
19
+ server: ['node>=24'],
20
+ node: ['node>=24']
21
+ }
22
+ } as const;
23
+
24
+ function resolveTargetSpec(
25
+ spec: TargetSpec,
26
+ buildTarget: BuildTarget
27
+ ): string[] {
28
+ if (typeof spec === 'string') {
29
+ return [...PRESET_TARGETS[spec][buildTarget]];
30
+ }
31
+ return spec;
32
+ }
33
+
34
+ export function getTargetSetting(
35
+ setting: TargetSetting | undefined,
36
+ buildTarget: BuildTarget
37
+ ): string[] {
38
+ if (!setting) {
39
+ return [...PRESET_TARGETS.compatible[buildTarget]];
40
+ }
41
+
42
+ if (typeof setting === 'string' || Array.isArray(setting)) {
43
+ return resolveTargetSpec(setting, buildTarget);
44
+ }
45
+
46
+ const targetSpec = setting[buildTarget];
47
+ if (!targetSpec) {
48
+ return [...PRESET_TARGETS.compatible[buildTarget]];
49
+ }
50
+
51
+ return resolveTargetSpec(targetSpec, buildTarget);
52
+ }