@modern-js/builder 3.9.1 → 3.9.3

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.
@@ -43,6 +43,7 @@ const globalVars_js_namespaceObject = require("../plugins/globalVars.js");
43
43
  const htmlMinify_js_namespaceObject = require("../plugins/htmlMinify.js");
44
44
  const runtimeChunk_js_namespaceObject = require("../plugins/runtimeChunk.js");
45
45
  const external_devServer_js_namespaceObject = require("./devServer.js");
46
+ const external_pluginOptions_js_namespaceObject = require("./pluginOptions.js");
46
47
  const external_utils_js_namespaceObject = require("./utils.js");
47
48
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
48
49
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -58,7 +59,7 @@ function removeUndefinedKey(obj) {
58
59
  }
59
60
  async function parseCommonConfig(builderConfig, options) {
60
61
  const frameworkConfigPath = options?.frameworkConfigPath;
61
- const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
62
+ const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, svgr, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
62
63
  let combinedAlias;
63
64
  if (alias || resolve.alias) combinedAlias = [].concat(alias ?? []).concat(resolve.alias ?? []);
64
65
  const rsbuildConfig = {
@@ -140,12 +141,8 @@ async function parseCommonConfig(builderConfig, options) {
140
141
  sourceMap
141
142
  }),
142
143
  (0, emitRouteFile_js_namespaceObject.pluginEmitRouteFile)(),
143
- (0, plugin_sass_namespaceObject.pluginSass)({
144
- sassLoaderOptions: sass
145
- }),
146
- (0, plugin_less_namespaceObject.pluginLess)({
147
- lessLoaderOptions: less
148
- }),
144
+ (0, plugin_sass_namespaceObject.pluginSass)((0, external_pluginOptions_js_namespaceObject.normalizeSassOptions)(sass)),
145
+ (0, plugin_less_namespaceObject.pluginLess)((0, external_pluginOptions_js_namespaceObject.normalizeLessOptions)(less)),
149
146
  (0, environmentDefaults_js_namespaceObject.pluginEnvironmentDefaults)(distPath),
150
147
  (0, htmlMinify_js_namespaceObject.pluginHtmlMinifierTerser)()
151
148
  ];
