跳转到主文档

tools.webpackChain

  • 类型: (chain, { env, name, webpack, CHAIN_ID }) => void
  • 默认值: undefined

通过 webpack-chain 来修改默认的 webpack 配置,值为 Function 类型。

  • 函数的第一个参数为 webpack-chain 对象。
  • 函数的第二个参数为一些工具集合,包括 envnamewebpack CHAIN_ID 等。

相比于 tools.webpackwebpack-chain 不仅支持链式调用,而且能够基于别名来定位到内置的 Rule 或 Plugin,从而实现精准的配置修改。我们推荐使用 tools.webpackChain 来代替 tools.webpack

执行时机

tools.webpackChain 的执行时机早于 tools.webpack,因此会被 tools.webpack 中的修改所覆盖。

示例

以下是一些常见用法的示例,完整 API 请参考 webpack-chain 文档

新增 loader

modern.config.js
export default defineConfig({
tools: {
webpackChain: chain => {
chain.module
.rule('compile-svg')
.test(/\.svg$/)
.use('svg-inline')
.loader('svg-inline-loader');
},
},
});

新增 plugin

modern.config.js
import CleanPlugin from 'clean-webpack-plugin';

export default defineConfig({
tools: {
webpackChain: chain => {
// 注意:插件的 options 选项需要放在数组中
chain.plugin('clean').use(CleanPlugin, [
{
// some plugin options
},
]);
},
},
});

判断环境

通过 env 参数可以判断当前环境为 development 还是 production

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { env }) => {
if (env === 'development') {
// 针对 dev 场景添加配置
}

if (env === 'production') {
// 针对 build 场景添加配置
}
},
},
});

判断构建产物的运行环境

通过 name 参数可以判断当前构建产物的运行环境:

  • client: 默认值,构建产物为运行在浏览器端的代码。
  • server: 开启 server.ssr SSR 后,构建产物为针对 SSR 场景的代码。
  • modern: 开启 output.enableModernMode 后,构建产物为运行在现代浏览器上的代码。
modern.config.js
export default defineConfig({
tools: {
webpackChain: (config, { name }) => {
if (name === 'client') {
// 针对浏览器场景添加配置
}

if (name === 'server') {
// 针对 SSR 场景添加配置
}
},
},
});

webpack 对象

通过 webpack 参数可以获取 Modern.js 内部使用的 webpack 对象。

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { webpack }) => {
console.log(
new webpack.BannerPlugin({
banner: 'hello world!',
}),
);
},
},
});

建议优先使用该参数来访问 webpack 对象,而不是通过 import 来引入 webpack

如果需要通过 import 引入,则项目里需要单独安装 webpack 依赖,这样可能会导致 webpack 被重复安装,因此不推荐该做法。

modern.config.js
import webpack from 'webpack';

export default defineConfig({
tools: {
webpackChain: chain => {
console.log(
new webpack.BannerPlugin({
banner: 'hello world!',
}),
);
},
},
});

HtmlWebpackPlugin

通过 HtmlWebpackPlugin 参数可以获取 Modern.js 内部使用的 HtmlWebpackPlugin 对象。

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { HtmlWebpackPlugin }) => {
console.log(HtmlWebpackPlugin);
},
},
});

预设 ID 用法

Modern.js 中预先定义了大量的 plugins 和 loaders,通过常量 CHAIN_ID 可以读取到这些预设内容的 ID,便于进行修改。

下面是一些修改的示例:

修改 MiniCssExtractPlugin

通过 CHAIN_ID.PLUGIN.MINI_CSS_EXTRACT 可以读取到 MiniCssExtractPlugin,然后通过 tap 方法进行修改:

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
chain.plugin(CHAIN_ID.PLUGIN.MINI_CSS_EXTRACT).tap(options => ({
...options,
ignoreOrder: false,
}));
},
},
});

修改 HtmlWebpackPlugin

通过 CHAIN_ID.PLUGIN.HTML 可以读取到 HtmlWebpackPlugin

由于 Modern.js 会为每个入口文件注册一个 HtmlWebpackPlugin,因此在修改插件时,需要基于 ${CHAIN_ID.PLUGIN.HTML}-${entry} 来进行定位。

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
const entries = Object.keys(chain.entryPoints.entries());

entries.forEach(entry => {
chain.plugin(`${CHAIN_ID.PLUGIN.HTML}-${entry}`).tap(options => {
// 注意:HtmlWebpackPlugin 的选项是一个数组
options[0].inject = 'body';
return options;
});
});
},
},
});

修改 css-loader

通过 CHAIN_ID.USE.CSS 可以读取到 css-loader,然后通过 tap 方法进行修改:

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
chain.module
.rule(CHAIN_ID.RULE.LOADERS)
.oneOf(CHAIN_ID.ONE_OF.CSS)
.use(CHAIN_ID.USE.CSS)
.tap(options => ({
...options,
sourceMap: false,
}));
},
},
});

修改 babel-loader

