@rsbuild/core 2.1.2 → 2.1.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/756.js CHANGED
@@ -3500,7 +3500,7 @@ function createPublicContext(context) {
3500
3500
  async function createContext(options, userConfig, logger) {
3501
3501
  let { cwd } = options, rootPath = userConfig.root ? ensureAbsolutePath(cwd, userConfig.root) : cwd, rsbuildConfig = await withDefaultConfig(rootPath, userConfig), cachePath = join(rootPath, 'node_modules', '.cache'), specifiedEnvironments = options.environment && options.environment.length > 0 ? options.environment : void 0;
3502
3502
  return {
3503
- version: "2.1.2",
3503
+ version: "2.1.4",
3504
3504
  rootPath,
3505
3505
  distPath: '',
3506
3506
  cachePath,
@@ -3778,12 +3778,15 @@ let configChain_CHAIN_ID = {
3778
3778
  JS_MAIN: 'js',
3779
3779
  JS_WORKER: 'js-worker',
3780
3780
  JS_RAW: 'js-raw',
3781
+ JS_TEXT: 'js-text',
3781
3782
  CSS_MAIN: 'css',
3782
3783
  CSS_RAW: 'css-raw',
3784
+ CSS_TEXT: 'css-text',
3783
3785
  CSS_URL: 'css-url',
3784
3786
  CSS_INLINE: 'css-inline',
3785
3787
  SVG: 'svg',
3786
3788
  SVG_RAW: 'svg-asset-raw',
3789
+ SVG_TEXT: 'svg-asset-text',
3787
3790
  SVG_URL: 'svg-asset-url',
3788
3791
  SVG_ASSET: 'svg-asset',
3789
3792
  SVG_REACT: 'svg-react',
@@ -4817,7 +4820,9 @@ let chainStaticAssetRule = ({ emit, rule, maxSize, filename, assetType })=>{
4817
4820
  let generatorOptions = {
4818
4821
  filename
4819
4822
  };
4820
- emit || (generatorOptions.emit = !1), rule.oneOf(`${assetType}-asset-url`).type('asset/resource').resourceQuery(URL_QUERY_REGEX).set('generator', generatorOptions), rule.oneOf(`${assetType}-asset-inline`).type('asset/inline').resourceQuery(INLINE_QUERY_REGEX), rule.oneOf(`${assetType}-asset-raw`).type('asset/source').resourceQuery(RAW_QUERY_REGEX), rule.oneOf(`${assetType}-asset`).type('asset').parser({
4823
+ emit || (generatorOptions.emit = !1), rule.oneOf(`${assetType}-asset-url`).type('asset/resource').resourceQuery(URL_QUERY_REGEX).set('generator', generatorOptions), rule.oneOf(`${assetType}-asset-inline`).type('asset/inline').resourceQuery(INLINE_QUERY_REGEX), rule.oneOf(`${assetType}-asset-text`).type('asset/source').with({
4824
+ type: 'text'
4825
+ }), rule.oneOf(`${assetType}-asset-raw`).type('asset/source').resourceQuery(RAW_QUERY_REGEX), rule.oneOf(`${assetType}-asset`).type('asset').parser({
4821
4826
  dataUrlCondition: {
4822
4827
  maxSize
4823
4828
  }
@@ -5150,7 +5155,7 @@ async function saveSnapshots(snapshotPath, snapshots, logger) {
5150
5155
  logger.debug('Failed to save file size snapshots:', err);
5151
5156
  }
5152
5157
  }
5153
- let EXCLUDE_ASSET_REGEX = /\.(?:map|LICENSE\.txt|d\.ts)$/, isSignificantDiff = (diff)=>Math.abs(diff) >= 10, formatDiff = (diff)=>{
5158
+ let EXCLUDE_ASSET_REGEX = /\.(?:map|LICENSE\.txt|d\.(?:ts|mts|cts))$/, isSignificantDiff = (diff)=>Math.abs(diff) >= 10, formatDiff = (diff)=>{
5154
5159
  let label = `(${diff > 0 ? '+' : '-'}${calcFileSize(Math.abs(diff))})`;
5155
5160
  return {
5156
5161
  label: (diff > 0 ? color.red : color.green)(label),
@@ -5175,7 +5180,7 @@ function getHeader(maxFileLength, maxSizeLength, fileHeader, showGzipHeader) {
5175
5180
  let calcFileSize = (len)=>{
5176
5181
  let val = len / 1000;
5177
5182
  return `${val.toFixed(val < 1 ? 2 : 1)} kB`;
5178
- }, COMPRESSIBLE_REGEX = /\.(?:js|css|html|json|svg|txt|xml|xhtml|wasm|manifest|md)$/i, isCompressible = (assetName)=>COMPRESSIBLE_REGEX.test(assetName), getFilePath = (assetName)=>{
5183
+ }, COMPRESSIBLE_REGEX = /\.(?:js|mjs|cjs|jsx|ts|tsx|mts|cts|css|html|json|svg|txt|xml|xhtml|wasm|manifest|md)$/i, isCompressible = (assetName)=>COMPRESSIBLE_REGEX.test(assetName), getFilePath = (assetName)=>{
5179
5184
  let queryIndex = assetName.indexOf('?');
5180
5185
  return -1 === queryIndex ? assetName : assetName.slice(0, queryIndex);
5181
5186
  };
@@ -5823,7 +5828,8 @@ let supportedChromiumBrowsers = [
5823
5828
  'Microsoft Edge',
5824
5829
  'Brave Browser',
5825
5830
  'Vivaldi',
5826
- 'Chromium'
5831
+ 'Chromium',
5832
+ 'Helium'
5827
5833
  ], mapChromiumBrowserName = (browser)=>'chrome' === browser || 'google chrome' === browser ? 'Google Chrome' : browser;
5828
5834
  async function openBrowser(url, logger) {
5829
5835
  let browser = process.env.BROWSER, browserArgs = process.env.BROWSER_ARGS;
@@ -8736,7 +8742,11 @@ function applyDefaultPlugins(pluginManager, context) {
8736
8742
  ], emitAssets), createAssetRule(configChain_CHAIN_ID.RULE.MEDIA, [
8737
8743
  ...VIDEO_EXTENSIONS,
8738
8744
  ...AUDIO_EXTENSIONS
8739
- ], emitAssets), createAssetRule(configChain_CHAIN_ID.RULE.FONT, FONT_EXTENSIONS, emitAssets), chain.module.rule(configChain_CHAIN_ID.RULE.JSON).test(/\.json$/i).oneOf('json-asset-raw').type('asset/source').resourceQuery(RAW_QUERY_REGEX);
8745
+ ], emitAssets), createAssetRule(configChain_CHAIN_ID.RULE.FONT, FONT_EXTENSIONS, emitAssets);
8746
+ let rule = chain.module.rule(configChain_CHAIN_ID.RULE.JSON).test(/\.json$/i);
8747
+ rule.oneOf('json-asset-text').type('asset/source').with({
8748
+ type: 'text'
8749
+ }), rule.oneOf('json-asset-raw').type('asset/source').resourceQuery(RAW_QUERY_REGEX);
8740
8750
  let assetsFilename = getMergedFilename('assets');
8741
8751
  chain.output.assetModuleFilename(assetsFilename), emitAssets || chain.module.generator.merge({
8742
8752
  'asset/resource': {
@@ -9034,7 +9044,9 @@ try {
9034
9044
  let cssRule = chain.module.rule(CHAIN_ID.RULE.CSS), { config } = environment;
9035
9045
  cssRule.test(CSS_REGEX).dependency({
9036
9046
  not: 'url'
9037
- });
9047
+ }), cssRule.oneOf(CHAIN_ID.ONE_OF.CSS_TEXT).with({
9048
+ type: 'text'
9049
+ }).type('asset/source');
9038
9050
  let urlRule = cssRule.oneOf(CHAIN_ID.ONE_OF.CSS_URL).resourceQuery(URL_QUERY_REGEX);
9039
9051
  urlRule.use(CHAIN_ID.USE.CSS_URL).loader(node_path.join(dirname, 'cssUrlLoader.mjs'));
9040
9052
  let inlineRule = cssRule.oneOf(CHAIN_ID.ONE_OF.CSS_INLINE).resourceQuery(INLINE_QUERY_REGEX);
@@ -9194,7 +9206,9 @@ try {
9194
9206
  let { config, browserslist } = environment, cacheRoot = node_path.join(api.context.cachePath, '.swc'), rule = chain.module.rule(CHAIN_ID.RULE.JS).test(SCRIPT_REGEX).dependency({
9195
9207
  not: 'url'
9196
9208
  });
9197
- rule.oneOf(CHAIN_ID.ONE_OF.JS_RAW).resourceQuery(RAW_QUERY_REGEX).type('asset/source');
9209
+ rule.oneOf(CHAIN_ID.ONE_OF.JS_TEXT).with({
9210
+ type: 'text'
9211
+ }).type('asset/source'), rule.oneOf(CHAIN_ID.ONE_OF.JS_RAW).resourceQuery(RAW_QUERY_REGEX).type('asset/source');
9198
9212
  let mainRule = rule.oneOf(CHAIN_ID.ONE_OF.JS_MAIN).type("javascript/auto"), dataUriRule = chain.module.rule(CHAIN_ID.RULE.JS_DATA_URI).mimetype({
9199
9213
  or: [
9200
9214
  "text/javascript",
@@ -9853,116 +9867,163 @@ async function createRsbuild(options = {}) {
9853
9867
  function defineConfig(config) {
9854
9868
  return config;
9855
9869
  }
9856
- async function loadConfig_loadConfig({ cwd = process.cwd(), path, envMode, meta, loader = 'auto' } = {}) {
9857
- let configExport, configFilePath = ((root, customConfig)=>{
9870
+ let DEFAULT_CONFIG_FILE_NAMES = [
9871
+ 'rsbuild.config.ts',
9872
+ 'rsbuild.config.js',
9873
+ 'rsbuild.config.mts',
9874
+ 'rsbuild.config.mjs',
9875
+ 'rsbuild.config.cts',
9876
+ 'rsbuild.config.cjs'
9877
+ ], canReadExport = (module)=>null !== module && ('object' == typeof module || 'function' == typeof module), getConfigExport = (configModule, exportName, configFilePath)=>{
9878
+ if (!1 === exportName) return {};
9879
+ if ('default' === exportName) return canReadExport(configModule) && 'default' in configModule ? configModule.default : configModule;
9880
+ if (canReadExport(configModule) && Object.hasOwn(configModule, exportName)) return configModule[exportName];
9881
+ throw Error(`Cannot find export ${color.yellow(exportName)} in config file: ${color.dim(configFilePath)}`);
9882
+ }, tryFreshImport = async (configFileURL)=>{
9883
+ try {
9884
+ let { freshImport } = await import("./fresh-import.js");
9885
+ return await freshImport(configFileURL);
9886
+ } catch (err) {
9887
+ src_logger.debug('failed to initialize fresh-import, fallback to dynamic import.'), src_logger.debug(err);
9888
+ }
9889
+ }, loadConfigWithNative = async (configFilePath)=>{
9890
+ let configFileURL = pathToFileURL(configFilePath).href, freshImportResult = await tryFreshImport(configFileURL);
9891
+ return freshImportResult ? {
9892
+ configModule: freshImportResult.result,
9893
+ dependencies: freshImportResult.dependencies.sort()
9894
+ } : {
9895
+ configModule: await import(`${configFileURL}?t=${Date.now()}`),
9896
+ dependencies: []
9897
+ };
9898
+ }, loadConfigWithJiti = async (configFilePath, exportName)=>{
9899
+ let { createJiti } = await import("../compiled/jiti/lib/jiti.mjs"), jiti = createJiti(import.meta.filename, {
9900
+ moduleCache: !1,
9901
+ interopDefault: !0,
9902
+ nativeModules: [
9903
+ "typescript"
9904
+ ]
9905
+ });
9906
+ return 'default' === exportName ? {
9907
+ configExport: await jiti.import(configFilePath, {
9908
+ default: !0
9909
+ }),
9910
+ dependencies: []
9911
+ } : {
9912
+ configExport: getConfigExport(await jiti.import(configFilePath), exportName, configFilePath),
9913
+ dependencies: []
9914
+ };
9915
+ };
9916
+ async function loadConfig_loadConfig({ cwd = process.cwd(), path, configFileNames, envMode, meta, loader = 'auto', command, exportName = 'default' } = {}) {
9917
+ let loadedConfig, configFilePath = ((root, customConfig, configFileNames = DEFAULT_CONFIG_FILE_NAMES)=>{
9858
9918
  if (customConfig) {
9859
9919
  let customConfigPath = external_node_path_isAbsolute(customConfig) ? customConfig : join(root, customConfig);
9860
9920
  if (node_fs.existsSync(customConfigPath)) return customConfigPath;
9861
9921
  throw Error(`Cannot find config file: ${color.dim(customConfigPath)}`);
9862
9922
  }
9863
- for (let file of [
9864
- 'rsbuild.config.ts',
9865
- 'rsbuild.config.js',
9866
- 'rsbuild.config.mts',
9867
- 'rsbuild.config.mjs',
9868
- 'rsbuild.config.cts',
9869
- 'rsbuild.config.cjs'
9870
- ]){
9923
+ for (let file of configFileNames){
9871
9924
  let configFile = join(root, file);
9872
9925
  if (node_fs.existsSync(configFile)) return configFile;
9873
9926
  }
9874
9927
  return null;
9875
- })(cwd, path);
9928
+ })(cwd, path, configFileNames);
9876
9929
  if (!configFilePath) return src_logger.debug('no config file found.'), {
9877
9930
  content: {},
9878
- filePath: configFilePath
9931
+ filePath: configFilePath,
9932
+ dependencies: []
9879
9933
  };
9880
9934
  let applyMetaInfo = (config)=>(config._privateMeta = {
9881
9935
  configFilePath
9882
9936
  }, config);
9883
- if ('native' === loader || 'auto' === loader && (process.features.typescript || process.versions.bun || process.versions.deno) || /\.(?:js|mjs|cjs)$/.test(configFilePath)) try {
9884
- let configFileURL = pathToFileURL(configFilePath).href, exportModule = await import(`${configFileURL}?t=${Date.now()}`);
9885
- configExport = exportModule.default ? exportModule.default : exportModule;
9886
- } catch (err) {
9887
- let errorMessage = `Failed to load file with native loader: ${color.dim(configFilePath)}`;
9888
- if ('native' === loader) throw src_logger.error(errorMessage), err;
9889
- src_logger.debug(`${errorMessage}, fallback to jiti.`), src_logger.debug(err);
9890
- }
9891
- if (void 0 === configExport) try {
9892
- let { createJiti } = await import("../compiled/jiti/lib/jiti.mjs"), jiti = createJiti(import.meta.filename, {
9893
- moduleCache: !1,
9894
- interopDefault: !0,
9895
- nativeModules: [
9896
- "typescript"
9897
- ]
9898
- });
9899
- configExport = await jiti.import(configFilePath, {
9900
- default: !0
9937
+ if ('native' === loader || 'auto' === loader && (process.features.typescript || process.versions.bun || process.versions.deno) || /\.(?:js|mjs|cjs)$/.test(configFilePath)) {
9938
+ let result;
9939
+ try {
9940
+ result = await loadConfigWithNative(configFilePath);
9941
+ } catch (err) {
9942
+ let errorMessage = `Failed to load file with native loader: ${color.dim(configFilePath)}`;
9943
+ if ('native' === loader) throw src_logger.error(errorMessage), err;
9944
+ src_logger.debug(`${errorMessage}, fallback to jiti.`), src_logger.debug(err);
9945
+ }
9946
+ result && (loadedConfig = {
9947
+ configExport: getConfigExport(result.configModule, exportName, configFilePath),
9948
+ dependencies: result.dependencies
9901
9949
  });
9950
+ }
9951
+ if (!loadedConfig) try {
9952
+ loadedConfig = await loadConfigWithJiti(configFilePath, exportName);
9902
9953
  } catch (err) {
9903
9954
  throw src_logger.error(`Failed to load file with jiti: ${color.dim(configFilePath)}`), err;
9904
9955
  }
9956
+ let { configExport, dependencies } = loadedConfig;
9905
9957
  if ('function' == typeof configExport) {
9906
- let command = process.argv[2], nodeEnv = process.env.NODE_ENV || '', result = await configExport({
9958
+ let nodeEnv = process.env.NODE_ENV || '', configParams = {
9907
9959
  env: nodeEnv,
9908
- command,
9960
+ command: command ?? process.argv[2],
9909
9961
  envMode: envMode || nodeEnv,
9910
9962
  meta
9911
- });
9912
- if (void 0 === result) throw Error(`${color.dim('[rsbuild:loadConfig]')} The config function must return a config object.`);
9963
+ }, result = await configExport(configParams);
9964
+ if (void 0 === result) throw Error('The config function must return a config object.');
9913
9965
  return {
9914
9966
  content: applyMetaInfo(result),
9915
- filePath: configFilePath
9967
+ filePath: configFilePath,
9968
+ dependencies
9916
9969
  };
9917
9970
  }
9918
- if (!isObject(configExport)) throw Error(`${color.dim('[rsbuild:loadConfig]')} The config must be an object or a function that returns an object, get ${color.yellow(configExport)}`);
9971
+ if (!isObject(configExport)) throw Error(`The config must be an object or a function that returns an object, get ${color.yellow(String(configExport))}`);
9919
9972
  return src_logger.debug('configuration loaded from:', configFilePath), {
9920
9973
  content: applyMetaInfo(configExport),
9921
- filePath: configFilePath
9974
+ filePath: configFilePath,
9975
+ dependencies
9922
9976
  };
9923
9977
  }
9924
- let commonOpts = {}, init_loadConfig = async (root)=>{
9925
- let { content: config, filePath } = await loadConfig_loadConfig({
9978
+ let cliState = {
9979
+ options: {}
9980
+ }, initCliAction = (command, options)=>{
9981
+ process.env.NODE_ENV || (process.env.NODE_ENV = 'build' === command || 'preview' === command ? 'production' : 'development'), options.environment?.some((env)=>env.includes(',')) && (options.environment = options.environment.flatMap((env)=>env.split(','))), cliState.command = command, cliState.options = options;
9982
+ }, init_loadConfig = async (root)=>{
9983
+ let { options, command } = cliState, { content: config, filePath, dependencies } = await loadConfig_loadConfig({
9926
9984
  cwd: root,
9927
- path: commonOpts.config,
9928
- envMode: commonOpts.envMode,
9929
- loader: commonOpts.configLoader
9985
+ path: options.config,
9986
+ envMode: options.envMode,
9987
+ loader: options.configLoader,
9988
+ command
9930
9989
  });
9931
- if (config.dev ||= {}, config.source ||= {}, config.server ||= {}, commonOpts.base && (config.server.base = commonOpts.base), commonOpts.root && (config.root = root), commonOpts.mode && (config.mode = commonOpts.mode), commonOpts.logLevel && (config.logLevel = commonOpts.logLevel), commonOpts.open && !config.server?.open && (config.server.open = commonOpts.open), void 0 !== commonOpts.host && (config.server.host = commonOpts.host), commonOpts.port && (config.server.port = commonOpts.port), void 0 !== commonOpts.distPath) {
9990
+ if (config.dev ||= {}, config.source ||= {}, config.server ||= {}, options.base && (config.server.base = options.base), options.root && (config.root = root), options.mode && (config.mode = options.mode), options.logLevel && (config.logLevel = options.logLevel), options.open && !config.server?.open && (config.server.open = options.open), void 0 !== options.host && (config.server.host = options.host), options.port && (config.server.port = options.port), void 0 !== options.strictPort && (config.server.strictPort = options.strictPort), void 0 !== options.distPath) {
9932
9991
  config.output ||= {};
9933
9992
  let { distPath } = config.output;
9934
9993
  config.output.distPath = distPath && 'object' == typeof distPath ? {
9935
9994
  ...distPath,
9936
- root: commonOpts.distPath
9995
+ root: options.distPath
9937
9996
  } : {
9938
- root: commonOpts.distPath
9997
+ root: options.distPath
9939
9998
  };
9940
9999
  }
9941
- if (void 0 !== commonOpts.sourceMap) {
9942
- let sourceMap = commonOpts.sourceMap;
10000
+ if (void 0 !== options.sourceMap) {
10001
+ let sourceMap = options.sourceMap;
9943
10002
  if ('boolean' != typeof sourceMap) throw Error('The "--source-map" option only accepts a boolean value.');
9944
10003
  config.output ||= {}, config.output.sourceMap = sourceMap;
9945
10004
  }
9946
10005
  return void 0 === config.dev.cliShortcuts && (config.dev.cliShortcuts = !0), filePath && (config.dev.watchFiles = [
9947
10006
  ...config.dev.watchFiles ? helpers_castArray(config.dev.watchFiles) : [],
9948
10007
  {
9949
- paths: filePath,
10008
+ paths: [
10009
+ filePath,
10010
+ ...dependencies
10011
+ ],
9950
10012
  type: 'reload-server'
9951
10013
  }
9952
10014
  ]), config;
9953
10015
  };
9954
- async function init_init({ cliOptions, isRestart, isBuildWatch = !1 }) {
9955
- cliOptions && (commonOpts = cliOptions), commonOpts.environment?.some((env)=>env.includes(',')) && (commonOpts.environment = commonOpts.environment.flatMap((env)=>env.split(',')));
9956
- let logger = src_logger;
10016
+ async function init_init({ isRestart, isBuildWatch = !1 } = {}) {
10017
+ let logger = src_logger, { options } = cliState;
9957
10018
  try {
9958
10019
  var envDir;
9959
- let cwd = process.cwd(), root = commonOpts.root ? ensureAbsolutePath(cwd, commonOpts.root) : cwd, rsbuild = await createRsbuild({
10020
+ let cwd = process.cwd(), root = options.root ? ensureAbsolutePath(cwd, options.root) : cwd, rsbuild = await createRsbuild({
9960
10021
  cwd: root,
9961
10022
  config: ()=>init_loadConfig(root),
9962
- environment: commonOpts.environment,
9963
- loadEnv: !1 !== commonOpts.env && {
9964
- cwd: (envDir = commonOpts.envDir) ? node_path.isAbsolute(envDir) ? envDir : node_path.join(root, envDir) : root,
9965
- mode: commonOpts.envMode
10023
+ environment: options.environment,
10024
+ loadEnv: !1 !== options.env && {
10025
+ cwd: (envDir = options.envDir) ? node_path.isAbsolute(envDir) ? envDir : node_path.join(root, envDir) : root,
10026
+ mode: options.envMode
9966
10027
  }
9967
10028
  });
9968
10029
  return logger = rsbuild.logger, rsbuild.onBeforeCreateCompiler(()=>{
@@ -10042,11 +10103,11 @@ async function watchFilesForRestart({ files, rsbuild, isBuildWatch, watchOptions
10042
10103
  watcher.on('add', onChange), watcher.on('change', onChange), watcher.on('unlink', onChange);
10043
10104
  }
10044
10105
  let applyServerOptions = (command)=>{
10045
- command.option('-o, --open [url]', 'Open the page in browser on startup').option('--port <port>', 'Set the port number for the server').option('--host [host]', 'Set the host that the server listens to');
10106
+ command.option('-o, --open [url]', 'Open the page in browser on startup').option('--port <port>', 'Set the port number for the server').option('--strict-port', 'Exit if the specified port is already in use').option('--host [host]', 'Set the host that the server listens to');
10046
10107
  };
10047
- function setupCommands() {
10108
+ function setupCommands(argv) {
10048
10109
  let cli = ((name = "")=>new CAC(name))('rsbuild');
10049
- cli.version("2.1.2"), cli.option('--base <base>', 'Set the base path of the server').option('-c, --config <config>', 'Set the configuration file (relative or absolute path)').option('--config-loader <loader>', 'Set the config file loader (auto | jiti | native)', {
10110
+ cli.version("2.1.4"), cli.option('--base <base>', 'Set the base path of the server').option('-c, --config <config>', 'Set the configuration file (relative or absolute path)').option('--config-loader <loader>', 'Set the config file loader (auto | jiti | native)', {
10050
10111
  default: 'auto'
10051
10112
  }).option('--dist-path <dir>', 'Set the root directory of output files').option('--source-map', 'Enable source map').option('--env-dir <dir>', 'Set the directory for loading `.env` files').option('--env-mode <mode>', 'Set the env mode to load the `.env.[mode]` file').option('--environment <name>', 'Set the environment name(s) to build', {
10052
10113
  type: [
@@ -10058,20 +10119,19 @@ function setupCommands() {
10058
10119
  applyServerOptions(devCommand), applyServerOptions(previewCommand);
10059
10120
  let logger = src_logger;
10060
10121
  devCommand.action(async (options)=>{
10122
+ initCliAction('dev', options);
10061
10123
  try {
10062
- let rsbuild = await init_init({
10063
- cliOptions: options
10064
- });
10124
+ let rsbuild = await init_init();
10065
10125
  if (!rsbuild) return;
10066
10126
  logger = rsbuild.logger, await rsbuild.startDevServer();
10067
10127
  } catch (err) {
10068
10128
  logger.error('Failed to start dev server.'), logger.error(err), process.exit(1);
10069
10129
  }
10070
10130
  }), buildCommand.option('-w, --watch', 'Enable watch mode to automatically rebuild on file changes').action(async (options)=>{
10131
+ initCliAction('build', options);
10071
10132
  try {
10072
10133
  options.watch || (process.env.RSPACK_UNSAFE_FAST_DROP = 'true');
10073
10134
  let rsbuild = await init_init({
10074
- cliOptions: options,
10075
10135
  isBuildWatch: options.watch
10076
10136
  });
10077
10137
  if (!rsbuild) return;
@@ -10084,20 +10144,18 @@ function setupCommands() {
10084
10144
  err instanceof Error && err.message === RSPACK_BUILD_ERROR || logger.error('Failed to build.'), logger.error(err), process.exit(1);
10085
10145
  }
10086
10146
  }), previewCommand.action(async (options)=>{
10147
+ initCliAction('preview', options);
10087
10148
  try {
10088
- let rsbuild = await init_init({
10089
- cliOptions: options
10090
- });
10149
+ let rsbuild = await init_init();
10091
10150
  if (!rsbuild) return;
10092
10151
  logger = rsbuild.logger, await rsbuild.preview();
10093
10152
  } catch (err) {
10094
10153
  logger.error('Failed to start preview server.'), logger.error(err), process.exit(1);
10095
10154
  }
10096
10155
  }), inspectCommand.option('--output <output>', 'Set the output path for inspection results').option('--verbose', 'Show complete function definitions in output').action(async (options)=>{
10156
+ initCliAction('inspect', options);
10097
10157
  try {
10098
- let rsbuild = await init_init({
10099
- cliOptions: options
10100
- });
10158
+ let rsbuild = await init_init();
10101
10159
  if (!rsbuild) return;
10102
10160
  logger = rsbuild.logger, await rsbuild.inspectConfig({
10103
10161
  verbose: options.verbose,
@@ -10109,21 +10167,17 @@ function setupCommands() {
10109
10167
  }
10110
10168
  }), cli.help((sections)=>{
10111
10169
  for (let section of (sections.shift(), sections))'Usage' === section.title && (section.body = section.body.replace('$ rsbuild', color.yellow("$ rsbuild [command] [options]"))), 'Commands' === section.title && (section.body = section.body.replace(` ${devDescription}`, `dev ${devDescription}`)), section.title?.startsWith('For more info') ? (section.title = color.dim(' For details on a sub-command, run'), section.body = color.dim(' $ rsbuild <command> -h')) : section.title && (section.title = color.cyan(section.title));
10112
- }), cli.parse();
10113
- }
10114
- let { argv: cli_argv } = process;
10115
- function initNodeEnv(command) {
10116
- process.env.NODE_ENV || (process.env.NODE_ENV = 'build' === command || 'preview' === command ? 'production' : 'development');
10170
+ }), cli.parse(argv);
10117
10171
  }
10118
10172
  function showGreeting() {
10119
10173
  let { npm_execpath, npm_lifecycle_event, NODE_RUN_SCRIPT_NAME } = process.env, isBun = npm_execpath?.includes('.bun');
10120
- src_logger.greet(`${'npx' === npm_lifecycle_event || isBun || NODE_RUN_SCRIPT_NAME ? '\n' : ''}Rsbuild v2.1.2\n`);
10174
+ src_logger.greet(`${'npx' === npm_lifecycle_event || isBun || NODE_RUN_SCRIPT_NAME ? '\n' : ''}Rsbuild v2.1.4\n`);
10121
10175
  }
10122
- function setupLogLevel() {
10123
- if (cli_argv.length <= 3) return;
10124
- let logLevelIndex = cli_argv.findIndex((item)=>'--log-level' === item || '--logLevel' === item);
10176
+ function setupLogLevel(argv) {
10177
+ if (argv.length <= 3) return;
10178
+ let logLevelIndex = argv.findIndex((item)=>'--log-level' === item || '--logLevel' === item);
10125
10179
  if (-1 !== logLevelIndex) {
10126
- let level = process.argv[logLevelIndex + 1];
10180
+ let level = argv[logLevelIndex + 1];
10127
10181
  level && [
10128
10182
  'warn',
10129
10183
  'error',
@@ -10131,13 +10185,13 @@ function setupLogLevel() {
10131
10185
  ].includes(level) && !isDebug() && (src_logger.level = level);
10132
10186
  }
10133
10187
  }
10134
- function runCLI() {
10135
- initNodeEnv(cli_argv[2]), setupLogLevel(), showGreeting();
10188
+ function runCLI({ argv = process.argv } = {}) {
10189
+ setupLogLevel(argv), showGreeting();
10136
10190
  try {
10137
- setupCommands();
10191
+ setupCommands(argv);
10138
10192
  } catch (err) {
10139
10193
  src_logger.error('Failed to start Rsbuild CLI.'), src_logger.error(err), process.exit(1);
10140
10194
  }
10141
10195
  }
10142
- let src_version = "2.1.2";
10196
+ let src_version = "2.1.4";
10143
10197
  export { PLUGIN_CSS_NAME, PLUGIN_SWC_NAME, core_rspack as rspack, createRsbuild, defaultAllowedOrigins, defineConfig, ensureAssetPrefix, loadConfig_loadConfig as loadConfig, loadEnv, logger_createLogger as createLogger, mergeRsbuildConfig, mrmime_lookup, runCLI, src_logger as logger, src_version as version };
@@ -0,0 +1,90 @@
1
+ let importer;
2
+ import { Module } from "node:module";
3
+ import { fileURLToPath } from "node:url";
4
+ import { MessageChannel } from "node:worker_threads";
5
+ let instanceId = Math.random().toString(36).slice(2), relativeImportRE = /^\.{1,2}(?:\/|\\)/;
6
+ function escapeRegExp(value) {
7
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8
+ }
9
+ function buildQueryName() {
10
+ return `fresh-import-${instanceId}`;
11
+ }
12
+ function buildQueryRE(queryName) {
13
+ return RegExp(`(?:\\?|&)${escapeRegExp(queryName)}=(\\d+),([^&]+)(?:&|$)`);
14
+ }
15
+ function formatTrackingQuery(queryName, id, context) {
16
+ return `?${queryName}=${id},${context}`;
17
+ }
18
+ function trackResolved(specifier, context, result, queryName, queryRE, onDependency) {
19
+ let isRelativeImport = relativeImportRE.test(specifier);
20
+ if ("builtin" === result.format || !isRelativeImport || !context.parentURL || queryRE.test(result.url) || !result.url.startsWith("file:")) return result;
21
+ let m = queryRE.exec(context.parentURL);
22
+ if (m) {
23
+ let [, id, contextFile] = m;
24
+ onDependency(contextFile, result.url), result.url = result.url.replace(/(\?)|$/, (_n, n1)=>`?${queryName}=${id},${contextFile}${"?" === n1 ? "&" : ""}`);
25
+ }
26
+ return result;
27
+ }
28
+ let nextId$1 = 0;
29
+ function createOffThreadImporter() {
30
+ let queryName = buildQueryName(), { port1, port2 } = new MessageChannel();
31
+ return Module.register('data:text/javascript,Math.random().toString(36).slice(2);%0Aconst relativeImportRE = /^\\.{1,2}(%3F:\\/|\\\\)/;%0Afunction escapeRegExp(value) {%0A%09return value.replace(/[.*+%3F^${}()|[\\]\\\\]/g, "\\\\$&");%0A}%0A/**%0A* Build the regex that matches the tracking query `%3F<name>=<id>,<context>`%0A* (or the `&<name>=...` form).%0A*/%0Afunction buildQueryRE(queryName) {%0A%09return new RegExp(`(%3F:\\\\%3F|&)${escapeRegExp(queryName)}=(\\\\d+),([^&]+)(%3F:&|$)`);%0A}%0A/**%0A* Shared body of the resolve hook for both the on-thread and off-thread%0A* importers. Given an already-resolved `result`, decides whether it is a tracked%0A* relative file dependency; if so, reports it via `onDependency` and tags the%0A* URL so the query propagates to its own dependencies.%0A*%0A* The sync/async difference between the two hooks lives entirely in the caller%0A* (which awaits `nextResolve` or not); this function performs no I/O. `result`%0A* is mutated in place and returned.%0A*/%0Afunction trackResolved(specifier, context, result, queryName, queryRE, onDependency) {%0A%09const isRelativeImport = relativeImportRE.test(specifier);%0A%09if (result.format === "builtin" || !isRelativeImport) return result;%0A%09if (!context.parentURL || queryRE.test(result.url) || !result.url.startsWith("file:")) return result;%0A%09const m = queryRE.exec(context.parentURL);%0A%09if (m) {%0A%09%09const [, id, contextFile] = m;%0A%09%09onDependency(contextFile, result.url);%0A%09%09result.url = result.url.replace(/(\\%3F)|$/, (_n, n1) => `%3F${queryName}=${id},${contextFile}${n1 === "%3F" %3F "&" : ""}`);%0A%09}%0A%09return result;%0A}%0A//%23endregion%0A//%23region src/off-thread/loader.ts%0Alet port;%0Alet queryName;%0Alet queryRE;%0Aconst initialize = async (data) => {%0A%09port = data.port;%0A%09queryName = data.queryName;%0A%09queryRE = buildQueryRE(queryName);%0A};%0Aconst resolve = async (specifier, context, nextResolve) => {%0A%09return trackResolved(specifier, context, await nextResolve(specifier, context), queryName, queryRE, (ctx, url) => {%0A%09%09port.postMessage({%0A%09%09%09context: ctx,%0A%09%09%09url%0A%09%09});%0A%09});%0A};%0A//%23endregion%0Aexport { initialize, resolve };%0A', {
32
+ data: {
33
+ port: port2,
34
+ queryName
35
+ },
36
+ transferList: [
37
+ port2
38
+ ]
39
+ }), port1.unref(), {
40
+ async collect (specifier) {
41
+ let id = nextId$1++, depsList = new Set(), onMessage = (e)=>{
42
+ e.context === specifier && depsList.add(e.url);
43
+ };
44
+ port1.on("message", onMessage), port1.unref();
45
+ try {
46
+ let result = await import(specifier + formatTrackingQuery(queryName, id, specifier));
47
+ return await new Promise((resolve)=>setImmediate(resolve)), {
48
+ result,
49
+ dependencies: [
50
+ ...depsList
51
+ ].filter((url)=>url.startsWith("file:")).map((url)=>fileURLToPath(url))
52
+ };
53
+ } finally{
54
+ port1.off("message", onMessage);
55
+ }
56
+ }
57
+ };
58
+ }
59
+ let nextId = 0;
60
+ function createOnThreadImporter() {
61
+ let registry = new Map(), queryName = buildQueryName(), queryRE = buildQueryRE(queryName);
62
+ return Module.registerHooks({
63
+ resolve: (specifier, context, nextResolve)=>trackResolved(specifier, context, nextResolve(specifier, context), queryName, queryRE, (ctx, url)=>{
64
+ registry.get(ctx)?.add(url);
65
+ })
66
+ }), {
67
+ async collect (specifier) {
68
+ let id = nextId++, depsList = new Set();
69
+ registry.set(specifier, depsList);
70
+ try {
71
+ return {
72
+ result: await import(specifier + formatTrackingQuery(queryName, id, specifier)),
73
+ dependencies: [
74
+ ...depsList
75
+ ].filter((url)=>url.startsWith("file:")).map((url)=>fileURLToPath(url))
76
+ };
77
+ } finally{
78
+ registry.delete(specifier);
79
+ }
80
+ }
81
+ };
82
+ }
83
+ function createImporter() {
84
+ return Module.registerHooks ? createOnThreadImporter() : Module.register ? createOffThreadImporter() : void 0;
85
+ }
86
+ let initialized = !1;
87
+ function freshImport(specifier) {
88
+ return initialized || (importer = createImporter(), initialized = !0), importer?.collect(specifier);
89
+ }
90
+ export { freshImport };
@@ -14,6 +14,7 @@ export type CommonOptions = {
14
14
  open?: boolean | string;
15
15
  host?: true | string;
16
16
  port?: number;
17
+ strictPort?: boolean;
17
18
  environment?: string[];
18
19
  logLevel?: LogLevel;
19
20
  };
@@ -27,4 +28,4 @@ export type InspectOptions = CommonOptions & {
27
28
  };
28
29
  export type DevOptions = CommonOptions;
29
30
  export type PreviewOptions = CommonOptions;
30
- export declare function setupCommands(): void;
31
+ export declare function setupCommands(argv: string[]): void;
@@ -1 +1,7 @@
1
- export declare function runCLI(): void;
1
+ export type RunCLIOptions = {
2
+ /**
3
+ * The command-line arguments to parse, matching the shape of Node.js `process.argv`
4
+ * @default process.argv
5
+ */ argv?: string[];
6
+ };
7
+ export declare function runCLI({ argv }?: RunCLIOptions): void;
@@ -1,7 +1,8 @@
1
1
  import type { RsbuildInstance } from '../types';
2
2
  import type { CommonOptions } from './commands';
3
- export declare function init({ cliOptions, isRestart, isBuildWatch }: {
4
- cliOptions?: CommonOptions;
3
+ export type CommandName = 'dev' | 'build' | 'preview' | 'inspect';
4
+ export declare const initCliAction: (command: CommandName, options: CommonOptions) => void;
5
+ export declare function init({ isRestart, isBuildWatch }?: {
5
6
  isRestart?: boolean;
6
7
  isBuildWatch?: boolean;
7
8
  }): Promise<RsbuildInstance | undefined>;
@@ -24,12 +24,15 @@ export declare const CHAIN_ID: {
24
24
  /** JS oneOf rules */ readonly JS_MAIN: 'js';
25
25
  readonly JS_WORKER: 'js-worker';
26
26
  readonly JS_RAW: 'js-raw';
27
+ readonly JS_TEXT: 'js-text';
27
28
  /** CSS oneOf rules */ readonly CSS_MAIN: 'css';
28
29
  readonly CSS_RAW: 'css-raw';
30
+ readonly CSS_TEXT: 'css-text';
29
31
  readonly CSS_URL: 'css-url';
30
32
  readonly CSS_INLINE: 'css-inline';
31
33
  /** SVG oneOf rules */ readonly SVG: 'svg';
32
34
  readonly SVG_RAW: 'svg-asset-raw';
35
+ readonly SVG_TEXT: 'svg-asset-text';
33
36
  readonly SVG_URL: 'svg-asset-url';
34
37
  readonly SVG_ASSET: 'svg-asset';
35
38
  readonly SVG_REACT: 'svg-react';
@@ -3,9 +3,9 @@
3
3
  * the public API of @rsbuild/core.
4
4
  */ import type * as Rspack from '@rspack/core';
5
5
  import { rspack } from '@rspack/core';
6
- export { runCLI } from './cli';
6
+ export { type RunCLIOptions, runCLI } from './cli';
7
7
  export { createRsbuild } from './createRsbuild';
8
- export { type ConfigParams, defineConfig, type LoadConfigOptions, type LoadConfigResult, loadConfig } from './loadConfig';
8
+ export { type ConfigParams, defineConfig, type LoadConfigOptions, type LoadConfigResult, type RsbuildConfigAsyncFn, type RsbuildConfigDefinition, type RsbuildConfigSyncFn, loadConfig } from './loadConfig';
9
9
  // Core methods
10
10
  export { type LoadEnvOptions, type LoadEnvResult, loadEnv } from './loadEnv';
11
11
  // Rsbuild version
@@ -7,7 +7,7 @@ export type ConfigParams = {
7
7
  };
8
8
  export type RsbuildConfigAsyncFn = (env: ConfigParams) => Promise<RsbuildConfig>;
9
9
  export type RsbuildConfigSyncFn = (env: ConfigParams) => RsbuildConfig;
10
- export type RsbuildConfigExport = RsbuildConfig | RsbuildConfigSyncFn | RsbuildConfigAsyncFn;
10
+ export type RsbuildConfigDefinition = RsbuildConfig | RsbuildConfigSyncFn | RsbuildConfigAsyncFn;
11
11
  export type LoadConfigOptions = {
12
12
  /**
13
13
  * The root path to resolve the config file.
@@ -18,6 +18,10 @@ export type LoadConfigOptions = {
18
18
  * If `path` is not provided, the function will search for the config file in the `cwd`.
19
19
  */ path?: string;
20
20
  /**
21
+ * Config file names to search in `cwd` when `path` is not provided.
22
+ * The list replaces the default `rsbuild.config.*` lookup order.
23
+ */ configFileNames?: string[];
24
+ /**
21
25
  * A custom meta object to be passed into the config function of `defineConfig`.
22
26
  */ meta?: Record<string, unknown>;
23
27
  /**
@@ -31,15 +35,28 @@ export type LoadConfigOptions = {
31
35
  * - 'native': Use native Node.js loader, requires TypeScript support in Node.js >= 22.6
32
36
  * @default 'auto'
33
37
  */ loader?: ConfigLoader;
38
+ /**
39
+ * The command passed to the config function.
40
+ * @default process.argv[2]
41
+ */ command?: string;
42
+ /**
43
+ * The export name to read from the config file.
44
+ * Set to `false` to execute the config file without reading exports.
45
+ * @default 'default'
46
+ */ exportName?: string | false;
34
47
  };
35
- export type LoadConfigResult = {
48
+ export type LoadConfigResult<Config = RsbuildConfig> = {
36
49
  /**
37
50
  * The loaded configuration object.
38
- */ content: RsbuildConfig;
51
+ */ content: Config;
39
52
  /**
40
53
  * The path to the loaded configuration file.
41
54
  * Return `null` if the configuration file is not found.
42
55
  */ filePath: string | null;
56
+ /**
57
+ * Absolute file paths of statically imported (relative) dependencies of the
58
+ * config file.
59
+ */ dependencies: string[];
43
60
  };
44
61
  /**
45
62
  * This function helps you to autocomplete configuration types.
@@ -47,6 +64,6 @@ export type LoadConfigResult = {
47
64
  */ export declare function defineConfig(config: RsbuildConfig): RsbuildConfig;
48
65
  export declare function defineConfig(config: RsbuildConfigSyncFn): RsbuildConfigSyncFn;
49
66
  export declare function defineConfig(config: RsbuildConfigAsyncFn): RsbuildConfigAsyncFn;
50
- export declare function defineConfig(config: RsbuildConfigExport): RsbuildConfigExport;
67
+ export declare function defineConfig(config: RsbuildConfigDefinition): RsbuildConfigDefinition;
51
68
  export type ConfigLoader = 'auto' | 'jiti' | 'native';
52
- export declare function loadConfig({ cwd, path, envMode, meta, loader }?: LoadConfigOptions): Promise<LoadConfigResult>;
69
+ export declare function loadConfig<Config = RsbuildConfig>({ cwd, path, configFileNames, envMode, meta, loader, command, exportName }?: LoadConfigOptions): Promise<LoadConfigResult<Config>>;
@@ -3,5 +3,5 @@
3
3
  * license at https://github.com/facebook/create-react-app/blob/master/LICENSE
4
4
  */ import type { InternalContext, PrintFileSizeAsset, RsbuildPlugin } from '../types';
5
5
  /** Normalize file path by removing hash for comparison across builds */ export declare function normalizeFilePath(filePath: string): string;
6
- /** Exclude source map and license files by default */ export declare const excludeAsset: (asset: PrintFileSizeAsset) => boolean;
6
+ /** Exclude source map, license, and type declaration files by default */ export declare const excludeAsset: (asset: PrintFileSizeAsset) => boolean;
7
7
  export declare const pluginFileSize: (context: InternalContext) => RsbuildPlugin;
@@ -516,7 +516,7 @@ export type PrintFileSizeOptions = {
516
516
  /**
517
517
  * A filter function to exclude static assets from the total size or detailed size.
518
518
  * If both `include` and `exclude` are set, `exclude` will take precedence.
519
- * @default (asset) => /\.(?:map|LICENSE\.txt)$/.test(asset.name)
519
+ * @default (asset) => /\.(?:map|LICENSE\.txt|d\.(?:ts|mts|cts))$/.test(asset.name)
520
520
  */ exclude?: (asset: PrintFileSizeAsset) => boolean;
521
521
  /**
522
522
  * Controls whether file size differences are displayed relative to the previous build.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsbuild/core",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "The Rspack-based build tool.",
5
5
  "homepage": "https://rsbuild.rs",
6
6
  "bugs": {
@@ -61,6 +61,7 @@
61
61
  "css-loader": "7.1.4",
62
62
  "deepmerge": "^4.3.1",
63
63
  "dotenv-expand": "^13.0.0",
64
+ "fresh-import": "^0.2.1",
64
65
  "html-rspack-plugin": "6.1.9",
65
66
  "http-proxy-middleware": "4.1.1",
66
67
  "jiti": "^2.7.0",