@@ -176,14 +173,14 @@ async function parseCommonConfig(builderConfig, options) {
176
173
  rsbuildPlugins.push((0, plugin_react_namespaceObject.pluginReact)(void 0 !== reactCompiler ? {
177
174
  reactCompiler
178
175
  } : {}));
179
- if (!disableSvgr) {
176
+ const svgrOptions = (0, external_pluginOptions_js_namespaceObject.resolveSvgrOptions)({
177
+ svgr,
178
+ disableSvgr,
179
+ svgDefaultExport
180
+ });
181
+ if (false !== svgrOptions) {
180
182
  const { pluginSvgr } = await import("@rsbuild/plugin-svgr");
181
- rsbuildPlugins.push(pluginSvgr({
182
- mixedImport: true,
183
- svgrOptions: {
184
- exportType: 'component' === svgDefaultExport ? 'default' : 'named'
185
- }
186
- }));
183
+ rsbuildPlugins.push(pluginSvgr(svgrOptions));
187
184
  }
188
185
  if (assetsRetry) {
189
186
  const { pluginAssetsRetry } = await import("@rsbuild/plugin-assets-retry");
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ normalizeLessOptions: ()=>normalizeLessOptions,
32
+ normalizeSassOptions: ()=>normalizeSassOptions,
33
+ resetPluginOptionsWarnings: ()=>resetPluginOptionsWarnings,
34
+ resolveSvgrOptions: ()=>resolveSvgrOptions
35
+ });
36
+ const utils_namespaceObject = require("@modern-js/utils");
37
+ const LESS_PLUGIN_KEYS = [
38
+ 'lessLoaderOptions',
39
+ 'include',
40
+ 'exclude',
41
+ 'parallel'
42
+ ];
43
+ const SASS_PLUGIN_KEYS = [
44
+ 'sassLoaderOptions',
45
+ 'include',
46
+ 'exclude',
47
+ 'rewriteUrls'
48
+ ];
49
+ const warned = new Set();
50
+ const resetPluginOptionsWarnings = ()=>{
51
+ warned.clear();
52
+ };
53
+ const warnOnceInDev = (key, message)=>{
54
+ if (!(0, utils_namespaceObject.isDevCommand)() || warned.has(key)) return;
55
+ warned.add(key);
56
+ utils_namespaceObject.logger.warn(message);
57
+ };
58
+ const isPlainObject = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
59
+ const isPluginLevelOptions = (value, pluginKeys)=>isPlainObject(value) && pluginKeys.some((key)=>key in value);
60
+ const isEmptyObject = (value)=>isPlainObject(value) && 0 === Object.keys(value).length;
61
+ const warnIgnoredKeys = (name, value, pluginKeys, loaderOptionsKey)=>{
62
+ const pluginLevel = Object.keys(value).filter((key)=>pluginKeys.includes(key));
63
+ const ignored = Object.keys(value).filter((key)=>!pluginKeys.includes(key));
64
+ if (0 === ignored.length) return;
65
+ warnOnceInDev(`${name}:mixed`, `\`${name}\` contains plugin-level options (${pluginLevel.join(', ')}) together with other keys (${ignored.join(', ')}). The whole object is passed to the plugin, so the other keys are ignored. Move loader options under \`${loaderOptionsKey}\`.`);
66
+ };
67
+ const normalizeLessOptions = (less)=>{
68
+ if (isPluginLevelOptions(less, LESS_PLUGIN_KEYS)) {
69
+ warnIgnoredKeys('tools.less', less, LESS_PLUGIN_KEYS, 'lessLoaderOptions');
70
+ return less;
71
+ }
72
+ if (void 0 !== less && !isEmptyObject(less)) warnOnceInDev('tools.less', "`tools.less` now accepts the full options of @rsbuild/plugin-less. Passing less-loader options directly is deprecated and will stop working in the next major version. Move them under `lessLoaderOptions`:\n before: tools: { less: { lessOptions: { javascriptEnabled: true } } }\n after: tools: { less: { lessLoaderOptions: { lessOptions: { javascriptEnabled: true } } } }");
73
+ return {
74
+ lessLoaderOptions: less
75
+ };
76
+ };
77
+ const normalizeSassOptions = (sass)=>{
78
+ if (isPluginLevelOptions(sass, SASS_PLUGIN_KEYS)) {
79
+ warnIgnoredKeys('tools.sass', sass, SASS_PLUGIN_KEYS, 'sassLoaderOptions');
80
+ return sass;
81
+ }
82
+ if (void 0 !== sass && !isEmptyObject(sass)) warnOnceInDev('tools.sass', "`tools.sass` now accepts the full options of @rsbuild/plugin-sass. Passing sass-loader options directly is deprecated and will stop working in the next major version. Move them under `sassLoaderOptions`:\n before: tools: { sass: { sassOptions: { quietDeps: true } } }\n after: tools: { sass: { sassLoaderOptions: { sassOptions: { quietDeps: true } } } }");
83
+ return {
84
+ sassLoaderOptions: sass
85
+ };
86
+ };
87
+ const mergeSvgrOptions = (target, source)=>{
88
+ const svgrOptions = source.svgrOptions ? {
89
+ ...target.svgrOptions,
90
+ ...source.svgrOptions
91
+ } : target.svgrOptions;
92
+ return Object.assign(target, source, {
93
+ svgrOptions
94
+ });
95
+ };
96
+ const resolveSvgrOptions = ({ svgr, disableSvgr, svgDefaultExport })=>{
97
+ if (void 0 !== disableSvgr) warnOnceInDev('output.disableSvgr', disableSvgr ? '`output.disableSvgr` is deprecated and will be removed in the next major version. Use `tools: { svgr: false }` instead.' : '`output.disableSvgr` is deprecated and will be removed in the next major version. SVGR is enabled by default, so `output.disableSvgr: false` can be removed (or use `tools: { svgr: {} }` to keep it explicit).');
98
+ if (void 0 !== svgDefaultExport) warnOnceInDev('output.svgDefaultExport', "`output.svgDefaultExport` is deprecated and will be removed in the next major version. Use `tools.svgr.svgrOptions.exportType` instead:\n before: output: { svgDefaultExport: 'component' }\n after: tools: { svgr: { svgrOptions: { exportType: 'default' } } }\n ('url' maps to exportType: 'named')");
99
+ if (false === svgr) return false;
100
+ if (void 0 === svgr && disableSvgr) return false;
101
+ const defaults = {
102
+ mixedImport: true,
103
+ svgrOptions: {
104
+ exportType: 'component' === svgDefaultExport ? 'default' : 'named'
105
+ }
106
+ };
107
+ return (0, utils_namespaceObject.applyOptionsChain)(defaults, svgr, void 0, mergeSvgrOptions);
108
+ };
109
+ exports.normalizeLessOptions = __webpack_exports__.normalizeLessOptions;
110
+ exports.normalizeSassOptions = __webpack_exports__.normalizeSassOptions;
111
+ exports.resetPluginOptionsWarnings = __webpack_exports__.resetPluginOptionsWarnings;
112
+ exports.resolveSvgrOptions = __webpack_exports__.resolveSvgrOptions;
113
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
114
+ "normalizeLessOptions",
115
+ "normalizeSassOptions",
116
+ "resetPluginOptionsWarnings",
117
+ "resolveSvgrOptions"
118
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
119
+ Object.defineProperty(exports, '__esModule', {
120
+ value: true
121
+ });
@@ -10,6 +10,7 @@ import { pluginGlobalVars } from "../plugins/globalVars.mjs";
10
10
  import { pluginHtmlMinifierTerser } from "../plugins/htmlMinify.mjs";
11
11
  import { pluginRuntimeChunk } from "../plugins/runtimeChunk.mjs";
12
12
  import { transformToRsbuildServerOptions } from "./devServer.mjs";
13
+ import { normalizeLessOptions, normalizeSassOptions, resolveSvgrOptions } from "./pluginOptions.mjs";
13
14
  import { NODE_MODULES_REGEX } from "./utils.mjs";
14
15
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
15
16
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -25,7 +26,7 @@ function removeUndefinedKey(obj) {
25
26
  }
26
27
  async function parseCommonConfig(builderConfig, options) {
27
28
  const frameworkConfigPath = options?.frameworkConfigPath;
28
- const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
29
+ const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, svgr, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
29
30
  let combinedAlias;
30
31
  if (alias || resolve.alias) combinedAlias = [].concat(alias ?? []).concat(resolve.alias ?? []);
31
32
  const rsbuildConfig = {
@@ -107,12 +108,8 @@ async function parseCommonConfig(builderConfig, options) {
107
108
  sourceMap
108
109
  }),
109
110
  pluginEmitRouteFile(),
110
- pluginSass({
111
- sassLoaderOptions: sass
112
- }),
113
- pluginLess({
114
- lessLoaderOptions: less
115
- }),
111
+ pluginSass(normalizeSassOptions(sass)),
112
+ pluginLess(normalizeLessOptions(less)),
116
113
  pluginEnvironmentDefaults(distPath),
117
114
  pluginHtmlMinifierTerser()
118
115
  ];
@@ -143,14 +140,14 @@ async function parseCommonConfig(builderConfig, options) {
143
140
  rsbuildPlugins.push(pluginReact(void 0 !== reactCompiler ? {
144
141
  reactCompiler
145
142
  } : {}));
146
- if (!disableSvgr) {
143
+ const svgrOptions = resolveSvgrOptions({
144
+ svgr,
145
+ disableSvgr,
146
+ svgDefaultExport
147
+ });
148
+ if (false !== svgrOptions) {
147
149
  const { pluginSvgr } = await import("@rsbuild/plugin-svgr");
148
- rsbuildPlugins.push(pluginSvgr({
149
- mixedImport: true,
150
- svgrOptions: {
151
- exportType: 'component' === svgDefaultExport ? 'default' : 'named'
152
- }
153
- }));
150
+ rsbuildPlugins.push(pluginSvgr(svgrOptions));
154
151
  }
155
152
  if (assetsRetry) {
156
153
  const { pluginAssetsRetry } = await import("@rsbuild/plugin-assets-retry");
@@ -0,0 +1,74 @@
1
+ import { applyOptionsChain, isDevCommand, logger } from "@modern-js/utils";
2
+ const LESS_PLUGIN_KEYS = [
3
+ 'lessLoaderOptions',
4
+ 'include',
5
+ 'exclude',
6
+ 'parallel'
7
+ ];
8
+ const SASS_PLUGIN_KEYS = [
9
+ 'sassLoaderOptions',
10
+ 'include',
11
+ 'exclude',
12
+ 'rewriteUrls'
13
+ ];
14
+ const warned = new Set();
15
+ const resetPluginOptionsWarnings = ()=>{
16
+ warned.clear();
17
+ };
18
+ const warnOnceInDev = (key, message)=>{
19
+ if (!isDevCommand() || warned.has(key)) return;
20
+ warned.add(key);
21
+ logger.warn(message);
22
+ };
23
+ const isPlainObject = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
24
+ const isPluginLevelOptions = (value, pluginKeys)=>isPlainObject(value) && pluginKeys.some((key)=>key in value);
25
+ const isEmptyObject = (value)=>isPlainObject(value) && 0 === Object.keys(value).length;
26
+ const warnIgnoredKeys = (name, value, pluginKeys, loaderOptionsKey)=>{
27
+ const pluginLevel = Object.keys(value).filter((key)=>pluginKeys.includes(key));
28
+ const ignored = Object.keys(value).filter((key)=>!pluginKeys.includes(key));
29
+ if (0 === ignored.length) return;
30
+ warnOnceInDev(`${name}:mixed`, `\`${name}\` contains plugin-level options (${pluginLevel.join(', ')}) together with other keys (${ignored.join(', ')}). The whole object is passed to the plugin, so the other keys are ignored. Move loader options under \`${loaderOptionsKey}\`.`);
31
+ };
32
+ const normalizeLessOptions = (less)=>{
33
+ if (isPluginLevelOptions(less, LESS_PLUGIN_KEYS)) {
34
+ warnIgnoredKeys('tools.less', less, LESS_PLUGIN_KEYS, 'lessLoaderOptions');
35
+ return less;
36
+ }
37
+ if (void 0 !== less && !isEmptyObject(less)) warnOnceInDev('tools.less', "`tools.less` now accepts the full options of @rsbuild/plugin-less. Passing less-loader options directly is deprecated and will stop working in the next major version. Move them under `lessLoaderOptions`:\n before: tools: { less: { lessOptions: { javascriptEnabled: true } } }\n after: tools: { less: { lessLoaderOptions: { lessOptions: { javascriptEnabled: true } } } }");
38
+ return {
39
+ lessLoaderOptions: less
40
+ };
41
+ };
42
+ const normalizeSassOptions = (sass)=>{
43
+ if (isPluginLevelOptions(sass, SASS_PLUGIN_KEYS)) {
44
+ warnIgnoredKeys('tools.sass', sass, SASS_PLUGIN_KEYS, 'sassLoaderOptions');
45
+ return sass;
46
+ }
47
+ if (void 0 !== sass && !isEmptyObject(sass)) warnOnceInDev('tools.sass', "`tools.sass` now accepts the full options of @rsbuild/plugin-sass. Passing sass-loader options directly is deprecated and will stop working in the next major version. Move them under `sassLoaderOptions`:\n before: tools: { sass: { sassOptions: { quietDeps: true } } }\n after: tools: { sass: { sassLoaderOptions: { sassOptions: { quietDeps: true } } } }");
48
+ return {
49
+ sassLoaderOptions: sass
50
+ };
51
+ };
52
+ const mergeSvgrOptions = (target, source)=>{
53
+ const svgrOptions = source.svgrOptions ? {
54
+ ...target.svgrOptions,
55
+ ...source.svgrOptions
56
+ } : target.svgrOptions;
57
+ return Object.assign(target, source, {
58
+ svgrOptions
59
+ });
60
+ };
61
+ const resolveSvgrOptions = ({ svgr, disableSvgr, svgDefaultExport })=>{
62
+ if (void 0 !== disableSvgr) warnOnceInDev('output.disableSvgr', disableSvgr ? '`output.disableSvgr` is deprecated and will be removed in the next major version. Use `tools: { svgr: false }` instead.' : '`output.disableSvgr` is deprecated and will be removed in the next major version. SVGR is enabled by default, so `output.disableSvgr: false` can be removed (or use `tools: { svgr: {} }` to keep it explicit).');
63
+ if (void 0 !== svgDefaultExport) warnOnceInDev('output.svgDefaultExport', "`output.svgDefaultExport` is deprecated and will be removed in the next major version. Use `tools.svgr.svgrOptions.exportType` instead:\n before: output: { svgDefaultExport: 'component' }\n after: tools: { svgr: { svgrOptions: { exportType: 'default' } } }\n ('url' maps to exportType: 'named')");
64
+ if (false === svgr) return false;
65
+ if (void 0 === svgr && disableSvgr) return false;
66
+ const defaults = {
67
+ mixedImport: true,
68
+ svgrOptions: {
69
+ exportType: 'component' === svgDefaultExport ? 'default' : 'named'
70
+ }
71
+ };
72
+ return applyOptionsChain(defaults, svgr, void 0, mergeSvgrOptions);
73
+ };
74
+ export { normalizeLessOptions, normalizeSassOptions, resetPluginOptionsWarnings, resolveSvgrOptions };
@@ -11,6 +11,7 @@ import { pluginGlobalVars } from "../plugins/globalVars.mjs";
11
11
  import { pluginHtmlMinifierTerser } from "../plugins/htmlMinify.mjs";
12
12
  import { pluginRuntimeChunk } from "../plugins/runtimeChunk.mjs";
13
13
  import { transformToRsbuildServerOptions } from "./devServer.mjs";
14
+ import { normalizeLessOptions, normalizeSassOptions, resolveSvgrOptions } from "./pluginOptions.mjs";
14
15
  import { NODE_MODULES_REGEX } from "./utils.mjs";
15
16
  const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
16
17
  const GLOBAL_CSS_REGEX = /\.global\.\w+$/;
@@ -26,7 +27,7 @@ function removeUndefinedKey(obj) {
26
27
  }
27
28
  async function parseCommonConfig(builderConfig, options) {
28
29
  const frameworkConfigPath = options?.frameworkConfigPath;
29
- const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
30
+ const { plugins: [...plugins] = [], splitChunks, performance: { ...performanceConfig } = {}, output: { module = false, enableCssModuleTSDeclaration, disableCssModuleExtension, disableTsChecker, disableSvgr, svgDefaultExport, assetsRetry, enableAssetManifest, sourceMap, convertToRem, polyfill, dataUriLimit = 10000, distPath = {}, ...outputConfig } = {}, html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, reactCompiler, ...sourceConfig } = {}, dev = {}, server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, tsChecker, minifyCss, less, sass, svgr, htmlPlugin, autoprefixer, ...toolsConfig } = {}, environments = {}, resolve = {} } = builderConfig;
30
31
  let combinedAlias;
31
32
  if (alias || resolve.alias) combinedAlias = [].concat(alias ?? []).concat(resolve.alias ?? []);
32
33
  const rsbuildConfig = {
@@ -108,12 +109,8 @@ async function parseCommonConfig(builderConfig, options) {
108
109
  sourceMap
109
110
  }),
110
111
  pluginEmitRouteFile(),
111
- pluginSass({
112
- sassLoaderOptions: sass
113
- }),
114
- pluginLess({
115
- lessLoaderOptions: less
116
- }),
112
+ pluginSass(normalizeSassOptions(sass)),
113
+ pluginLess(normalizeLessOptions(less)),
117
114
  pluginEnvironmentDefaults(distPath),
118
115
  pluginHtmlMinifierTerser()
119
116
  ];
@@ -144,14 +141,14 @@ async function parseCommonConfig(builderConfig, options) {
144
141
  rsbuildPlugins.push(pluginReact(void 0 !== reactCompiler ? {
145
142
  reactCompiler
146
143
  } : {}));
147
- if (!disableSvgr) {
144
+ const svgrOptions = resolveSvgrOptions({
145
+ svgr,
146
+ disableSvgr,
147
+ svgDefaultExport
148
+ });
149
+ if (false !== svgrOptions) {
148
150
  const { pluginSvgr } = await import("@rsbuild/plugin-svgr");
149
- rsbuildPlugins.push(pluginSvgr({
150
- mixedImport: true,
151
- svgrOptions: {
152
- exportType: 'component' === svgDefaultExport ? 'default' : 'named'
153
- }
154
- }));
151
+ rsbuildPlugins.push(pluginSvgr(svgrOptions));
155
152
  }
156
153
  if (assetsRetry) {
157
154
  const { pluginAssetsRetry } = await import("@rsbuild/plugin-assets-retry");
@@ -0,0 +1,75 @@
1
+ import "node:module";
2
+ import { applyOptionsChain, isDevCommand, logger } from "@modern-js/utils";
3
+ const LESS_PLUGIN_KEYS = [
4
+ 'lessLoaderOptions',
5
+ 'include',
6
+ 'exclude',
7
+ 'parallel'
8
+ ];
9
+ const SASS_PLUGIN_KEYS = [
10
+ 'sassLoaderOptions',
11
+ 'include',
12
+ 'exclude',
13
+ 'rewriteUrls'
14
+ ];
15
+ const warned = new Set();
16
+ const resetPluginOptionsWarnings = ()=>{
17
+ warned.clear();
18
+ };
19
+ const warnOnceInDev = (key, message)=>{
20
+ if (!isDevCommand() || warned.has(key)) return;
21
+ warned.add(key);
22
+ logger.warn(message);
23
+ };
24
+ const isPlainObject = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
25
+ const isPluginLevelOptions = (value, pluginKeys)=>isPlainObject(value) && pluginKeys.some((key)=>key in value);
26
+ const isEmptyObject = (value)=>isPlainObject(value) && 0 === Object.keys(value).length;
27
+ const warnIgnoredKeys = (name, value, pluginKeys, loaderOptionsKey)=>{
28
+ const pluginLevel = Object.keys(value).filter((key)=>pluginKeys.includes(key));
29
+ const ignored = Object.keys(value).filter((key)=>!pluginKeys.includes(key));
30
+ if (0 === ignored.length) return;
31
+ warnOnceInDev(`${name}:mixed`, `\`${name}\` contains plugin-level options (${pluginLevel.join(', ')}) together with other keys (${ignored.join(', ')}). The whole object is passed to the plugin, so the other keys are ignored. Move loader options under \`${loaderOptionsKey}\`.`);
32
+ };
33
+ const normalizeLessOptions = (less)=>{
34
+ if (isPluginLevelOptions(less, LESS_PLUGIN_KEYS)) {
35
+ warnIgnoredKeys('tools.less', less, LESS_PLUGIN_KEYS, 'lessLoaderOptions');
36
+ return less;
37
+ }
38
+ if (void 0 !== less && !isEmptyObject(less)) warnOnceInDev('tools.less', "`tools.less` now accepts the full options of @rsbuild/plugin-less. Passing less-loader options directly is deprecated and will stop working in the next major version. Move them under `lessLoaderOptions`:\n before: tools: { less: { lessOptions: { javascriptEnabled: true } } }\n after: tools: { less: { lessLoaderOptions: { lessOptions: { javascriptEnabled: true } } } }");
39
+ return {
40
+ lessLoaderOptions: less
41
+ };
42
+ };
43
+ const normalizeSassOptions = (sass)=>{
44
+ if (isPluginLevelOptions(sass, SASS_PLUGIN_KEYS)) {
45
+ warnIgnoredKeys('tools.sass', sass, SASS_PLUGIN_KEYS, 'sassLoaderOptions');
46
+ return sass;
47
+ }
48
+ if (void 0 !== sass && !isEmptyObject(sass)) warnOnceInDev('tools.sass', "`tools.sass` now accepts the full options of @rsbuild/plugin-sass. Passing sass-loader options directly is deprecated and will stop working in the next major version. Move them under `sassLoaderOptions`:\n before: tools: { sass: { sassOptions: { quietDeps: true } } }\n after: tools: { sass: { sassLoaderOptions: { sassOptions: { quietDeps: true } } } }");
49
+ return {
50
+ sassLoaderOptions: sass
51
+ };
52
+ };
53
+ const mergeSvgrOptions = (target, source)=>{
54
+ const svgrOptions = source.svgrOptions ? {
55
+ ...target.svgrOptions,
56
+ ...source.svgrOptions
57
+ } : target.svgrOptions;
58
+ return Object.assign(target, source, {
59
+ svgrOptions
60
+ });
61
+ };
62
+ const resolveSvgrOptions = ({ svgr, disableSvgr, svgDefaultExport })=>{
63
+ if (void 0 !== disableSvgr) warnOnceInDev('output.disableSvgr', disableSvgr ? '`output.disableSvgr` is deprecated and will be removed in the next major version. Use `tools: { svgr: false }` instead.' : '`output.disableSvgr` is deprecated and will be removed in the next major version. SVGR is enabled by default, so `output.disableSvgr: false` can be removed (or use `tools: { svgr: {} }` to keep it explicit).');
64
+ if (void 0 !== svgDefaultExport) warnOnceInDev('output.svgDefaultExport', "`output.svgDefaultExport` is deprecated and will be removed in the next major version. Use `tools.svgr.svgrOptions.exportType` instead:\n before: output: { svgDefaultExport: 'component' }\n after: tools: { svgr: { svgrOptions: { exportType: 'default' } } }\n ('url' maps to exportType: 'named')");
65
+ if (false === svgr) return false;
66
+ if (void 0 === svgr && disableSvgr) return false;
67
+ const defaults = {
68
+ mixedImport: true,
69
+ svgrOptions: {
70
+ exportType: 'component' === svgDefaultExport ? 'default' : 'named'
71
+ }
72
+ };
73
+ return applyOptionsChain(defaults, svgr, void 0, mergeSvgrOptions);
74
+ };
75
+ export { normalizeLessOptions, normalizeSassOptions, resetPluginOptionsWarnings, resolveSvgrOptions };
@@ -0,0 +1,32 @@
1
+ import type { PluginLessOptions } from '@rsbuild/plugin-less';
2
+ import type { PluginSassOptions } from '@rsbuild/plugin-sass';
3
+ import type { PluginSvgrOptions, SvgDefaultExport } from '@rsbuild/plugin-svgr';
4
+ import type { BuilderConfig } from '../types.js';
5
+ type BuilderToolsConfig = NonNullable<BuilderConfig['tools']>;
6
+ /** Reset the warn-once state. Only meant for unit tests. */
7
+ export declare const resetPluginOptionsWarnings: () => void;
8
+ /**
9
+ * `tools.less` accepts either the full options of `@rsbuild/plugin-less`
10
+ * or, for backward compatibility, the less-loader options directly
11
+ * (object, function or array form). The legacy form is wrapped into
12
+ * `lessLoaderOptions` so the generated bundler config stays unchanged.
13
+ */
14
+ export declare const normalizeLessOptions: (less: BuilderToolsConfig["less"]) => PluginLessOptions;
15
+ /**
16
+ * Same as {@link normalizeLessOptions} for `tools.sass`.
17
+ */
18
+ export declare const normalizeSassOptions: (sass: BuilderToolsConfig["sass"]) => PluginSassOptions;
19
+ /**
20
+ * Resolve the options passed to `@rsbuild/plugin-svgr`, or `false` when the
21
+ * plugin should not be registered.
22
+ *
23
+ * `tools.svgr` takes precedence over the deprecated `output.disableSvgr` and
24
+ * `output.svgDefaultExport`; the two legacy options keep working when
25
+ * `tools.svgr` is not set.
26
+ */
27
+ export declare const resolveSvgrOptions: ({ svgr, disableSvgr, svgDefaultExport, }: {
28
+ svgr: BuilderToolsConfig["svgr"];
29
+ disableSvgr?: boolean;
30
+ svgDefaultExport?: SvgDefaultExport;
31
+ }) => PluginSvgrOptions | false;
32
+ export {};
@@ -8,7 +8,7 @@ import type { PluginReactOptions } from '@rsbuild/plugin-react';
8
8
  import type { PluginRemOptions } from '@rsbuild/plugin-rem';
9
9
  import type { PluginSassOptions } from '@rsbuild/plugin-sass';
10
10
  import type { PluginSourceBuildOptions } from '@rsbuild/plugin-source-build';
11
- import type { SvgDefaultExport } from '@rsbuild/plugin-svgr';
11
+ import type { PluginSvgrOptions, SvgDefaultExport } from '@rsbuild/plugin-svgr';
12
12
  import type { PluginTypeCheckerOptions } from '@rsbuild/plugin-type-check';
13
13
  import type { Options as AutoprefixerOptions } from 'autoprefixer';
14
14
  export type CacheGroup = Rspack.OptimizationSplitChunksCacheGroup;
@@ -100,13 +100,29 @@ export type BuilderExtraConfig = {
100
100
  */
101
101
  minifyCss?: PluginCssMinimizerOptions['pluginOptions'];
102
102
  /**
103
- * Modify the config of [less-loader](https://github.com/webpack-contrib/less-loader).
103
+ * Modify the options of [@rsbuild/plugin-less](https://rsbuild.rs/plugins/list/plugin-less),
104
+ * such as `lessLoaderOptions`, `include`, `exclude` and `parallel`.
105
+ *
106
+ * Passing the [less-loader](https://github.com/webpack-contrib/less-loader)
107
+ * options directly is still supported for backward compatibility, but is
108
+ * deprecated: move them under `lessLoaderOptions`.
109
+ */
110
+ less?: PluginLessOptions['lessLoaderOptions'] | PluginLessOptions;
111
+ /**
112
+ * Modify the options of [@rsbuild/plugin-sass](https://rsbuild.rs/plugins/list/plugin-sass),
113
+ * such as `sassLoaderOptions`, `include`, `exclude` and `rewriteUrls`.
114
+ *
115
+ * Passing the [sass-loader](https://github.com/webpack-contrib/sass-loader)
116
+ * options directly is still supported for backward compatibility, but is
117
+ * deprecated: move them under `sassLoaderOptions`.
104
118
  */
105
- less?: PluginLessOptions['lessLoaderOptions'];
119
+ sass?: PluginSassOptions['sassLoaderOptions'] | PluginSassOptions;
106
120
  /**
107
- * Modify the config of [sass-loader](https://github.com/webpack-contrib/sass-loader).
121
+ * Modify the options of [@rsbuild/plugin-svgr](https://rsbuild.rs/plugins/list/plugin-svgr),
122
+ * such as `svgrOptions`, `parallel`, `exclude` and `query`.
123
+ * Set to `false` to disable SVGR; all `.svg` files are then treated as static assets.
108
124
  */
109
- sass?: PluginSassOptions['sassLoaderOptions'];
125
+ svgr?: ConfigChain<PluginSvgrOptions> | false;
110
126
  };
111
127
  dev?: {
112
128
  /** Set the page URL to open when the server starts. */
@@ -177,10 +193,14 @@ export type BuilderExtraConfig = {
177
193
  disableTsChecker?: boolean;
178
194
  /**
179
195
  * Configure the default export type of SVG files.
196
+ * @deprecated Use `tools.svgr.svgrOptions.exportType` instead:
197
+ * `'component'` maps to `exportType: 'default'`, `'url'` maps to `exportType: 'named'`.
180
198
  */
181
199
  svgDefaultExport?: SvgDefaultExport;
182
200
  /**
183
201
  * Whether to transform SVGs into React components. If true, will treat all .svg files as assets.
202
+ * @deprecated Use `tools.svgr` instead: `output.disableSvgr: true` maps to `tools.svgr: false`;
203
+ * `false` is the default behavior and can simply be removed.
184
204
  */
185
205
  disableSvgr?: boolean;
186
206
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modern-js/builder",
3
- "version": "3.9.1",
3
+ "version": "3.9.3",
4
4
  "description": "A builder for Modern.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "dist"
27
27
  ],
28
28
  "dependencies": {
29
- "@rsbuild/core": "2.2.4",
29
+ "@rsbuild/core": "2.2.9",
30
30
  "@rsbuild/plugin-assets-retry": "2.0.2",
31
31
  "@rsbuild/plugin-check-syntax": "2.0.1",
32
32
  "@rsbuild/plugin-css-minimizer": "2.0.1",
@@ -34,19 +34,19 @@
34
34
  "@rsbuild/plugin-react": "2.1.0",
35
35
  "@rsbuild/plugin-rem": "1.0.6",
36
36
  "@rsbuild/plugin-sass": "2.0.1",
37
- "@rsbuild/plugin-source-build": "1.0.6",
37
+ "@rsbuild/plugin-source-build": "1.0.7",
38
38
  "@rsbuild/plugin-svgr": "2.0.5",
39
39
  "@rsbuild/plugin-type-check": "1.6.0",
40
40
  "@rsbuild/plugin-typed-css-modules": "1.2.4",
41
41
  "@swc/core": "1.15.41",
42
42
  "@swc/helpers": "^0.5.17",
43
43
  "autoprefixer": "10.4.27",
44
- "browserslist": "4.28.8",
44
+ "browserslist": "4.29.0",
45
45
  "core-js": "^3.48.0",
46
46
  "cssnano": "6.1.2",
47
47
  "html-minifier-terser": "^7.2.0",
48
48
  "lodash": "^4.18.1",
49
- "postcss": "^8.5.26",
49
+ "postcss": "^8.5.28",
50
50
  "postcss-custom-properties": "13.3.12",
51
51
  "postcss-flexbugs-fixes": "5.0.2",
52
52
  "postcss-font-variant": "5.0.0",
@@ -56,19 +56,19 @@
56
56
  "postcss-page-break": "3.0.4",
57
57
  "rsbuild-plugin-rsc": "0.1.1",
58
58
  "rspack-manifest-plugin": "5.2.2",
59
- "ts-deepmerge": "7.0.3",
60
- "@modern-js/utils": "3.9.1"
59
+ "ts-deepmerge": "8.0.0",
60
+ "@modern-js/utils": "3.9.3"
61
61
  },
62
62
  "devDependencies": {
63
- "@rslib/core": "1.0.0",
63
+ "@rslib/core": "1.0.1",
64
64
  "@types/html-minifier-terser": "^7.0.2",
65
- "@types/lodash": "^4.17.24",
65
+ "@types/lodash": "^4.17.25",
66
66
  "react": "^19.2.8",
67
- "terser": "^5.48.0",
67
+ "terser": "^5.51.2",
68
68
  "typescript": "^5.3.0",
69
- "@modern-js/types": "3.9.1",
70
- "@scripts/rstest-config": "2.66.0",
71
- "@modern-js/rslib": "2.68.10"
69
+ "@modern-js/rslib": "2.68.10",
70
+ "@modern-js/types": "3.9.3",
71
+ "@scripts/rstest-config": "2.66.0"
72
72
  },
73
73
  "publishConfig": {
74
74
  "access": "public",