通过 CHAIN_ID.USE.BABEL 可以读取到 babel-loader,并添加一些自定义行为。

比如修改默认的 babel-loader 配置项:

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
chain.module
.rule(CHAIN_ID.RULE.LOADERS)
.oneOf(CHAIN_ID.ONE_OF.JS)
.use(CHAIN_ID.USE.BABEL)
.tap(options => ({
...options,
plugins: [...babelOptions.plugins, require.resolve('my-plugin')],
}));
},
},
});

比如在 babel-loader 执行之后,添加自定义的 loader 进行处理:

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
chain.module
.rule(CHAIN_ID.RULE.LOADERS)
.oneOf(CHAIN_ID.ONE_OF.JS)
.use('my-loader')
.loader('my-loader')
.after(CHAIN_ID.USE.BABEL)
.options({});
},
},
});

比如在 babel-loader 执行之前,添加自定义的 loader 进行处理:

modern.config.js
export default defineConfig({
tools: {
webpackChain: (chain, { CHAIN_ID }) => {
chain.module
.rule(CHAIN_ID.RULE.LOADERS)
.oneOf(CHAIN_ID.ONE_OF.JS)
.use('my-loader')
.loader('my-loader')
.before(CHAIN_ID.USE.BABEL)
.options({});
},
},
});

预设 ID 列表

下面是完整的预设 ID 列表:

RULE

ID描述
RULE.LOADERSModern.js 预设的所有 Loaders

ONE_OF

通过 ONE_OF.XXX 可以匹配到规则数组中的某一类规则。

ID描述
ONE_OF.JS处理 JS 的规则,未开启 ts-loader 时,也会处理 TS 文件
ONE_OF.TS处理 TS 的规则,仅在开启 ts-loader 时生效
ONE_OF.CSS处理 CSS 的规则
ONE_OF.CSS_MODULES处理 CSS Modules 的规则
ONE_OF.LESS处理 LESS 的规则
ONE_OF.LESS_MODULES处理 LESS Modules 的规则
ONE_OF.SASS处理 SASS 的规则
ONE_OF.SASS_MODULES处理 SASS Modules 的规则
ONE_OF.YAML处理 .yaml 文件的规则
ONE_OF.TOML处理 .toml 文件的规则
ONE_OF.MARKDOWN处理 Markdown 的规则
ONE_OF.SVG处理 SVG 的规则,在 data URI 和单独文件之间自动选择
ONE_OF.SVG_URL处理 SVG 的规则,输出为单独文件
ONE_OF.SVG_INLINE处理 SVG 的规则,作为 data URI 内联到 bundle 中
ONE_OF.ASSETS处理图片、字体等资源的规则,在 data URI 和单独文件之间自动选择
ONE_OF.ASSETS_URL处理图片、字体等资源的规则,输出为单独文件
ONE_OF.ASSETS_INLINE处理图片、字体等资源的规则,作为 data URI 内联到 bundle 中
ONE_OF.FALLBACK处理无法识别的文件类型,通过 asset/resource 输出为文件

USE

通过 USE.XXX 可以匹配到对应的 loader。

ID描述
USE.TS对应 ts-loader
USE.CSS对应 css-loader
USE.URL对应 url-loader
USE.SVGR对应 @svgr/webpack
USE.YAML对应 yaml-loader
USE.TOML对应 toml-loader
USE.HTML对应 html-loader
USE.BABEL对应 babel-loader
USE.STYLE对应 style-loader
USE.POSTCSS对应 postcss-loader
USE.MARKDOWN对应 markdown-loader
USE.CSS_MODULES_TS对应 css-modules-typescript-loader
USE.MINI_CSS_EXTRACT对应 mini-css-extract-plugin.loader

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.LOADABLE对应 LoadableWebpackPlugin
PLUGIN.MANIFEST对应 WebpackManifestPlugin
PLUGIN.TS_CHECKER对应 ForkTsCheckerWebpackPlugin
PLUGIN.INLINE_HTML对应 InlineChunkHtmlPlugin
PLUGIN.BUNDLE_ANALYZER对应 WebpackBundleAnalyzer
PLUGIN.BOTTOM_TEMPLATE对应 BottomTemplatePlugin
PLUGIN.MINI_CSS_EXTRACT对应 MiniCssExtractPlugin
PLUGIN.REACT_FAST_REFRESH对应 ReactFastRefreshPlugin
PLUGIN.NODE_POLYFILL_PROVIDE对应处理 node polyfill 的 ProvidePlugin

MINIMIZER

通过 MINIMIZER.XXX 可以匹配到对应的压缩工具。

ID描述
MINIMIZER.JS对应 TerserWebpackPlugin
MINIMIZER.CSS对应 CssMinimizerWebpackPlugin
MINIMIZER.ESBUILD对应 ESBuildPlugin

常见问题

如何查看最终生效的 webpack 配置?

可以通过 modern inspect 命令来查看最终生效的 webpack 配置,从而确定 tools.webpackChain 的改动是否正确应用到 webpack 配置上。