diff --git a/.changeset/afraid-socks-jam.md b/.changeset/afraid-socks-jam.md new file mode 100644 index 000000000000..38951651a0d9 --- /dev/null +++ b/.changeset/afraid-socks-jam.md @@ -0,0 +1,7 @@ +--- +'@modern-js/app-tools': patch +'@modern-js/uni-builder': patch +'@modern-js/utils': patch +--- + +feat(app-tools): enable Rsbuild CLI shortcuts diff --git a/.changeset/shiny-hairs-wink.md b/.changeset/shiny-hairs-wink.md new file mode 100644 index 000000000000..8591934f31a8 --- /dev/null +++ b/.changeset/shiny-hairs-wink.md @@ -0,0 +1,5 @@ +--- +'@modern-js/uni-builder': patch +--- + +feat(uni-builder): support environment tools.babel config diff --git a/packages/cli/uni-builder/package.json b/packages/cli/uni-builder/package.json index 33a9de0ff9cc..cd3effca9c3c 100644 --- a/packages/cli/uni-builder/package.json +++ b/packages/cli/uni-builder/package.json @@ -44,7 +44,7 @@ "@rsbuild/plugin-react": "1.0.7", "@rsbuild/plugin-rem": "1.0.2", "@rsbuild/plugin-sass": "1.1.1", - "@rsbuild/plugin-source-build": "1.0.1", + "@rsbuild/plugin-source-build": "1.0.2", "@rsbuild/plugin-styled-components": "1.1.0", "@rsbuild/plugin-svgr": "1.0.5", "@rsbuild/plugin-toml": "1.0.1", diff --git a/packages/cli/uni-builder/src/rspack/index.ts b/packages/cli/uni-builder/src/rspack/index.ts index 2312375b5613..13338fd0d505 100644 --- a/packages/cli/uni-builder/src/rspack/index.ts +++ b/packages/cli/uni-builder/src/rspack/index.ts @@ -4,9 +4,10 @@ import type { RsbuildInstance, RsbuildPlugin, } from '@rsbuild/core'; +import type { PluginBabelOptions } from '@rsbuild/plugin-babel'; import { compatLegacyPlugin } from '../shared/compatLegacyPlugin'; import { parseCommonConfig } from '../shared/parseCommonConfig'; -import { SERVICE_WORKER_ENVIRONMENT_NAME } from '../shared/utils'; +import { SERVICE_WORKER_ENVIRONMENT_NAME, castArray } from '../shared/utils'; import type { CreateBuilderCommonOptions, CreateUniBuilderOptions, @@ -58,7 +59,48 @@ export async function parseConfig( ); } - if (uniBuilderConfig.tools?.babel) { + const hasEnvironmentBabelConfig = Object.values( + uniBuilderConfig.environments || {}, + ).some(c => c.tools?.babel !== undefined); + + if (hasEnvironmentBabelConfig) { + const mergeSharedBabelConfig = ( + config: PluginBabelOptions['babelLoaderOptions'], + ) => { + if (uniBuilderConfig.tools?.babel) { + return castArray(config).concat( + ...castArray(uniBuilderConfig.tools?.babel), + ); + } + return config; + }; + + const { pluginBabel } = await import('@rsbuild/plugin-babel'); + const { pluginBabelPost } = await import('./plugins/babel-post'); + Object.entries(uniBuilderConfig.environments!).forEach(([name, config]) => { + const environmentConfig = rsbuildConfig.environments?.[name]; + if (!environmentConfig) { + return; + } + if (config.tools?.babel) { + environmentConfig.plugins ??= []; + environmentConfig.plugins.push( + pluginBabel({ + babelLoaderOptions: mergeSharedBabelConfig(config.tools?.babel), + }), + pluginBabelPost(), + ); + } else if (uniBuilderConfig.tools?.babel) { + environmentConfig.plugins ??= []; + environmentConfig.plugins.push( + pluginBabel({ + babelLoaderOptions: uniBuilderConfig.tools?.babel, + }), + pluginBabelPost(), + ); + } + }); + } else if (uniBuilderConfig.tools?.babel) { const { pluginBabel } = await import('@rsbuild/plugin-babel'); const { pluginBabelPost } = await import('./plugins/babel-post'); rsbuildPlugins.push( diff --git a/packages/cli/uni-builder/src/shared/parseCommonConfig.ts b/packages/cli/uni-builder/src/shared/parseCommonConfig.ts index 5d71a4dca0b6..3eec1dc43922 100644 --- a/packages/cli/uni-builder/src/shared/parseCommonConfig.ts +++ b/packages/cli/uni-builder/src/shared/parseCommonConfig.ts @@ -315,14 +315,14 @@ export async function parseCommonConfig( }; } - const { dev: RsbuildDev, server } = transformToRsbuildServerOptions( + const { dev: rsbuildDev, server } = transformToRsbuildServerOptions( dev || {}, devServer || {}, ); rsbuildConfig.server = removeUndefinedKey(server); - rsbuildConfig.dev = removeUndefinedKey(RsbuildDev); + rsbuildConfig.dev = removeUndefinedKey(rsbuildDev); rsbuildConfig.html = html; rsbuildConfig.output = output; diff --git a/packages/cli/uni-builder/src/types.ts b/packages/cli/uni-builder/src/types.ts index fc8152cb4d8e..6d8e9d511920 100644 --- a/packages/cli/uni-builder/src/types.ts +++ b/packages/cli/uni-builder/src/types.ts @@ -4,6 +4,7 @@ import type { ConfigChainWithContext, DevConfig, DistPathConfig, + EnvironmentConfig, HtmlConfig, HtmlTagDescriptor, OutputConfig, @@ -452,5 +453,14 @@ export type UniBuilderConfig = { source?: Omit; // plugins is a new field, should avoid adding modern plugin by mistake plugins?: RsbuildPlugins; - environments?: RsbuildConfig['environments']; + environments?: { + [key: string]: EnvironmentConfig & { + tools?: { + /** + * Modify the options of [babel-loader](https://github.com/babel/babel-loader) + */ + babel?: PluginBabelOptions['babelLoaderOptions']; + }; + }; + }; } & UniBuilderExtraConfig; diff --git a/packages/cli/uni-builder/src/webpack/index.ts b/packages/cli/uni-builder/src/webpack/index.ts index da7040d86b7f..8dad6e58d902 100644 --- a/packages/cli/uni-builder/src/webpack/index.ts +++ b/packages/cli/uni-builder/src/webpack/index.ts @@ -4,10 +4,11 @@ import { type RsbuildPlugin, createRsbuild, } from '@rsbuild/core'; +import type { PluginBabelOptions } from '@rsbuild/plugin-babel'; import { compatLegacyPlugin } from '../shared/compatLegacyPlugin'; import { parseCommonConfig } from '../shared/parseCommonConfig'; import { pluginPostcss } from '../shared/plugins/postcss'; -import { SERVICE_WORKER_ENVIRONMENT_NAME } from '../shared/utils'; +import { SERVICE_WORKER_ENVIRONMENT_NAME, castArray } from '../shared/utils'; import type { CreateBuilderCommonOptions, CreateUniBuilderOptions, @@ -36,16 +37,70 @@ export async function parseConfig( }), ); - rsbuildPlugins.push( - pluginBabel( - { - babelLoaderOptions: uniBuilderConfig.tools?.babel, - }, - { - transformLodash: uniBuilderConfig.performance?.transformLodash ?? true, - }, - ), - ); + const hasEnvironmentBabelConfig = Object.values( + uniBuilderConfig.environments || {}, + ).some(c => c.tools?.babel !== undefined); + + // Add babel plugin into each environment separately + if (hasEnvironmentBabelConfig) { + const mergeSharedBabelConfig = ( + config: PluginBabelOptions['babelLoaderOptions'], + ) => { + if (uniBuilderConfig.tools?.babel) { + return castArray(config).concat( + ...castArray(uniBuilderConfig.tools?.babel), + ); + } + return config; + }; + + Object.entries(uniBuilderConfig.environments!).forEach(([name, config]) => { + const environmentConfig = rsbuildConfig.environments?.[name]; + if (!environmentConfig) { + return; + } + environmentConfig.plugins ??= []; + + if (config.tools?.babel) { + environmentConfig.plugins.push( + pluginBabel( + { + babelLoaderOptions: mergeSharedBabelConfig(config.tools?.babel), + }, + { + transformLodash: + uniBuilderConfig.performance?.transformLodash ?? true, + }, + ), + ); + } else { + environmentConfig.plugins.push( + pluginBabel( + { + babelLoaderOptions: uniBuilderConfig.tools?.babel, + }, + { + transformLodash: + uniBuilderConfig.performance?.transformLodash ?? true, + }, + ), + ); + } + }); + } else { + rsbuildPlugins.push( + pluginBabel( + { + babelLoaderOptions: uniBuilderConfig.tools?.babel, + }, + { + transformLodash: + uniBuilderConfig.performance?.transformLodash ?? true, + }, + ), + ); + } + rsbuildPlugins.push(pluginReact()); if (uniBuilderConfig.tools?.tsLoader) { diff --git a/packages/cli/uni-builder/tests/__snapshots__/babel.test.ts.snap b/packages/cli/uni-builder/tests/__snapshots__/babel.test.ts.snap index 895750e8c46b..3bb8e9a01945 100644 --- a/packages/cli/uni-builder/tests/__snapshots__/babel.test.ts.snap +++ b/packages/cli/uni-builder/tests/__snapshots__/babel.test.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`plugin-babel (rspack mode) > should not set babel-loader when babel config not modified 1`] = ` +exports[`plugin-babel (rspack mode) > should merge environment and shared babel config 1`] = ` [ { "resolve": { @@ -94,12 +94,57 @@ exports[`plugin-babel (rspack mode) > should not set babel-loader when babel con }, }, }, + { + "loader": "/node_modules//@rsbuild/plugin-babel/compiled/babel-loader/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-transform-class-properties/lib/index.js", + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components", + "style": true, + }, + ], + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components-1", + "style": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + ], + }, + }, ], }, ] `; -exports[`plugin-babel (rspack mode) > should set babel-loader when babel config modified 1`] = ` +exports[`plugin-babel (rspack mode) > should merge environment and shared babel config 2`] = ` [ { "resolve": { @@ -211,12 +256,1051 @@ exports[`plugin-babel (rspack mode) > should set babel-loader when babel config "babel-plugin-import", { "libraryDirectory": "es", - "libraryName": "xxx-components", + "libraryName": "components-1", + "style": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel (rspack mode) > should not set babel-loader when babel config not modified 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "resolve": { + "alias": { + "core-js": "/node_modules//core-js", + }, + }, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "coreJs": "3.39", + "mode": "entry", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "node_modules/.cache/.swc", + "keepImportAttributes": true, + "plugins": [ + [ + "/node_modules//@swc/plugin-styled-components/swc_plugin_styled_components.wasm", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + }, + "externalHelpers": true, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": true, + }, + "transform": { + "decoratorMetadata": true, + "legacyDecorator": true, + "react": { + "development": false, + "refresh": false, + "runtime": "automatic", + }, + "useDefineForClassFields": false, + }, + }, + "rspackExperiments": { + "import": [ + { + "camelToDashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + { + "camelToDashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + ], + }, + }, + }, + ], + }, +] +`; + +exports[`plugin-babel (rspack mode) > should set babel-loader when babel config modified 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "resolve": { + "alias": { + "core-js": "/node_modules//core-js", + }, + }, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "coreJs": "3.39", + "mode": "entry", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "node_modules/.cache/.swc", + "keepImportAttributes": true, + "plugins": [ + [ + "/node_modules//@swc/plugin-styled-components/swc_plugin_styled_components.wasm", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + }, + "externalHelpers": true, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": true, + }, + "transform": { + "decoratorMetadata": true, + "legacyDecorator": true, + "react": { + "development": false, + "refresh": false, + "runtime": "automatic", + }, + "useDefineForClassFields": false, + }, + }, + "rspackExperiments": { + "import": [ + { + "camelToDashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", "style": true, }, + { + "camelToDashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + ], + }, + }, + }, + { + "loader": "/node_modules//@rsbuild/plugin-babel/compiled/babel-loader/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-transform-class-properties/lib/index.js", + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "xxx-components", + "style": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel (rspack mode) > should set babel-loader when environment babel config defined 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "resolve": { + "alias": { + "core-js": "/node_modules//core-js", + }, + }, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "coreJs": "3.39", + "mode": "entry", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "node_modules/.cache/.swc", + "keepImportAttributes": true, + "plugins": [ + [ + "/node_modules//@swc/plugin-styled-components/swc_plugin_styled_components.wasm", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + }, + "externalHelpers": true, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": true, + }, + "transform": { + "decoratorMetadata": true, + "legacyDecorator": true, + "react": { + "development": false, + "refresh": false, + "runtime": "automatic", + }, + "useDefineForClassFields": false, + }, + }, + "rspackExperiments": { + "import": [ + { + "camelToDashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + { + "camelToDashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + ], + }, + }, + }, + { + "loader": "/node_modules//@rsbuild/plugin-babel/compiled/babel-loader/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-transform-class-properties/lib/index.js", + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components", + "style": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel (rspack mode) > should set babel-loader when environment babel config defined 2`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "resolve": { + "alias": { + "core-js": "/node_modules//core-js", + }, + }, + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "builtin:swc-loader", + "options": { + "env": { + "coreJs": "3.39", + "mode": "entry", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + }, + "isModule": "unknown", + "jsc": { + "experimental": { + "cacheRoot": "node_modules/.cache/.swc", + "keepImportAttributes": true, + "plugins": [ + [ + "/node_modules//@swc/plugin-styled-components/swc_plugin_styled_components.wasm", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + }, + "externalHelpers": true, + "parser": { + "decorators": true, + "syntax": "typescript", + "tsx": true, + }, + "transform": { + "decoratorMetadata": true, + "legacyDecorator": true, + "react": { + "development": false, + "refresh": false, + "runtime": "automatic", + }, + "useDefineForClassFields": false, + }, + }, + "rspackExperiments": { + "import": [ + { + "camelToDashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + { + "camelToDashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + ], + }, + }, + }, + ], + }, +] +`; + +exports[`plugin-babel > should add core-js-entry when output.polyfill is entry 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//babel-loader/lib/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-proposal-export-default-from/lib/index.js", + "/node_modules//@babel/plugin-proposal-partial-application/lib/index.js", + [ + "/node_modules//@babel/plugin-proposal-pipeline-operator/lib/index.js", + { + "proposal": "minimal", + }, + ], + [ + "/node_modules//@babel/plugin-transform-runtime/lib/index.js", + { + "useESModules": true, + "version": "7.26.0", + }, + ], + "/packages/cli/babel-preset/src/pluginLockCorejsVersion.js", + [ + "/compiled/babel-plugin-lodash/index.js", + {}, + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], + [ + "/node_modules//react-refresh/babel.js", + { + "skipEnvCheck": true, + }, + ], + [ + "/node_modules//babel-plugin-styled-components/lib/index.js", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-env/lib/index.js", + { + "bugfixes": true, + "corejs": { + "proposals": true, + "version": "3.37", + }, + "exclude": [ + "transform-typeof-symbol", + ], + "include": [ + "@babel/plugin-transform-class-properties", + ], + "modules": "commonjs", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + "useBuiltIns": "entry", + }, + ], + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + [ + "/node_modules//@babel/preset-react/lib/index.js", + { + "development": true, + "runtime": "automatic", + "useBuiltIns": true, + "useSpread": false, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//babel-loader/lib/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-proposal-export-default-from/lib/index.js", + "/node_modules//@babel/plugin-proposal-partial-application/lib/index.js", + [ + "/node_modules//@babel/plugin-proposal-pipeline-operator/lib/index.js", + { + "proposal": "minimal", + }, + ], + "/node_modules//babel-plugin-dynamic-import-node/lib/index.js", + [ + "/compiled/babel-plugin-lodash/index.js", + {}, + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "lib", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon-cjs", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], + [ + "/node_modules//babel-plugin-styled-components/lib/index.js", + { + "displayName": true, + "pure": false, + "ssr": true, + "transpileTemplateLiterals": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-env/lib/index.js", + { + "exclude": [ + "transform-typeof-symbol", + ], + "include": [ + "@babel/plugin-transform-class-properties", + ], + "modules": "commonjs", + "targets": [ + "node >= 14", + ], + }, + ], + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + [ + "/node_modules//@babel/preset-react/lib/index.js", + { + "development": true, + "runtime": "automatic", + "useBuiltIns": true, + "useSpread": false, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel > should apply exclude condition when using source.exclude 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "exclude": [ + "src/foo/**/*.js", + ], + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//babel-loader/lib/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-proposal-export-default-from/lib/index.js", + "/node_modules//@babel/plugin-proposal-partial-application/lib/index.js", + [ + "/node_modules//@babel/plugin-proposal-pipeline-operator/lib/index.js", + { + "proposal": "minimal", + }, + ], + [ + "/node_modules//@babel/plugin-transform-runtime/lib/index.js", + { + "useESModules": true, + "version": "7.26.0", + }, + ], + "/packages/cli/babel-preset/src/pluginLockCorejsVersion.js", + [ + "/compiled/babel-plugin-lodash/index.js", + {}, + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], + [ + "/node_modules//react-refresh/babel.js", + { + "skipEnvCheck": true, + }, + ], + [ + "/node_modules//babel-plugin-styled-components/lib/index.js", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-env/lib/index.js", + { + "bugfixes": true, + "corejs": { + "proposals": true, + "version": "3.37", + }, + "exclude": [ + "transform-typeof-symbol", + ], + "include": [ + "@babel/plugin-transform-class-properties", + ], + "modules": "commonjs", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + "useBuiltIns": "entry", + }, + ], + [ + "/node_modules//@babel/preset-typescript/lib/index.js", + { + "allExtensions": true, + "allowDeclareFields": true, + "allowNamespaces": true, + "isTSX": true, + "optimizeConstEnums": true, + }, + ], + [ + "/node_modules//@babel/preset-react/lib/index.js", + { + "development": true, + "runtime": "automatic", + "useBuiltIns": true, + "useSpread": false, + }, + ], + ], + }, + }, + ], + }, +] +`; + +exports[`plugin-babel > should merge environment and shared babel config 1`] = ` +[ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", + "use": [ + { + "loader": "/node_modules//babel-loader/lib/index.js", + "options": { + "babelrc": false, + "compact": false, + "configFile": false, + "plugins": [ + [ + "/node_modules//@babel/plugin-proposal-decorators/lib/index.js", + { + "version": "legacy", + }, + ], + "/node_modules//@babel/plugin-proposal-export-default-from/lib/index.js", + "/node_modules//@babel/plugin-proposal-partial-application/lib/index.js", + [ + "/node_modules//@babel/plugin-proposal-pipeline-operator/lib/index.js", + { + "proposal": "minimal", + }, + ], + [ + "/node_modules//@babel/plugin-transform-runtime/lib/index.js", + { + "useESModules": true, + "version": "7.26.0", + }, + ], + "/packages/cli/babel-preset/src/pluginLockCorejsVersion.js", + [ + "/compiled/babel-plugin-lodash/index.js", + {}, + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components", + "style": true, + }, + ], + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components-1", + "style": true, + }, + ], + [ + "/node_modules//react-refresh/babel.js", + { + "skipEnvCheck": true, + }, + ], + [ + "/node_modules//babel-plugin-styled-components/lib/index.js", + { + "displayName": true, + "pure": false, + "ssr": false, + "transpileTemplateLiterals": true, + }, + ], + ], + "presets": [ + [ + "/node_modules//@babel/preset-env/lib/index.js", + { + "bugfixes": true, + "corejs": { + "proposals": true, + "version": "3.37", + }, + "exclude": [ + "transform-typeof-symbol", + ], + "include": [ + "@babel/plugin-transform-class-properties", + ], + "modules": "commonjs", + "targets": [ + "> 0.01%", + "not dead", + "not op_mini all", + ], + "useBuiltIns": "entry", + }, ], - ], - "presets": [ [ "/node_modules//@babel/preset-typescript/lib/index.js", { @@ -227,6 +1311,15 @@ exports[`plugin-babel (rspack mode) > should set babel-loader when babel config "optimizeConstEnums": true, }, ], + [ + "/node_modules//@babel/preset-react/lib/index.js", + { + "development": true, + "runtime": "automatic", + "useBuiltIns": true, + "useSpread": false, + }, + ], ], }, }, @@ -235,7 +1328,7 @@ exports[`plugin-babel (rspack mode) > should set babel-loader when babel config ] `; -exports[`plugin-babel > should add core-js-entry when output.polyfill is entry 1`] = ` +exports[`plugin-babel > should merge environment and shared babel config 2`] = ` [ { "resolve": { @@ -313,6 +1406,14 @@ exports[`plugin-babel > should add core-js-entry when output.polyfill is entry 1 }, "@arco-design/web-react/icon", ], + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components-1", + "style": true, + }, + ], [ "/node_modules//react-refresh/babel.js", { @@ -380,7 +1481,7 @@ exports[`plugin-babel > should add core-js-entry when output.polyfill is entry 1 ] `; -exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` +exports[`plugin-babel > should not add core-js-entry when output.polyfill is usage 1`] = ` [ { "resolve": { @@ -427,7 +1528,14 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` "proposal": "minimal", }, ], - "/node_modules//babel-plugin-dynamic-import-node/lib/index.js", + [ + "/node_modules//@babel/plugin-transform-runtime/lib/index.js", + { + "useESModules": true, + "version": "7.26.0", + }, + ], + "/packages/cli/babel-preset/src/pluginLockCorejsVersion.js", [ "/compiled/babel-plugin-lodash/index.js", {}, @@ -436,7 +1544,7 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` "/node_modules//babel-plugin-import/lib/index.js", { "camel2DashComponentName": false, - "libraryDirectory": "lib", + "libraryDirectory": "es", "libraryName": "@arco-design/web-react", "style": true, }, @@ -446,17 +1554,23 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` "/node_modules//babel-plugin-import/lib/index.js", { "camel2DashComponentName": false, - "libraryDirectory": "react-icon-cjs", + "libraryDirectory": "react-icon", "libraryName": "@arco-design/web-react/icon", }, "@arco-design/web-react/icon", ], + [ + "/node_modules//react-refresh/babel.js", + { + "skipEnvCheck": true, + }, + ], [ "/node_modules//babel-plugin-styled-components/lib/index.js", { "displayName": true, "pure": false, - "ssr": true, + "ssr": false, "transpileTemplateLiterals": true, }, ], @@ -465,6 +1579,11 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` [ "/node_modules//@babel/preset-env/lib/index.js", { + "bugfixes": true, + "corejs": { + "proposals": true, + "version": "3.37", + }, "exclude": [ "transform-typeof-symbol", ], @@ -473,8 +1592,11 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` ], "modules": "commonjs", "targets": [ - "node >= 14", + "> 0.01%", + "not dead", + "not op_mini all", ], + "useBuiltIns": "usage", }, ], [ @@ -504,21 +1626,12 @@ exports[`plugin-babel > should adjust browserslist when target is node 1`] = ` ] `; -exports[`plugin-babel > should apply exclude condition when using source.exclude 1`] = ` +exports[`plugin-babel > should not have any pluginImport in Babel 1`] = ` [ - { - "resolve": { - "fullySpecified": false, - }, - "test": /\\\\\\.m\\?js/, - }, { "dependency": { "not": "url", }, - "exclude": [ - "src/foo/**/*.js", - ], "include": [ { "and": [ @@ -566,25 +1679,6 @@ exports[`plugin-babel > should apply exclude condition when using source.exclude "/compiled/babel-plugin-lodash/index.js", {}, ], - [ - "/node_modules//babel-plugin-import/lib/index.js", - { - "camel2DashComponentName": false, - "libraryDirectory": "es", - "libraryName": "@arco-design/web-react", - "style": true, - }, - "@arco-design/web-react", - ], - [ - "/node_modules//babel-plugin-import/lib/index.js", - { - "camel2DashComponentName": false, - "libraryDirectory": "react-icon", - "libraryName": "@arco-design/web-react/icon", - }, - "@arco-design/web-react/icon", - ], [ "/node_modules//react-refresh/babel.js", { @@ -649,34 +1743,16 @@ exports[`plugin-babel > should apply exclude condition when using source.exclude }, ], }, -] -`; - -exports[`plugin-babel > should not add core-js-entry when output.polyfill is usage 1`] = ` -[ { + "mimetype": { + "or": [ + "text/javascript", + "application/javascript", + ], + }, "resolve": { "fullySpecified": false, }, - "test": /\\\\\\.m\\?js/, - }, - { - "dependency": { - "not": "url", - }, - "include": [ - { - "and": [ - "", - { - "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, - }, - ], - }, - /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, - ], - "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, - "type": "javascript/auto", "use": [ { "loader": "/node_modules//babel-loader/lib/index.js", @@ -711,31 +1787,6 @@ exports[`plugin-babel > should not add core-js-entry when output.polyfill is usa "/compiled/babel-plugin-lodash/index.js", {}, ], - [ - "/node_modules//babel-plugin-import/lib/index.js", - { - "camel2DashComponentName": false, - "libraryDirectory": "es", - "libraryName": "@arco-design/web-react", - "style": true, - }, - "@arco-design/web-react", - ], - [ - "/node_modules//babel-plugin-import/lib/index.js", - { - "camel2DashComponentName": false, - "libraryDirectory": "react-icon", - "libraryName": "@arco-design/web-react/icon", - }, - "@arco-design/web-react/icon", - ], - [ - "/node_modules//react-refresh/babel.js", - { - "skipEnvCheck": true, - }, - ], [ "/node_modules//babel-plugin-styled-components/lib/index.js", { @@ -767,7 +1818,7 @@ exports[`plugin-babel > should not add core-js-entry when output.polyfill is usa "not dead", "not op_mini all", ], - "useBuiltIns": "usage", + "useBuiltIns": "entry", }, ], [ @@ -797,7 +1848,7 @@ exports[`plugin-babel > should not add core-js-entry when output.polyfill is usa ] `; -exports[`plugin-babel > should not have any pluginImport in Babel 1`] = ` +exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` [ { "dependency": { @@ -850,6 +1901,25 @@ exports[`plugin-babel > should not have any pluginImport in Babel 1`] = ` "/compiled/babel-plugin-lodash/index.js", {}, ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], [ "/node_modules//react-refresh/babel.js", { @@ -958,6 +2028,25 @@ exports[`plugin-babel > should not have any pluginImport in Babel 1`] = ` "/compiled/babel-plugin-lodash/index.js", {}, ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "es", + "libraryName": "@arco-design/web-react", + "style": true, + }, + "@arco-design/web-react", + ], + [ + "/node_modules//babel-plugin-import/lib/index.js", + { + "camel2DashComponentName": false, + "libraryDirectory": "react-icon", + "libraryName": "@arco-design/web-react/icon", + }, + "@arco-design/web-react/icon", + ], [ "/node_modules//babel-plugin-styled-components/lib/index.js", { @@ -1019,8 +2108,14 @@ exports[`plugin-babel > should not have any pluginImport in Babel 1`] = ` ] `; -exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` +exports[`plugin-babel > should override targets of babel-preset-env when using output.overrideBrowserslist config 1`] = ` [ + { + "resolve": { + "fullySpecified": false, + }, + "test": /\\\\\\.m\\?js/, + }, { "dependency": { "not": "url", @@ -1124,9 +2219,7 @@ exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` ], "modules": "commonjs", "targets": [ - "> 0.01%", - "not dead", - "not op_mini all", + "Chrome 80", ], "useBuiltIns": "entry", }, @@ -1155,16 +2248,34 @@ exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` }, ], }, +] +`; + +exports[`plugin-babel > should set babel-loader 1`] = ` +[ { - "mimetype": { - "or": [ - "text/javascript", - "application/javascript", - ], - }, "resolve": { "fullySpecified": false, }, + "test": /\\\\\\.m\\?js/, + }, + { + "dependency": { + "not": "url", + }, + "include": [ + { + "and": [ + "", + { + "not": /\\[\\\\\\\\/\\]node_modules\\[\\\\\\\\/\\]/, + }, + ], + }, + /\\\\\\.\\(\\?:ts\\|tsx\\|jsx\\|mts\\|cts\\)\\$/, + ], + "test": /\\\\\\.\\(\\?:js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/, + "type": "javascript/auto", "use": [ { "loader": "/node_modules//babel-loader/lib/index.js", @@ -1218,6 +2329,12 @@ exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` }, "@arco-design/web-react/icon", ], + [ + "/node_modules//react-refresh/babel.js", + { + "skipEnvCheck": true, + }, + ], [ "/node_modules//babel-plugin-styled-components/lib/index.js", { @@ -1279,7 +2396,7 @@ exports[`plugin-babel > should not set default pluginImport for Babel 1`] = ` ] `; -exports[`plugin-babel > should override targets of babel-preset-env when using output.overrideBrowserslist config 1`] = ` +exports[`plugin-babel > should set babel-loader separate by environment 1`] = ` [ { "resolve": { @@ -1357,6 +2474,14 @@ exports[`plugin-babel > should override targets of babel-preset-env when using o }, "@arco-design/web-react/icon", ], + [ + "babel-plugin-import", + { + "libraryDirectory": "es", + "libraryName": "components", + "style": true, + }, + ], [ "/node_modules//react-refresh/babel.js", { @@ -1390,7 +2515,9 @@ exports[`plugin-babel > should override targets of babel-preset-env when using o ], "modules": "commonjs", "targets": [ - "Chrome 80", + "> 0.01%", + "not dead", + "not op_mini all", ], "useBuiltIns": "entry", }, @@ -1422,7 +2549,7 @@ exports[`plugin-babel > should override targets of babel-preset-env when using o ] `; -exports[`plugin-babel > should set babel-loader 1`] = ` +exports[`plugin-babel > should set babel-loader separate by environment 2`] = ` [ { "resolve": { diff --git a/packages/cli/uni-builder/tests/babel.test.ts b/packages/cli/uni-builder/tests/babel.test.ts index 7e7da626973d..f51bc87ca468 100644 --- a/packages/cli/uni-builder/tests/babel.test.ts +++ b/packages/cli/uni-builder/tests/babel.test.ts @@ -66,6 +66,121 @@ describe('plugin-babel (rspack mode)', () => { }), ).toMatchSnapshot(); }); + + it('should set babel-loader when environment babel config defined', async () => { + const rsbuild = await createUniBuilder({ + cwd: '', + bundlerType: 'rspack', + config: { + output: { + polyfill: 'entry', + }, + performance: { + buildCache: false, + }, + environments: { + web: { + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + }, + web1: {}, + }, + }, + }); + + const configs = await rsbuild.initConfigs(); + const webConfig = configs.find(config => config.name === 'web'); + const web1Config = configs.find(config => config.name === 'web1'); + + expect( + matchRules({ + config: webConfig!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + + expect( + matchRules({ + config: web1Config!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + }); + + it('should merge environment and shared babel config', async () => { + const rsbuild = await createUniBuilder({ + cwd: '', + bundlerType: 'rspack', + config: { + output: { + polyfill: 'entry', + }, + performance: { + buildCache: false, + }, + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components-1', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + environments: { + web: { + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + }, + web1: {}, + }, + }, + }); + + const configs = await rsbuild.initConfigs(); + const webConfig = configs.find(config => config.name === 'web'); + const web1Config = configs.find(config => config.name === 'web1'); + + expect( + matchRules({ + config: webConfig!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + + expect( + matchRules({ + config: web1Config!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + }); }); describe('plugin-babel', () => { @@ -93,6 +208,123 @@ describe('plugin-babel', () => { ).toMatchSnapshot(); }); + it('should set babel-loader separate by environment', async () => { + const rsbuild = await createUniBuilder({ + cwd: '', + bundlerType: 'webpack', + config: { + output: { + polyfill: 'entry', + }, + environments: { + web: { + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + }, + web1: { + tools: { + babel: {}, + }, + }, + }, + }, + }); + + const configs = await rsbuild.initConfigs(); + const webConfig = configs.find(config => config.name === 'web'); + const web1Config = configs.find(config => config.name === 'web1'); + + expect( + matchRules({ + config: webConfig!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + + expect( + matchRules({ + config: web1Config!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + }); + + it('should merge environment and shared babel config', async () => { + const rsbuild = await createUniBuilder({ + cwd: '', + bundlerType: 'webpack', + config: { + output: { + polyfill: 'entry', + }, + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components-1', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + environments: { + web: { + tools: { + babel(config) { + config.plugins ??= []; + config.plugins.push([ + 'babel-plugin-import', + { + libraryName: 'components', + libraryDirectory: 'es', + style: true, + }, + ]); + }, + }, + }, + web1: { + tools: { + babel: {}, + }, + }, + }, + }, + }); + + const configs = await rsbuild.initConfigs(); + const webConfig = configs.find(config => config.name === 'web'); + const web1Config = configs.find(config => config.name === 'web1'); + + expect( + matchRules({ + config: webConfig!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + + expect( + matchRules({ + config: web1Config!, + testFile: 'a.js', + }), + ).toMatchSnapshot(); + }); + it('should set include/exclude', async () => { const rsbuild = await createUniBuilder({ cwd: '', diff --git a/packages/solutions/app-tools/src/config/default.ts b/packages/solutions/app-tools/src/config/default.ts index c33b3d870b56..ab82f6025006 100644 --- a/packages/solutions/app-tools/src/config/default.ts +++ b/packages/solutions/app-tools/src/config/default.ts @@ -11,6 +11,12 @@ export function createDefaultConfig( // `dev.port` should not have a default value // because we will use `server.port` by default port: undefined, + cliShortcuts: { + help: false, + // does not support restart server and print urls yet + custom: (shortcuts = []) => + shortcuts.filter(({ key }) => key !== 'r' && key !== 'u'), + }, }; const output: AppUserConfig['output'] = { diff --git a/packages/toolkit/utils/src/cli/prettyInstructions.ts b/packages/toolkit/utils/src/cli/prettyInstructions.ts index bd024cf87afb..cb4a380e3273 100644 --- a/packages/toolkit/utils/src/cli/prettyInstructions.ts +++ b/packages/toolkit/utils/src/cli/prettyInstructions.ts @@ -142,5 +142,11 @@ export const prettyInstructions = (appContext: any, config: any) => { ); } + if (config.dev?.cliShortcuts) { + message += ` ${chalk.dim('> press')} ${chalk.bold( + 'h + enter', + )} ${chalk.dim('to show shortcuts')}\n`; + } + return message; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f2cae4bffee..c87dc33adc9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -665,8 +665,8 @@ importers: specifier: 1.1.1 version: 1.1.1(@rsbuild/core@1.1.8) '@rsbuild/plugin-source-build': - specifier: 1.0.1 - version: 1.0.1(@rsbuild/core@1.1.8) + specifier: 1.0.2 + version: 1.0.2(@rsbuild/core@1.1.8) '@rsbuild/plugin-styled-components': specifier: 1.1.0 version: 1.1.0(@rsbuild/core@1.1.8) @@ -3805,10 +3805,10 @@ importers: version: link:../../toolkit/utils '@storybook/react': specifier: ~7.6.1 - version: 7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.3.3) + version: 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.3.3) storybook: specifier: ~7.6.1 - version: 7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + version: 7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10) devDependencies: '@storybook/types': specifier: ~7.6.12 @@ -11473,10 +11473,10 @@ packages: peerDependencies: '@rsbuild/core': 1.x - '@rsbuild/plugin-source-build@1.0.1': - resolution: {integrity: sha512-GA9Uapy4cTOOa0jkwf4/L4m6rPieWWOmeeEygVnJAHRdB5nW45conwlV9g1ZQC14ITHsZlai8FiZotWGPNJlwA==} + '@rsbuild/plugin-source-build@1.0.2': + resolution: {integrity: sha512-gjlFFq0eIPrAlVvNYOFKJcdjrWOxgSmjepQrZv507ECQD+t0W+wFonjLcXRQcnlp7m/cu9fBLMG8c2OjmJVh1Q==} peerDependencies: - '@rsbuild/core': 0.x || 1.x || ^1.0.1-beta.0 + '@rsbuild/core': 1.x peerDependenciesMeta: '@rsbuild/core': optional: true @@ -21672,8 +21672,8 @@ packages: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} engines: {node: '>= 14'} - yaml@2.5.0: - resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==} + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} engines: {node: '>= 14'} hasBin: true @@ -26504,11 +26504,11 @@ snapshots: reduce-configs: 1.0.0 sass-embedded: 1.81.0 - '@rsbuild/plugin-source-build@1.0.1(@rsbuild/core@1.1.8)': + '@rsbuild/plugin-source-build@1.0.2(@rsbuild/core@1.1.8)': dependencies: fast-glob: 3.3.2 json5: 2.2.3 - yaml: 2.5.0 + yaml: 2.6.1 optionalDependencies: '@rsbuild/core': 1.1.8 @@ -26919,7 +26919,7 @@ snapshots: '@mdx-js/loader': 2.3.0(webpack@5.96.1(@swc/core@1.3.42)(esbuild@0.17.19)) '@mdx-js/mdx': 2.3.0 '@mdx-js/react': 2.3.0(react@18.3.1) - '@modern-js/utils': link:packages/toolkit/utils + '@modern-js/utils': 2.60.6 '@rsbuild/core': 1.0.19 '@rsbuild/plugin-less': 1.0.3(@rsbuild/core@1.0.19) '@rsbuild/plugin-react': 1.0.7(@rsbuild/core@1.0.19) @@ -26974,7 +26974,7 @@ snapshots: '@mdx-js/loader': 2.3.0(webpack@5.96.1(esbuild@0.17.19)) '@mdx-js/mdx': 2.3.0 '@mdx-js/react': 2.3.0(react@18.3.1) - '@modern-js/utils': link:packages/toolkit/utils + '@modern-js/utils': 2.60.6 '@rsbuild/core': 1.0.19 '@rsbuild/plugin-less': 1.0.3(@rsbuild/core@1.0.19) '@rsbuild/plugin-react': 1.0.7(@rsbuild/core@1.0.19) @@ -27280,7 +27280,7 @@ snapshots: '@storybook/components': 7.6.20(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/core-events': 7.6.20 '@storybook/csf': 0.1.11 - '@storybook/docs-tools': 7.6.20(encoding@0.1.13) + '@storybook/docs-tools': 7.6.20 '@storybook/global': 5.0.0 '@storybook/manager-api': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/preview-api': 7.6.20 @@ -27306,7 +27306,7 @@ snapshots: - encoding - supports-color - '@storybook/builder-manager@7.6.20(encoding@0.1.13)': + '@storybook/builder-manager@7.6.20': dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 '@storybook/core-common': 7.6.20(encoding@0.1.13) @@ -27337,7 +27337,7 @@ snapshots: telejson: 7.2.0 tiny-invariant: 1.3.3 - '@storybook/cli@7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@storybook/cli@7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@babel/core': 7.26.0 '@babel/preset-env': 7.26.0(@babel/core@7.26.0) @@ -27346,10 +27346,10 @@ snapshots: '@storybook/codemod': 7.6.20 '@storybook/core-common': 7.6.20(encoding@0.1.13) '@storybook/core-events': 7.6.20 - '@storybook/core-server': 7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@storybook/core-server': 7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@storybook/csf-tools': 7.6.20 '@storybook/node-logger': 7.6.20 - '@storybook/telemetry': 7.6.20(encoding@0.1.13) + '@storybook/telemetry': 7.6.20 '@storybook/types': 7.6.20 '@types/semver': 7.5.8 '@yarnpkg/fslib': 2.10.3 @@ -27464,11 +27464,11 @@ snapshots: dependencies: ts-dedent: 2.2.0 - '@storybook/core-server@7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@storybook/core-server@7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.6.20(encoding@0.1.13) + '@storybook/builder-manager': 7.6.20 '@storybook/channels': 7.6.20 '@storybook/core-common': 7.6.20(encoding@0.1.13) '@storybook/core-events': 7.6.20 @@ -27479,7 +27479,7 @@ snapshots: '@storybook/manager': 7.6.20 '@storybook/node-logger': 7.6.20 '@storybook/preview-api': 7.6.20 - '@storybook/telemetry': 7.6.20(encoding@0.1.13) + '@storybook/telemetry': 7.6.20 '@storybook/types': 7.6.20 '@types/detect-port': 1.3.5 '@types/node': 18.19.64 @@ -27540,7 +27540,7 @@ snapshots: '@storybook/docs-mdx@0.1.0': {} - '@storybook/docs-tools@7.6.20(encoding@0.1.13)': + '@storybook/docs-tools@7.6.20': dependencies: '@storybook/core-common': 7.6.20(encoding@0.1.13) '@storybook/preview-api': 7.6.20 @@ -27629,11 +27629,11 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/react@7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.3.3)': + '@storybook/react@7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.3.3)': dependencies: '@storybook/client-logger': 7.6.20 '@storybook/core-client': 7.6.20 - '@storybook/docs-tools': 7.6.20(encoding@0.1.13) + '@storybook/docs-tools': 7.6.20 '@storybook/global': 5.0.0 '@storybook/preview-api': 7.6.20 '@storybook/react-dom-shim': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -27666,7 +27666,7 @@ snapshots: memoizerific: 1.11.3 qs: 6.13.0 - '@storybook/telemetry@7.6.20(encoding@0.1.13)': + '@storybook/telemetry@7.6.20': dependencies: '@storybook/client-logger': 7.6.20 '@storybook/core-common': 7.6.20(encoding@0.1.13) @@ -38122,9 +38122,9 @@ snapshots: store2@2.14.3: {} - storybook@7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10): + storybook@7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: - '@storybook/cli': 7.6.20(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@storybook/cli': 7.6.20(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - encoding @@ -39954,7 +39954,7 @@ snapshots: yaml@2.3.1: {} - yaml@2.5.0: {} + yaml@2.6.1: {} yargs-parser@18.1.3: dependencies: