Tools Config
本章节描述了 Builder 中与底层工具有关的配置。
tools.autoprefixer
- 类型:
Object | Function
- 默认值:
{
flexbox: 'no-2009',
// browserslist 取决于项目中的 browserslist 配置
// 以及 `output.overrideBrowserslist`(优先级更高) 配置
overrideBrowserslist: browserslist,
}
通过 tools.autoprefixer
可以修改 autoprefixer 的配置。
Object 类型
当 tools.autoprefixer
的值为 Object
类型时,会与默认配置通过 Object.assign 合并。比如:
export default {
tools: {
autoprefixer: {
flexbox: 'no-2009',
},
},
};
Function 类型
当 tools.autoprefixer
为 Function 类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果。比如:
export default {
tools: {
autoprefixer(config) {
// 修改 flexbox 的配置
config.flexbox = 'no-2009';
},
},
};
tools.babel
- 类型:
Object | Function
- 默认值:
undefined
通过 tools.babel
可以修改 babel-loader 的配置项。
使用场景
请留意 tools.babel
在以下使用场景中的局限性:
- Rspack 场景:在使用 Rspack 作为打包工具时,使用
tools.babel
配置项将会明显拖慢 Rspack 构建速度。因为 Rspack 默认使用的是 SWC 编译,配置 Babel 会导致代码需要被编译两次,产生了额外的编译开销。
- webpack + SWC 场景:在使用 webpack 作为打包工具时,如果你使用了 Builder 的 SWC 插件进行代码编译,那么
tools.babel
选项将不会生效。
Function 类型
当 tools.babel
为 Function 类型时,默认 Babel 配置会作为第一个参数传入,你可以直接修改配置对象,也可以返回一个对象作为最终的 babel-loader
配置。
export default {
tools: {
babel(config) {
// 添加一个插件,比如配置某个组件库的按需引入
config.plugins.push([
'babel-plugin-import',
{
libraryName: 'xxx-components',
libraryDirectory: 'es',
style: true,
},
]);
},
},
};
tools.babel
函数的第二个参数提供了一些方便的工具函数,请继续阅读下方文档。
TIP
以上示例仅作为参考,通常来说,你不需要手动配置 babel-plugin-import
,因为 Builder 已经提供了更通用的 source.transformImport
配置。
Object 类型
当 tools.babel
的值为 Object
类型时,会与默认配置通过 Object.assign
浅合并。
CAUTION
Object.assign
是浅拷贝,会完全覆盖内置的 presets
或 plugins
数组,导致内置的 presets 或 plugins 失效,请在明确影响面的情况下再使用这种方式。
export default {
tools: {
babel: {
plugins: [
[
'babel-plugin-import',
{
libraryName: 'xxx-components',
libraryDirectory: 'es',
style: true,
},
],
],
},
},
};
工具函数
tools.babel
为 Function 类型时,第二个参数可用的工具函数如下:
addPlugins
- 类型:
(plugins: BabelPlugin[]) => void
添加若干个 Babel 插件。
export default {
tools: {
babel(config, { addPlugins }) {
addPlugins([
[
'babel-plugin-import',
{
libraryName: 'xxx-components',
libraryDirectory: 'es',
style: true,
},
],
]);
},
},
};
addPresets
- 类型:
(presets: BabelPlugin[]) => void
添加若干个 Babel 预设配置 (大多数情况下不需要增加预设)。
export default {
tools: {
babel(config, { addPresets }) {
addPresets(['@babel/preset-env']);
},
},
};
removePlugins
- 类型:
(plugins: string | string[]) => void
移除 Babel 插件,传入需要移除的插件名称即可,你可以传入单个字符串,也可以传入一个字符串数组。
export default {
tools: {
babel(config, { removePlugins }) {
removePlugins('babel-plugin-import');
},
},
};
removePresets
- 类型:
(presets: string | string[]) => void
移除 Babel 预设配置,传入需要移除的预设名称即可,你可以传入单个字符串,也可以传入一个字符串数组。
export default {
tools: {
babel(config, { removePresets }) {
removePresets('@babel/preset-env');
},
},
};
modifyPresetEnvOptions
- 类型:
(options: PresetEnvOptions) => void
修改 @babel/preset-env 的配置项,传入的配置会与默认配置进行浅层合并,比如:
export default {
tools: {
babel(config, { modifyPresetEnvOptions }) {
modifyPresetEnvOptions({
targets: {
browsers: ['last 2 versions'],
},
});
},
},
};
modifyPresetReactOptions
- 类型:
(options: PresetReactOptions) => void
修改 @babel/preset-react 的配置项,传入的配置会与默认配置进行浅层合并,比如:
export default {
tools: {
babel(config, { modifyPresetReactOptions }) {
modifyPresetReactOptions({
pragma: 'React.createElement',
});
},
},
};
addIncludes
已废弃,请使用 source.include 代替,两者功能完全一致。
addExcludes
已废弃,请使用 source.exclude 代替,两者功能完全一致。
调试 Babel 配置
当你通过 tools.babel
修改 babel-loader
配置后,可以在 Builder 调试模式 下查看最终生成的配置。
首先通过 DEBUG=builder
参数开启调试模式:
# 调试开发环境
DEBUG=builder pnpm dev
# 调试生产环境
DEBUG=builder pnpm build
然后打开生成的 (webpack|rspack).config.web.js
,搜索 babel-loader
关键词,即可看到完整的 babel-loader
配置内容。
tools.bundlerChain
- 类型:
Function | undefined
- 默认值:
undefined
你可以通过 tools.bundlerChain
来修改默认的 webpack 和 Rspack 配置,它的值为 Function
类型,接收两个参数:
- 第一个参数为
bundler-chain
对象实例,你可以通过这个实例来修改 webpack 和 Rspack 的配置。
- 第二个参数为一个工具集合,包括
env
、isProd
、CHAIN_ID
等。
什么是 BundlerChain
Bundler chain 是 webpack chain 的子集,其中包含一部分 webpack chain API,你可以用它来同时修改 webpack 和 Rspack 的配置。
通过 bundler chain 修改的配置,在 webpack 和 Rspack 构建时均可生效。需要注意的是,bundler chain 只支持修改 webpack 和 Rspack 间无差异部分的配置。如,修改 devtool 配置项(webpack 和 Rspack 的 devtool 属性值类型相同),或添加一个Rspack 兼容的 webpack 插件。
tools.bundlerChain
的执行时机早于 tools.webpackChain / tools.webpack / tools.rspack,因此会被其他几个配置中的修改所覆盖。
更多信息可参考 Rsbuild#tools.bundlerChain
- 类型:
Object | Function
- 默认值:
const defaultOptions = {
// Loader 配置
loaderOptions: {},
// Plugin 配置
pluginOptions: {
// cssPath 默认为 static/css, cssFilename 默认为 [name].[contenthash:8].css
filename: `${cssPath}/${cssFilename}`,
chunkFilename: `${cssPath}/async/${cssFilename}`,
ignoreOrder: true,
},
};
通过 tools.cssExtract
可以更改 mini-css-extract-plugin 的配置。
Object 类型
当此值为 Object 类型时,与默认配置通过 Object.assign 合并。比如:
export default {
tools: {
cssExtract: {
pluginOptions: {
filename: 'static/css/[name].[contenthash:8].css',
},
},
},
};
Function 类型
当此值为 Function 类型时,默认配置作为第一个参数传入,你可以直接修改配置对象,也可以返回一个对象作为最终配置。比如:
export default {
tools: {
cssExtract: config => {
config.pluginOptions.filename = 'static/css/[name].[contenthash:8].css';
return config;
},
},
};
更多配置细节可参考 mini-css-extract-plugin。
tools.cssLoader
- 类型:
Object | Function
- 默认值:
undefined
通过 tools.cssLoader
可以修改 css-loader 的配置项。默认配置如下:
{
modules: {
auto: true,
exportLocalsConvention: 'camelCase',
localIdentName: config.output.cssModuleLocalIdentName,
// isServer 表示 node (SSR) 构建
// isWebWorker 表示 web worker 构建
exportOnlyLocals: isServer || isWebWorker,
},
// 默认在开发环境下启用 CSS 的 Source Map
sourceMap: isDev,
// importLoaders 在编译 css 文件时为 `1`,在编译 sass/less 文件时为 `2`
importLoaders: 1 || 2,
}
Object 类型
当此值为 Object 类型时,会与默认配置进行深层合并 (deep merge)。比如:
export default {
tools: {
cssLoader: {
modules: {
exportOnlyLocals: true,
},
},
},
};
Function 类型
当此值为 Function 类型时,默认配置作为第一个参数传入,你可以直接修改配置对象,也可以返回一个对象作为最终配置。比如:
export default {
tools: {
cssLoader: config => {
config.modules.exportOnlyLocals = true;
return config;
},
},
};
tools.devServer
通过 tools.devServer
可以修改开发环境服务器的配置。
选项
after
添加自定义中间件,在所有开发环境中间件后执行。
export default {
tools: {
devServer: {
after: [
async (req, res, next) => {
console.log('after dev middleware');
next();
},
],
},
},
};
webpack-dev-server
使用 Express 作为服务端框架。Modern.js 中没有使用任何框架,上述中间件中 req
和 res
都是 Node 原生对象,因此 webpack-dev-server
的 Express 中间件不一定能直接在 Modern.js 中使用。
如果要迁移 webpack-dev-server
中使用的 Express 中间件,可以使用以下方式,将 Express app 作为中间件传入:
import expressMiddleware from 'my-express-middleware';
import express from 'express';
// 初始化 Express app
const app = express();
app.use(expressMiddleware);
export default {
tools: {
devServer: {
after: [app],
},
},
};
before
添加自定义中间件,在所有开发环境中间件前执行。
export default {
tools: {
devServer: {
before: [
async (req, res, next) => {
console.log('before dev middleware');
next();
},
],
},
},
};
client
{
/** 指定协议名称 */
protocol?: string;
/** 事件流路径 */
path?: string;
/** 指定监听请求的端口号 */
port?: string;
/** 指定要使用的 host */
host?: string;
}
const defaultConfig = {
path: '/webpack-hmr',
// By default it is set to the port number of the dev server
port: '',
// By default it is set to "location.hostname"
host: '',
// By default it is set to "location.protocol === 'https:' ? 'wss' : 'ws'""
protocol: '',
};
对应 HMR 客户端的配置,通常用于设置 HMR 对应的 WebSocket URL。
compress
是否对静态资源启用 gzip 压缩。
如果你需要禁用 gzip 压缩,可以将 compress
设置为 false
:
export default {
tools: {
devServer: {
compress: false,
},
},
};
devMiddleware
{
writeToDisk: boolean | ((filename: string) => boolean);
}
{
writeToDisk: (file: string) => !file.includes('.hot-update.'),
}
devMiddleware 配置项。当前配置是 webpack-dev-middleware 配置项的子集.
- 类型:
Record<string, string>
- 默认值:
undefined
设置自定义响应头。
export default {
tools: {
devServer: {
headers: {
'X-Custom-Foo': 'bar',
},
},
},
};
historyApiFallback
- 类型:
boolean | ConnectHistoryApiFallbackOptions
- 默认值:
false
在需要对一些 404 响应或其他请求提供替代页面的场景,可通过 devServer.historyApiFallback
进行设置:
export default {
tools: {
devServer: {
historyApiFallback: true,
},
},
};
更多选项和详细信息可参考 connect-history-api-fallback 文档。
hot
是否开启 Hot Module Replacement 热更新能力。
https
- 类型:
boolean | { key: string; cert: string }
- 默认值:
false
默认情况下,DevServer 会启用 HTTP 服务器。通过设置 devServer.https
为 true
将开启对 HTTPS 的支持,同时会禁用 HTTP 服务器。
你也可以手动传入 HTTPS 服务器所需要的证书和对应的私钥:
export default {
tools: {
devServer: {
https: {
key: fs.readFileSync('certificates/private.pem'),
cert: fs.readFileSync('certificates/public.pem'),
},
},
},
};
liveReload
默认情况下,当监听到文件变化时,DevServer 将会刷新页面(为使 liveReload 能够生效,devServer.hot
配置项应当禁用)。通过设置 devServer.liveReload
为 false
可以关闭该行为。
setupMiddlewares
Array<
(
middlewares: {
unshift: (...handlers: RequestHandler[]) => void;
push: (...handlers: RequestHandler[]) => void;
},
server: {
sockWrite: (
type: string,
data?: string | boolean | Record<string, any>,
) => void;
},
) => void
>;
提供执行自定义函数和应用自定义中间件的能力。
几种不同中间件之间的执行顺序是: devServer.before
=> unshift
=> 内置中间件 => push
=> devServer.after
。
export default {
tools: {
devServer: {
setupMiddlewares: [
(middlewares, server) => {
middlewares.unshift((req, res, next) => {
next();
});
middlewares.push((req, res, next) => {
next();
});
},
],
},
},
};
一些特殊场景需求可能需要使用服务器 API:
- sockWrite。允许向 hmr 客户端传递一些消息,hmr 客户端将根据接收到的消息类型进行不同的处理。如果你发送一个 "content-changed " 的消息,页面将会重新加载。
export default {
tools: {
devServer: {
setupMiddlewares: [
(middlewares, server) => {
// 添加自定义 watcher 并在文件更新时触发页面刷新
watcher.on('change', changed => {
server.sockWrite('content-changed');
});
},
],
},
},
};
proxy
- 类型:
Record<string, string> | Record<string, ProxyDetail>
- 默认值:
undefined
代理请求到指定的服务上。
export default {
tools: {
devServer: {
proxy: {
'/api': 'http://localhost:3000',
},
},
},
};
此时,/api/users 请求将会代理到 http://localhost:3000/api/users。
如果你不想传递 /api,可以通过 pathRewrite
重写请求路径:
export default {
tools: {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
},
};
DevServer Proxy 基于 http-proxy-middleware 实现。你可以使用 http-proxy-middleware 的所有配置项,具体可以查看文档。
DevServer Proxy 完整类型定义为:
import type { Options as HttpProxyOptions } from 'http-proxy-middleware';
type Filter = string | string[] | ((pathname: string, req: Request) => boolean);
type ProxyDetail = HttpProxyOptions & {
bypass?: (
req: IncomingMessage,
res: ServerResponse,
proxyOptions: ProxyOptions,
) => string | undefined | null | false;
context?: Filter;
};
type ProxyOptions =
| Record<string, string>
| Record<string, ProxyDetail>
| ProxyDetail[]
| ProxyDetail;
除了 http-proxy-middleware 的选项外,还支持 bypass 和 context 两个配置项:
- bypass:根据函数的返回值绕过代理。
- 返回
null
或 undefined
会继续用代理处理请求。
- 返回
false
会返回 404 错误。
- 返回一个具体的服务路径,将会使用此路径替代原请求路径。
- context:如果你想代理多个特定的路径到同一个目标,你可以使用 context 配置项。
// 自定义 bypass 方法
export default {
tools: {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
bypass: function (req, res, proxyOptions) {
if (req.headers.accept.indexOf('html') !== -1) {
console.log('Skipping proxy for browser request.');
return '/index.html';
}
},
},
},
},
},
};
// 代理多个路径到同一个目标
export default {
tools: {
devServer: {
proxy: [
{
context: ['/auth', '/api'],
target: 'http://localhost:3000',
},
],
},
},
};
watch
是否监听 mock/
、server/
、api/
等目录的文件变化。
tools.htmlPlugin
- 类型:
false | Object | Function
- 默认值:
const defaultHtmlPluginOptions = {
inject, // 对应 html.inject 配置项
favicon, // 对应 html.favicon 配置项
filename, // 基于 output.distPath 和 entryName 生成
template, // 默认为内置的 HTML 模板路径
templateParameters, // 对应 html.templateParameters 配置项
chunks: [entryName],
minify: { // 基于 output.disableMinimize 生成
removeComments: false,
useShortDoctype: true,
keepClosingSlash: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
removeEmptyAttributes: true,
minifyJS, // 基于 output.charset 和 tools.terser.terserOptions 生成
minifyCSS: true,
minifyURLs: true,
},
};
通过 tools.htmlPlugin
可以修改 html-webpack-plugin 或 @rspack/plugin-html 的配置项。
Object 类型
当 tools.htmlPlugin
的值为 Object
类型时,会与默认配置通过 Object.assign
合并。
export default {
tools: {
htmlPlugin: {
scriptLoading: 'blocking',
},
},
};
Function 类型
当 tools.htmlPlugin
为 Function 类型时:
- 第一个参数是默认配置的对象,可以直接修改该对象。
- 第二个参数是也是一个对象,包含了 entry 的名称和 entry 的值。
- 函数可以 return 一个新的对象作为最终的配置。
export default {
tools: {
htmlPlugin(config, { entryName, entryValue }) {
if (entryName === 'main') {
config.scriptLoading = 'blocking';
}
},
},
};
Boolean 类型
将 tools.htmlPlugin
配置为 false
,可以禁用默认的 html-webpack-plugin
插件。
export default {
tools: {
htmlPlugin: false,
},
};
禁用 JS / CSS 压缩
默认情况下,Builder 会在生产环境构建时压缩 HTML 内的 JavaScript / CSS 代码,从而提升页面性能。此能力通常在使用自定义模版或插入自定义脚本时会有帮助。然而,当开启 output.enableInlineScripts
或 output.enableInlineStyles
时,会出现对 inline JavaScript / CSS 代码重复压缩的情况,对构建性能会有一定影响。你可以通过修改 tools.htmlPlugin.minify
配置项来修改默认的压缩行为。
export default {
tools: {
htmlPlugin: config => {
if (typeof config.minify === 'object') {
config.minify.minifyJS = false;
config.minify.minifyCSS = false;
}
},
},
};
tools.less
- 类型:
Object | Function
- 默认值:
const defaultOptions = {
lessOptions: {
javascriptEnabled: true,
},
// 默认在开发环境下启用 CSS 的 Source Map
sourceMap: isDev,
};
你可以通过 tools.less
修改 less-loader 的配置。
Object 类型
当 tools.less
的值为 Object
类型时,会与默认配置通过 Object.assign 进行浅层合并,值得注意的是,lessOptions
会通过 deepMerge 进行深层合并。
export default {
tools: {
less: {
lessOptions: {
javascriptEnabled: false,
},
},
},
};
Function 类型
当 tools.less
为 Function 类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果,第二个参数提供了一些可以直接调用的工具函数:
export default {
tools: {
less(config) {
// 修改 lessOptions 配置
config.lessOptions = {
javascriptEnabled: false,
};
},
},
};
修改 Less 版本
在某些场景下,如果你需要使用特定的 Less 版本,而不是使用 Builder 内置的 Less v4,可以在项目中安装需要使用的 Less 版本,并通过 less-loader
的 implementation
选项设置。
export default {
tools: {
less: {
implementation: require('less'),
},
},
};
工具函数
addExcludes
- 类型:
(excludes: RegExp | RegExp[]) => void
用来指定 less-loader
不编译哪些文件,你可以传入一个或多个正则表达式来匹配 less 文件的路径。例如:
export default {
tools: {
less(config, { addExcludes }) {
addExcludes(/node_modules/);
},
},
};
tools.minifyCss
- 类型:
Object | Function | undefined
- 默认值:
const defaultOptions = {
minimizerOptions: {
preset: [
'default',
{
mergeLonghand: false,
},
],
},
};
在生产环境构建时,Builder 会通过 css-minimizer-webpack-plugin 对 CSS 代码进行压缩优化。可以通过 tools.minifyCss
修改 css-minimizer-webpack-plugin 的配置。
Object 类型
当 tools.minifyCss
的值为 Object
类型时,会与默认配置通过 Object.assign
合并。
例如下面修改 cssnano 的 preset
配置:
export default {
tools: {
minifyCss: {
minimizerOptions: {
preset: require.resolve('cssnano-preset-simple'),
},
},
},
};
Function 类型
当 tools.minifyCss
配置为 Function
类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果。
export default {
tools: {
minifyCss: options => {
options.minimizerOptions = {
preset: require.resolve('cssnano-preset-simple'),
},
}
}
};
tools.postcss
- 类型:
Object | Function
- 默认值:
const defaultOptions = {
postcssOptions: {
plugins: [
// 以下插件默认启用
require('postcss-nesting'),
require('postcss-media-minmax'),
require('postcss-flexbugs-fixes'),
require('autoprefixer')({
flexbox: 'no-2009',
}),
// 以下插件仅在需要兼容低版本浏览器时启用
require('postcss-custom-properties'),
require('postcss-initial'),
require('postcss-page-break'),
require('postcss-font-variant'),
],
// 默认在开发环境下启用 CSS 的 Source Map
sourceMap: isDev,
},
};
Builder 默认集成 PostCSS,你可以通过 tools.postcss
对 postcss-loader 进行配置。
Function 类型
值为 Function 类型时,内部默认配置作为第一参数传入,可以直接修改配置对象不做返回,也可以返回一个对象作为最终结果;第二个参数为修改 postcss-loader 配置的工具函数集合。
例如,需要在原有插件的基础上新增一个 PostCSS 插件,在 postcssOptions.plugins 数组中 push 一个新的插件即可:
export default {
tools: {
postcss: opts => {
opts.postcssOptions.plugins.push(require('postcss-px-to-viewport'));
},
},
};
需要给 PostCSS 插件传递参数时,可以通过函数参数的形式进行传入:
export default {
tools: {
postcss: opts => {
const viewportPlugin = require('postcss-px-to-viewport')({
viewportWidth: 375,
});
opts.postcssOptions.plugins.push(viewportPlugin);
},
},
};
tools.postcss
可以返回一个配置对象,并完全替换默认配置:
export default {
tools: {
postcss: () => {
return {
postcssOptions: {
plugins: [require('postcss-px-to-viewport')],
},
};
},
},
};
Object 类型
当此值为 Object 类型时,与默认配置通过 Object.assign
合并。注意 Object.assign
是浅拷贝,会完全覆盖内置的 plugins
数组,请谨慎使用。
export default {
tools: {
postcss: {
// 由于使用 `Object.assign` 合并,因此默认的 postcssOptions 会被覆盖。
postcssOptions: {
plugins: [require('postcss-px-to-viewport')],
},
},
},
};
工具函数
addPlugins
- 类型:
(plugins: PostCSSPlugin | PostCSSPlugin[]) => void
用于添加额外的 PostCSS 插件,你可以传入单个 PostCSS 插件,也可以传入 PostCSS 插件数组。
export default {
tools: {
postcss: (config, { addPlugins }) => {
// 添加一个插件
addPlugins(require('postcss-preset-env'));
// 批量添加插件
addPlugins([require('postcss-preset-env'), require('postcss-import')]);
},
},
};
TIP
Builder 中使用的 PostCSS 版本为 v8,当你引入社区中的 PostCSS 插件时,请注意版本是否适配,部分旧版本插件可能无法在 PostCSS v8 下运行。
tools.pug
- 类型:
true | Object | Function | undefined
- 默认值:
false
配置 Pug 模板引擎。
Boolean 类型
Builder 默认不启用 Pug 模板引擎,你可以将 tools.pug
设置为 true
来启用它。
export default {
tools: {
pug: true,
},
};
启用后,你可以在 html.template
中指定使用 index.pug
作为模板文件。
Object 类型
当 tools.terser
的值为 Object
类型时,可以配置 Pug 模板引擎的选项:
export default {
tools: {
pug: {
doctype: 'xml',
},
},
};
详细参数请查看 Pug API Reference。
Function 类型
当 tools.pug
配置为 Function
类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果。
export default {
tools: {
pug(config) {
config.doctype = 'xml';
},
},
};
tools.sass
- 类型:
Object | Function
- 默认值:
const defaultOptions = {
// 默认在开发环境下启用 CSS 的 Source Map
sourceMap: isDev,
};
你可以通过 tools.sass
修改 sass-loader 的配置。
Object 类型
当 tools.sass
的值为 Object
类型时,会与默认配置通过 Object.assign 进行浅层合并,值得注意的是,sassOptions
会通过 deepMerge 进行深层合并。
export default {
tools: {
sass: {
sourceMap: true,
},
},
};
Function 类型
当 tools.sass
为 Function 类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果,第二个参数提供了一些可以直接调用的工具函数:
export default {
tools: {
sass(config) {
// 修改 sourceMap 配置
config.additionalData = async (content, loaderContext) => {
// ...
};
},
},
};
修改 Sass 版本
在某些场景下,如果你需要使用特定的 Sass 版本,而不是使用 Builder 内置的 Dart Sass v1,可以在项目中安装需要使用的 Sass 版本,并通过 sass-loader
的 implementation
选项设置。
export default {
tools: {
sass: {
implementation: require('sass'),
},
},
};
工具函数
addExcludes
- 类型:
(excludes: RegExp | RegExp[]) => void
用来指定 sass-loader
不编译哪些文件,你可以传入一个或多个正则表达式来匹配 sass 文件的路径。例如:
export default {
tools: {
sass(config, { addExcludes }) {
addExcludes(/node_modules/);
},
},
};
tools.styleLoader
- 类型:
Object | Function
- 默认值:
{}
通过 tools.styleLoader
可以设置 style-loader 的配置项。
值得注意的是,Builder 默认不会开启 style-loader
,你可以通过 output.disableCssExtract
配置项来开启它。
Object 类型
当此值为 Object 类型时,与默认配置通过 Object.assign 合并。比如:
export default {
tools: {
styleLoader: {
insert: 'head',
},
},
};
Function 类型
当此值为 Function 类型时,默认配置作为第一个参数传入,你可以直接修改配置对象,也可以返回一个对象作为最终配置。比如:
export default {
tools: {
styleLoader: config => {
config.insert = 'head';
return config;
},
},
};
tools.styledComponents
- 类型:
Object | Function | false
- 默认值:
{
displayName: true,
// 在 SSR 构建中 isSSR 为 true
ssr: isSSR,
// 在生产环境构建时启用 `pure` 来优化包体积
pure: isProd,
transpileTemplateLiterals: true,
}
对应 babel-plugin-styled-components 或使用 SWC 时 @swc/plugin-styled-components 的配置。 值为 Object
类型时,利用 Object.assign 函数与默认配置合并。比如:
export default {
tools: {
styledComponents: {
pure: false,
},
},
};
值为 Function
类型时,第一个参数为默认配置,第二个参数提供了一些可以直接调用的工具函数:
export default {
tools: {
styledComponents(config) {
// 修改 pure 配置
config.pure = false;
},
},
};
该特性默认启用,你可以配置 tools.styledComponents
为 false
来关闭该行为,关闭后可以提升编译性能:
export default {
tools: {
styledComponents: false,
},
};
tools.terser
- 类型:
Object | Function | undefined
- 默认值:
const defaultTerserOptions = {
terserOptions: {
mangle: {
safari10: true,
},
},
};
在生产环境构建时,Builder 会通过 terser-webpack-plugin 对 JavaScript 代码进行压缩优化。可以通过 tools.terser
修改 terser-webpack-plugin 的配置。
Object 类型
当 tools.terser
的值为 Object
类型时,会与默认配置通过 Object.assign
合并。
例如通过 exclude
排除部分文件的压缩:
export default {
tools: {
terser: {
exclude: /\/excludes/,
},
},
};
Function 类型
当 tools.terser
配置为 Function
类型时,默认配置作为第一个参数传入,可以直接修改配置对象,也可以返回一个值作为最终结果。
export default {
tools: {
terser: opts => {
opts.exclude = /\/excludes/;
},
},
};
tools.tsLoader
- 类型:
Object | Function | undefined
- 默认值:
undefined
- 打包工具:
仅支持 webpack
项目中默认不开启 ts-loader,当 tools.tsLoader
不为 undefined 则表示开启 ts-loader,同时禁用 babel-loader 对 TypeScript 的编译。
Object 类型
当此值为 Object 类型时,与默认配置通过 Object.assign 合并。
默认配置如下:
{
"compilerOptions": {
"target": "es5",
"module": "ESNext"
},
"transpileOnly": true,
"allowTsInNodeModules": true
}
你可以通过 tools.tsLoader
配置项来覆盖默认配置:
export default {
tools: {
tsLoader: {
allowTsInNodeModules: false,
},
},
};
Function 类型
当此值为 Function 类型时,默认配置作为第一参数传入,可以直接修改配置对象,也可以返回一个对象作为最终配置;第二个参数为修改 ts-loader
配置工具函数集合:
export default {
tools: {
tsLoader: opts => {
opts.allowTsInNodeModules = false;
},
},
};
工具函数
addIncludes
已废弃,请使用 source.include 代替,两者功能完全一致。
addExcludes
已废弃,请使用 source.exclude 代替,两者功能完全一致。
tools.tsChecker
- 类型:
Object | Function
- 默认值:
const defaultOptions = {
typescript: {
// avoid OOM issue
memoryLimit: 8192,
// use tsconfig of user project
configFile: tsconfigPath,
// use typescript of user project
typescriptPath: require.resolve('typescript'),
},
issue: {
exclude: [
{ file: '**/*.(spec|test).ts' },
{ file: '**/node_modules/**/*' },
],
},
logger: {
log() {
// do nothing
// we only want to display error messages
},
error(message: string) {
console.error(message.replace(/ERROR/g, 'Type Error'));
},
},
},
默认情况下,Builder 会开启 fork-ts-checker-webpack-plugin 进行类型检查。你可以通过 output.disableTsChecker
配置项来关闭类型检查。
Object 类型
当 tsChecker
的值为 Object 类型时,会与默认配置进行深层合并。
export default {
tools: {
tsChecker: {
issue: {
exclude: [{ file: '**/some-folder/**/*.ts' }],
},
},
},
};
Function 类型
当 tsChecker
的值为 Function 类型时,默认配置会作为第一个参数传入,你可以直接修改配置对象,也可以返回一个对象作为最终配置。
export default {
tools: {
tsChecker(options) {
(options?.issue?.exclude as unknown[]).push({
file: '**/some-folder/**/*.ts',
});
},
},
};
tools.webpack
- 类型:
Object | Function | undefined
- 默认值:
undefined
- 打包工具:
仅支持 webpack
tools.webpack
选项用于配置原生的 webpack。
tools.bundlerChain
同样可以修改 webpack 配置,并且功能更加强大,建议优先使用 tools.bundlerChain
。
Object 类型
tools.webpack
可以配置为一个对象,这个对象将会和内置的 webpack 配置通过 webpack-merge 进行深层合并。
比如添加 resolve.alias
配置:
export default {
tools: {
webpack: {
resolve: {
alias: {
'@util': 'src/util',
},
},
},
},
};
Function 类型
tools.webpack
也可以配置为一个函数,这个函数的第一个入参为内置的 webpack 配置对象,你可以对这个对象进行修改,然后返回一份新的配置。比如:
export default {
tools: {
webpack: config => {
config.resolve.alias['@util'] = 'src/util';
return config;
},
},
};
TIP
tools.webpack
函数返回的对象会直接作为最终使用的 webpack 配置,不会再与内置的 webpack 配置进行合并。
工具集合
这个函数的第二个参数是一个对象,包含了一些工具函数和属性,详情如下:
env
- 类型:
'development' | 'production' | 'test'
通过 env 参数可以判断当前环境为 development、production 还是 test。比如:
export default {
tools: {
webpack: (config, { env }) => {
if (env === 'development') {
config.devtool = 'cheap-module-eval-source-map';
}
return config;
},
},
};
isProd
通过 isProd 参数可以判断当前环境是否为 production。比如:
export default {
tools: {
webpack: (config, { isProd }) => {
if (isProd) {
config.devtool = 'source-map';
}
return config;
},
},
};
target
- 类型:
'web' | 'node' | 'modern-web' | 'web-worker'
通过 target 参数可以判断当前构建的目标运行时环境。比如:
export default {
tools: {
webpack: (config, { target }) => {
if (target === 'node') {
// ...
}
return config;
},
},
};
isServer
判断当前构建的目标运行时环境是否为 node
,等价于 target === 'node'
。
export default {
tools: {
webpack: (config, { isServer }) => {
if (isServer) {
// ...
}
return config;
},
},
};
isWebWorker
判断当前构建的目标运行时环境是否为 web-worker
,等价于 target === 'web-worker'
。
export default {
tools: {
webpack: (config, { isWebWorker }) => {
if (isWebWorker) {
// ...
}
return config;
},
},
};
webpack
- 类型:
typeof import('webpack')
通过这个参数你可以拿到 webpack 实例。比如:
export default {
tools: {
webpack: (config, { webpack }) => {
config.plugins.push(new webpack.ProgressPlugin());
return config;
},
},
};
HtmlWebpackPlugin
- 类型:
typeof import('html-webpack-plugin')
通过这个参数你可以拿到 HtmlWebpackPlugin 实例。
export default {
tools: {
webpack: (chain, { HtmlWebpackPlugin }) => {
console.log(HtmlWebpackPlugin);
},
},
};
addRules
- 类型:
(rules: RuleSetRule | RuleSetRule[]) => void
添加额外的 webpack rules。
示例:
export default {
tools: {
webpack: (config, { addRules }) => {
// 添加单条规则
addRules({
test: /\.foo/,
loader: require.resolve('foo-loader'),
});
// 以数组形式添加多条规则
addRules([
{
test: /\.foo/,
loader: require.resolve('foo-loader'),
},
{
test: /\.bar/,
loader: require.resolve('bar-loader'),
},
]);
},
},
};
prependPlugins
- 类型:
(plugins: WebpackPluginInstance | WebpackPluginInstance[]) => void
在内部 webpack 插件数组头部添加额外的插件,数组头部的插件会优先执行。
export default {
tools: {
webpack: (config, { prependPlugins, webpack }) => {
// 添加单个插件
prependPlugins(
new webpack.BannerPlugin({
banner: 'hello world!',
}),
);
// 以数组形式添加多个插件
prependPlugins([new PluginA(), new PluginB()]);
},
},
};
appendPlugins
- 类型:
(plugins: WebpackPluginInstance | WebpackPluginInstance[]) => void
在内部 webpack 插件数组尾部添加额外的插件,数组尾部的插件会在最后执行。
export default {
tools: {
webpack: (config, { appendPlugins, webpack }) => {
// 添加单个插件
appendPlugins([
new webpack.BannerPlugin({
banner: 'hello world!',
}),
]);
// 以数组形式添加多个插件
appendPlugins([new PluginA(), new PluginB()]);
},
},
};
removePlugin
- 类型:
(name: string) => void
删除内部的 webpack 插件,参数为该插件的 constructor.name
。
例如,删除内部的 fork-ts-checker-webpack-plugin:
export default {
tools: {
webpack: (config, { removePlugin }) => {
removePlugin('ForkTsCheckerWebpackPlugin');
},
},
};
mergeConfig
- 类型:
(...configs: WebpackConfig[]) => WebpackConfig
用于合并多份 webpack 配置,等价于 webpack-merge。
export default {
tools: {
webpack: (config, { mergeConfig }) => {
return mergeConfig(config, {
devtool: 'eval',
});
},
},
};
getCompiledPath
- 类型:
(name: string) => string
获取 builder 内置依赖的所在路径,等价于 webpackChain#getCompiledPath。
tools.webpackChain
- 类型:
Function | undefined
- 默认值:
undefined
- 打包工具:
仅支持 webpack
你可以通过 tools.webpackChain
来修改默认的 webpack 配置,它的值为 Function
类型,接收两个参数:
- 第一个参数为
webpack-chain
对象实例,你可以通过这个实例来修改默认的 webpack 配置。
- 第二个参数为一个工具集合,包括
env
、isProd
、CHAIN_ID
等。
相比于 tools.webpack
,webpack-chain 不仅支持链式调用,而且能够基于别名来定位到内置的 Rule 或 Plugin,从而实现精准的配置修改。我们推荐使用 tools.webpackChain
来代替 tools.webpack
。
tools.webpackChain
的执行时机早于 tools.webpack,因此会被 tools.webpack
中的修改所覆盖。
工具集合
env
- 类型:
'development' | 'production' | 'test'
通过 env 参数可以判断当前环境为 development、production 还是 test。比如:
export default {
tools: {
webpackChain: (chain, { env }) => {
if (env === 'development') {
chain.devtool('cheap-module-eval-source-map');
}
},
},
};
isProd
通过 isProd 参数可以判断当前环境是否为 production。比如:
export default {
tools: {
webpackChain: (chain, { isProd }) => {
if (isProd) {
chain.devtool('source-map');
}
},
},
};
target
- 类型:
'web' | 'node' | 'modern-web' | 'web-worker'
通过 target 参数可以判断当前构建的目标运行时环境。比如:
export default {
tools: {
webpackChain: (chain, { target }) => {
if (target === 'node') {
// ...
}
},
},
};
isServer
判断当前构建的目标运行时环境是否为 node
,等价于 target === 'node'
。
export default {
tools: {
webpackChain: (chain, { isServer }) => {
if (isServer) {
// ...
}
},
},
};
isWebWorker
判断当前构建的目标运行时环境是否为 web-worker
,等价于 target === 'web-worker'
。
export default {
tools: {
webpackChain: (chain, { isWebWorker }) => {
if (isWebWorker) {
// ...
}
},
},
};
webpack
- 类型:
typeof import('webpack')
通过这个参数你可以拿到 webpack 实例。比如:
export default {
tools: {
webpackChain: (chain, { webpack }) => {
chain.plugin('my-progress').use(webpack.ProgressPlugin);
},
},
};
HtmlWebpackPlugin
- 类型:
typeof import('html-webpack-plugin')
通过这个参数你可以拿到 HtmlWebpackPlugin 实例。
export default {
tools: {
webpackChain: (chain, { HtmlWebpackPlugin }) => {
console.log(HtmlWebpackPlugin);
},
},
};
getCompiledPath
- 类型:
(name: string) => string
获取 builder 内置依赖的所在路径,例如:
- sass
- sass-loader
- less
- less-loader
- css-loader
- ...
该方法通常在需要与 builder 复用同一份依赖时会被用到。
TIP
Builder 内部依赖会随着版本迭代而发生变化,例如产生大版本变更。在非必要的情况下,请避免使用此 API。
export default {
tools: {
webpackChain: (chain, { getCompiledPath }) => {
const loaderPath = getCompiledPath('less-loader');
// ...
},
},
};
CHAIN_ID
Builder 中预先定义了一些常用的 Chain ID,你可以通过这些 ID 来定位到内置的 Rule 或 Plugin。
TIP
请留意,下列的一部分 Rule 或 Plugin 并不是默认存在的,当你开启特定配置项、或是注册某些插件后,它们才会被包含在 webpack 配置中。
比如,RULE.STYLUS
仅在注册了 Stylus 插件后才会存在。
CHAIN_ID.RULE
ID |
描述 |
RULE.MJS |
处理 mjs 的规则 |
RULE.JS |
处理 js 的规则 |
RULE.TS |
处理 ts 的规则 |
RULE.CSS |
处理 css 的规则 |
RULE.LESS |
处理 less 的规则 |
RULE.SASS |
处理 sass 的规则 |
RULE.STYLUS |
处理 stylus 的规则(依赖 Stylus 插件) |
RULE.SVG |
Rule for svg |
RULE.PUG |
处理 pug 的规则 |
RULE.TOML |
处理 toml 的规则 |
RULE.YAML |
处理 yaml 的规则 |
RULE.WASM |
处理 wasm 的规则 |
RULE.NODE |
处理 node 的规则 |
RULE.FONT |
处理字体的规则 |
RULE.IMAGE |
处理图片的规则 |
RULE.MEDIA |
处理媒体资源的规则 |
CHAIN_ID.ONE_OF
通过 ONE_OF.XXX
可以匹配到规则数组中的某一类规则。
ID |
描述 |
ONE_OF.SVG |
处理 SVG 的规则,在 data URI 和单独文件之间自动选择 |
ONE_OF.SVG_URL |
处理 SVG 的规则,输出为单独文件 |
ONE_OF.SVG_INLINE |
处理 SVG 的规则,作为 data URI 内联到 bundle 中 |
ONE_OF.SVG_ASSETS |
处理 SVG 的规则,在 data URI 和单独文件之间自动选择 |
CHAIN_ID.USE
通过 USE.XXX
可以匹配到对应的 loader。
ID |
描述 |
USE.TS |
对应 ts-loader |
USE.CSS |
对应 css-loader |
USE.LESS |
对应 less-loader |
USE.SASS |
对应 sass-loader |
USE.STYLUS |
对应 stylus-loader |
USE.PUG |
对应 pug-loader |
USE.VUE |
对应 vue-loader |
USE.TOML |
对应 toml-loader |
USE.YAML |
对应 yaml-loader |
USE.NODE |
对应 node-loader |
USE.URL |
对应 url-loader |
USE.SVGR |
对应 @svgr/webpack |
USE.BABEL |
对应 babel-loader |
USE.STYLE |
对应 style-loader |
USE.POSTCSS |
对应 postcss-loader |
USE.CSS_MODULES_TS |
对应 css-modules-typescript-loader |
USE.MINI_CSS_EXTRACT |
对应 mini-css-extract-plugin.loader |
USE.RESOLVE_URL_LOADER_FOR_SASS |
对应 resolve-url-loader |
CHAIN_ID.PLUGIN
通过 PLUGIN.XXX
可以匹配到对应的 plugin。
ID |
描述 |
PLUGIN.HMR |
对应 HotModuleReplacementPlugin |
PLUGIN.COPY |
对应 CopyWebpackPlugin |
PLUGIN.HTML |
对应 HtmlWebpackPlugin ,使用时需要拼接 entry 名称:${PLUGIN.HTML}-${entryName} |
PLUGIN.DEFINE |
对应 DefinePlugin |
PLUGIN.IGNORE |
对应 IgnorePlugin |
PLUGIN.BANNER |
对应 BannerPlugin |
PLUGIN.PROGRESS |
对应 Webpackbar |
PLUGIN.APP_ICON |
对应 AppIconPlugin |
PLUGIN.MANIFEST |
对应 WebpackManifestPlugin |
PLUGIN.TS_CHECKER |
对应 ForkTsCheckerWebpackPlugin |
PLUGIN.INLINE_HTML |
对应 InlineChunkHtmlPlugin |
PLUGIN.BUNDLE_ANALYZER |
对应 WebpackBundleAnalyzer |
PLUGIN.MINI_CSS_EXTRACT |
对应 MiniCssExtractPlugin |
PLUGIN.VUE_LOADER_PLUGIN |
对应 VueLoaderPlugin |
PLUGIN.REACT_FAST_REFRESH |
对应 ReactFastRefreshPlugin |
PLUGIN.NODE_POLYFILL_PROVIDE |
对应处理 node polyfill 的 ProvidePlugin |
PLUGIN.SUBRESOURCE_INTEGRITY |
对应 webpack-subresource-integrity |
PLUGIN.ASSETS_RETRY |
对应 Builder 中的 webpack 静态资源重试插件 WebpackAssetsRetryPlugin |
PLUGIN.AUTO_SET_ROOT_SIZE |
对应 Builder 中的自动设置根字体大小插件 AutoSetRootSizePlugin |
CHAIN_ID.MINIMIZER
通过 MINIMIZER.XXX
可以匹配到对应的压缩工具。
ID |
描述 |
MINIMIZER.JS |
对应 TerserWebpackPlugin |
MINIMIZER.CSS |
对应 CssMinimizerWebpackPlugin |
MINIMIZER.ESBUILD |
对应 ESBuildPlugin |
MINIMIZER.SWC |
对应 SwcWebpackPlugin |
使用示例
使用示例可参考:WebpackChain 使用示例。
tools.rspack
- 类型:
Object | Function | undefined
- 默认值:
undefined
- 打包工具:
仅支持 Rspack
tools.rspack
选项用于配置原生的 Rspack。
Object 类型
tools.rspack
可以配置为一个对象,这个对象将会和内置的 Rspack 配置通过 webpack-merge 进行深层合并。
比如添加 resolve.alias
配置:
export default {
tools: {
rspack: {
resolve: {
alias: {
'@util': 'src/util',
},
},
},
},
};
Function 类型
tools.rspack
也可以配置为一个函数,这个函数接收一个参数,即内置的 Rspack 配置对象,你可以对这个对象进行修改,然后返回一份新的配置。比如:
export default {
tools: {
rspack: config => {
config.resolve.alias['@util'] = 'src/util';
return config;
},
},
};
TIP
tools.rspack
函数返回的对象会直接作为最终使用的 Rspack 配置,不会再与内置的 Rspack 配置进行合并。
工具集合
这个函数的第二个参数是一个对象,包含了一些工具函数和属性,详情如下:
env
- 类型:
'development' | 'production' | 'test'
通过 env 参数可以判断当前环境为 development、production 还是 test。比如:
export default {
tools: {
rspack: (config, { env }) => {
if (env === 'development') {
config.devtool = 'cheap-module-eval-source-map';
}
return config;
},
},
};
isProd
通过 isProd 参数可以判断当前环境是否为 production。比如:
export default {
tools: {
rspack: (config, { isProd }) => {
if (isProd) {
config.devtool = 'source-map';
}
return config;
},
},
};
target
- 类型:
'web' | 'node' | 'modern-web' | 'web-worker'
通过 target 参数可以判断当前构建的目标运行时环境。比如:
export default {
tools: {
rspack: (config, { target }) => {
if (target === 'node') {
// ...
}
return config;
},
},
};
isServer
判断当前构建的目标运行时环境是否为 node
,等价于 target === 'node'
。
export default {
tools: {
rspack: (config, { isServer }) => {
if (isServer) {
// ...
}
return config;
},
},
};
isWebWorker
判断当前构建的目标运行时环境是否为 web-worker
,等价于 target === 'web-worker'
。
export default {
tools: {
rspack: (config, { isWebWorker }) => {
if (isWebWorker) {
// ...
}
return config;
},
},
};
rspack
- 类型:
typeof import('@rspack/core')
通过这个参数你可以拿到 Rspack 实例。比如:
export default {
tools: {
rspack: (config, { rspack }) => {
config.plugins.push(new rspack.BannerPlugin());
return config;
},
},
};
addRules
- 类型:
(rules: RuleSetRule | RuleSetRule[]) => void
添加额外的 Rspack rules。
示例:
export default {
tools: {
rspack: (config, { addRules }) => {
// 添加单条规则
addRules({
test: /\.foo/,
loader: require.resolve('foo-loader'),
});
// 以数组形式添加多条规则
addRules([
{
test: /\.foo/,
loader: require.resolve('foo-loader'),
},
{
test: /\.bar/,
loader: require.resolve('bar-loader'),
},
]);
},
},
};
prependPlugins
- 类型:
(plugins: RspackPluginInstance | RspackPluginInstance[]) => void
在内部 Rspack 插件数组头部添加额外的插件,数组头部的插件会优先执行。
export default {
tools: {
rspack: (config, { prependPlugins }) => {
// 添加单个插件
prependPlugins(new PluginA());
// 以数组形式添加多个插件
prependPlugins([new PluginA(), new PluginB()]);
},
},
};
appendPlugins
- 类型:
(plugins: RspackPluginInstance | RspackPluginInstance[]) => void
在内部 Rspack 插件数组尾部添加额外的插件,数组尾部的插件会在最后执行。
export default {
tools: {
rspack: (config, { appendPlugins }) => {
// 添加单个插件
appendPlugins([new PluginA()]);
// 以数组形式添加多个插件
appendPlugins([new PluginA(), new PluginB()]);
},
},
};
removePlugin
- 类型:
(name: string) => void
删除内部的 Rspack 插件,参数为该插件的 constructor.name
。
例如,删除内部的 webpack-bundle-analyzer:
export default {
tools: {
rspack: (config, { removePlugin }) => {
removePlugin('BundleAnalyzerPlugin');
},
},
};
mergeConfig
- 类型:
(...configs: RspackConfig[]) => RspackConfig
用于合并多份 Rspack 配置,等价于 webpack-merge。
export default {
tools: {
rspack: (config, { mergeConfig }) => {
return mergeConfig(config, {
devtool: 'eval',
});
},
},
};
getCompiledPath
- 类型:
(name: string) => string
获取 builder 内置依赖的所在路径,例如:
- sass
- sass-loader
- less
- less-loader
- ...
该方法通常在需要与 builder 复用同一份依赖时会被用到。
TIP
Builder 内部依赖会随着版本迭代而发生变化,例如产生大版本变更。在非必要的情况下,请避免使用此 API。
export default {
tools: {
rspack: (config, { getCompiledPath }) => {
const loaderPath = getCompiledPath('less-loader');
// ...
},
},
};