本章节描述了 Rsbuild 中与源代码解析、编译方式相关的配置。
undefined
设置文件引用的别名,对应 Rspack 的 resolve.alias 配置。
对于 TypeScript 项目,你只需要在 tsconfig.json
中配置 compilerOptions.paths 即可,Rsbuild 会自动识别它,不需要额外配置 source.alias
字段,详见 「路径别名」。
alias
的值可以定义为 Object 类型,其中的相对路径会自动被 Rsbuild 转换为绝对路径。
以上配置完成后,如果你在代码中引用 @common/Foo.tsx
, 则会映射到 <project>/src/common/Foo.tsx
路径上。
alias
的值定义为函数时,可以接受预设的 alias 对象,并对其进行修改。
也可以在函数中返回一个新对象作为最终结果,新对象会覆盖预设的 alias 对象。
默认情况,source.alias
会自动匹配子路径,比如以下配置:
它的匹配结果如下:
你可以添加 $
符号来开启精确匹配,开启后将不会自动匹配子路径。
它的匹配结果如下:
你可以使用 alias
将某个 npm 包指向统一的目录。
比如项目中安装了多份 react
,你可以将 react
统一指向根目录的 node_modules
中安装的版本,避免出现打包多份 React 代码的问题。
当你在使用 alias 处理 npm 包时,请留意项目中是否使用了这个包不同的 major 版本。
比如你的项目中某个模块或 npm 依赖使用了 React 18 的 API,如果你将 React alias 到 17 版本,就会导致该模块无法引用到 React 18 的 API,导致代码异常。
'prefer-tsconfig' | 'prefer-alias'
'prefer-tsconfig'
source.aliasStrategy
用于控制 tsconfig.json
中的 paths
选项与打包工具的 alias
选项的优先级。
source.aliasStrategy
默认为 'prefer-tsconfig'
,此时 tsconfig.json
中的 paths
选项和打包工具的 alias
选项都会生效,但 tsconfig paths 选项的优先级更高。
比如同时配置以下内容:
source.alias
:由于 tsconfig paths 的优先级更高,所以:
@common
会使用 tsconfig paths 定义的值,指向 ./src/common-1
@utils
会使用 source.alias
定义的值,指向 ./src/utils
当 source.aliasStrategy
的值为 prefer-alias
时,tsconfig.json
中的 paths
选项只用于提供 TypeScript 类型定义,而不会对打包结果产生任何影响。此时,构建工具只会读取 alias
选项作为路径别名。
比如同时配置以下内容:
source.alias
:由于 tsconfig paths 只用于提供类型,所以最终只有 @common
别名生效,并指向 ./src/common-2
目录。
大部分情况下你不需要使用 prefer-alias
,但当你需要动态生成一些别名配置时,可以考虑使用它。比如,基于环境变量来生成 alias
选项:
Array<string | RegExp>
source.include
用于指定额外需要编译的 JavaScript 文件。
为了避免二次编译,默认情况下,Rsbuild 只会编译当前目录下的 JavaScript 文件,以及所有目录下的 TypeScript 和 JSX 文件,不会编译 node_modules 下的 JavaScript 文件。
通过 source.include
配置项,可以指定需要 Rsbuild 额外进行编译的目录或模块。source.include
的用法与 Rspack 中的 Rule.include 一致,支持传入字符串或正则表达式来匹配模块的路径。
比如:
比较典型的使用场景是编译 node_modules 下的 npm 包,因为某些第三方依赖存在 ESNext 的语法,这可能导致在低版本浏览器上无法运行,你可以通过该选项指定需要编译的依赖,从而解决此类问题。
以 query-string
为例,你可以做如下的配置:
上述两种方法分别通过 "路径前缀" 和 "正则表达式" 来匹配文件的绝对路径,值得留意的是,项目中所有被引用的模块都会经过匹配,因此你不能使用过于松散的值进行匹配,避免造成编译性能问题或编译异常。
当你通过 source.include
编译一个 npm 包时,Rsbuild 默认只会编译匹配到的模块,不会编译对应模块的子依赖。
以 query-string
为例,它依赖的 decode-uri-component
包中同样存在 ESNext 代码,因此你需要将 decode-uri-component
也加入到 source.include
中:
在 Monorepo 中进行开发时,如果需要引用 Monorepo 中其他库的 JavaScript 代码,也可以直接在 source.include
进行配置:
如果你匹配的模块是通过 symlink 链接到当前项目中的,那么需要匹配这个模块的真实路径,而不是 symlink 后的路径。
比如,你将 Monorepo 中的 packages/foo
路径 symlink 到当前项目的 node_modules/foo
路径下,则需要去匹配 packages/foo
路径,而不是 node_modules/foo
路径。
注意,source.include
不应该被用于编译整个 node_modules
目录,比如下面的写法是错误的:
如果你对整个 node_modules
进行编译,不仅会使编译时间大幅度增加,并且可能会产生不可预期的错误。因为 node_modules
中的大部分 npm 包发布的已经是编译后的产物,通常没必要经过二次编译。此外,core-js
等 npm 包被编译后可能会出现异常。
用于设置构建的入口模块,用法与 Rspack 的 entry 选项一致。
Array<string | RegExp>
[]
指定不需要编译的 JavaScript/TypeScript 文件。用法与 Rspack 中的 Rule.exclude 一致,支持传入字符串或正则表达式来匹配模块的路径。
比如:
Record<string, unknown>
{}
构建时将代码中的变量替换成其它值或者表达式,可以用于在代码逻辑中区分开发环境与生产环境等场景。
传入的配置对象的键名是需要替换变量的名称,或者是用 .
连接的多个标识符,配置项的值则根据类型进行不同的处理:
.
连接作为需要替换的变量名。更多细节参考 Rspack - DefinePlugin。
表达式会被替换为对应的代码段:
用于按需引入组件库的代码和样式,能力等价于 babel-plugin-import。
它与 babel-plugin-import 的区别在于,source.transformImport
不与 Babel 耦合。Rsbuild 会自动识别当前使用的编译工具是 Babel、SWC 还是 Rspack,并添加相应的按需引入配置。
当使用上述 antd 默认配置:
源代码如下:
会被转换成:
你可以手动设置 transformImport: false
来关掉 transformImport 的默认行为。
比如,当你使用了 externals
来避免打包 antd 时,由于 transformImport
默认会转换 antd 的引用路径,导致匹配的路径发生了变化,因此 externals 无法正确生效,此时你可以设置关闭 transformImport
来避免该问题。
string
用于指定需要按需加载的模块名称。当 Rsbuild 遍历代码时,如果遇到了对应模块的 import 语句,则会对其进行转换。
string
'lib'
用于拼接转换后的路径,拼接规则为 ${libraryName}/${libraryDirectory}/${member}
,其中 member 为引入成员。
示例:
转换结果:
boolean
undefined
确定是否需要引入相关样式,若为 true
,则会引入路径 ${libraryName}/${libraryDirectory}/${member}/style
。
若为 false
或 undefined
则不会引入样式。
当配置为 true
时:
转换结果:
string
undefined
该配置用于拼接引入样式时的引入路径,若该配置被指定,则 style
配置项会被忽略。拼接引入路径为 ${libraryName}/${styleLibraryDirectory}/${member}
。
当配置为 styles
时:
转换结果:
boolean
true
是否需要将 camelCase 的引入转换成 kebab-case。
示例:
转换结果:
boolean
true
是否将导入语句转换成默认导入。
示例:
转换结果:
((member: string) => string | undefined) | string
undefined
自定义转换后的导入路径,输入是引入的成员,例如配置成 (member) => `my-lib/${member}`
,会将 import { foo } from 'bar'
转换成 import foo from 'my-lib/foo'
。
在使用 Rspack 构建时,不能使用函数配置,但可以使用 handlebars 模版字符串,对于上面的函数配置,在使用模版字符串时可以用以下模版代替 my-lib/{{ member }}
,也可以使用一些内置帮助方法,例如 my-lib/{{ kebabCase member }}
来转换成 kebab-case 格式,除了 kebabCase 以外还有 camelCase,snakeCase,upperCase,lowerCase 可以使用。
((member: string) => string | undefined) | string
undefined
自定义转换后的样式导入路径,输入是引入的成员,例如配置成 (member) => `my-lib/${member}`
,会将 import { foo } from 'bar'
转换成 import foo from 'my-lib/foo'
。
在使用 Rspack 构建时,不能使用函数配置,但可以使用 handlebars 模版字符串,对于上面的函数配置,在使用模版字符串时可以用以下模版代替 my-lib/{{ member }}
,也可以使用一些内置帮助方法,例如 my-lib/{{ kebabCase member }}
来转换成 kebab-case 格式,除了 kebabCase 以外还有 camelCase,snakeCase,upperCase,lowerCase 可以使用。
string | string[]
undefined
在每个页面的入口文件前添加一段代码,这段代码会早于页面的代码执行,因此可以用于执行一些全局的代码逻辑,比如注入 polyfill、设置全局样式等。
首先创建一个 src/polyfill.ts
文件:
然后将 src/polyfill.ts
配置到 source.preEntry
上:
重新运行编译并访问任意页面,可以看到 src/polyfill.ts
中的代码已经执行,并在 console 中输出了对应的内容。
你也可以通过 source.preEntry
来配置全局样式,这段 CSS 代码会早于页面代码加载,比如引入一个 normalize.css
文件:
你可以将 preEntry
设置为数组来添加多个脚本,它们会按数组顺序执行:
string | Record<RsbuildTarget, string>
undefined
用于为 resolve.extensions 添加统一的前缀。
如果多个文件拥有相同的名称,但具有不同的文件后缀,Rsbuild 会根据 extensions 数组的顺序进行识别,解析数组中第一个被识别的文件,并跳过其余文件。
下面是配置 .web
前缀的例子。
配置完成后,extensions 数组会发生以下变化:
在代码中 import './foo'
时,会优先识别 foo.web.js
文件,再识别 foo.js
文件。
当你同时构建多种类型的产物时,你可以为不同的产物类型设置不同的 extension 前缀。此时,你需要把 resolveExtensionPrefix
设置为一个对象,对象的 key 为对应的产物类型。
比如为 web
和 node
设置不同的 extension 前缀:
在代码中 import './foo'
时,对于 node 产物,会优先识别 foo.node.js
文件,而对于 web 产物,则会优先识别 foo.web.js
文件。
undefined
该配置项将决定你使用 package.json
哪个字段导入 npm
模块。对应 webpack 的 resolve.mainFields 配置。
当你同时构建多种类型的产物时,你可以为不同的产物类型设置不同的 mainFields。此时,你需要把 resolveMainFields
设置为一个对象,对象的 key 为对应的产物类型。
比如为 web
和 node
设置不同的 mainFields: