如果你带着 Customary Rights 去 Webpack 官方文档搜索,会发现没有任何对应章节。这个名字不是官方术语,也不是某个隐藏配置项。它的出现通常来自两个原因:一是把 asset/resource 中的 resource 与 rights 进行了语义联想,二是用习惯权利来描述 Webpack 5 不再依赖额外 loader 即可处理静态资源的默认行为。因此,真正值得关注的是 Webpack 5 在资源模块和构建控制层面的几个变化。

一、先澄清:Customary Rights 不是官方特性
Webpack 5 官方列出的 major features 主要包括 Asset Modules、Module Federation、Persistent Caching、Improved Tree Shaking、Top Level Await 以及 output.clean 等。无论从哪个版本的迁移指南看,都没有 Customary Rights 这一项。它更可能来自社区对 Asset Modules 行为的二次解释,甚至是一些翻译工具将 asset 与 rights 强行拼接后形成的误传。
如果我们把 rights 理解为开发者对资源的控制权,那么 Asset Modules 确实赋予了这种习惯权利。过去处理一张图片需要安装 file-loader,处理小图标需要 url-loader,处理文本文件需要 raw-loader。Webpack 5 把这些 loader 的能力内置到核心模块中,开发者不再需要为了基础资源处理去维护一长串依赖。这才是 Customary Rights 这个说法背后真正想表达的东西:默认就能享有资源处理的权利。
所以,与其纠结一个不存在的术语,不如把注意力放在 Webpack 5 实际提供的资源模块机制上。下面会从 Asset Modules 的类型、自定义方式、依赖共享以及构建缓存几个角度,说明这些能力如何让资源处理变得更加自然和可控。
二、Asset Modules:默认赋予的资源处理权利
Webpack 5 引入了四种资源模块类型,分别是 asset/resource、asset/inline、asset/source 和 asset。asset/resource 相当于原来的 file-loader,它会把文件发送到输出目录,并导出该文件的 URL。asset/inline 相当于把文件内容转成 data URI 内联到产物中,行为类似 url-loader 在 limit 设置为无穷大时的表现。asset/source 则对应 raw-loader,直接导出文件的原始文本内容。
最常用的是 asset 类型,它允许根据文件大小自动在 resource 和 inline 之间切换。默认情况下,小于 8KB 的文件会被内联,超过该大小则作为独立文件输出。这个阈值可以通过 parser.dataUrlCondition.maxSize 调整。以下配置展示了几种常见的资源处理方式:
module.exports = {
output: {
assetModuleFilename: 'assets/[name].[hash][ext][query]'
},
module: {
rules: [
{
test: /\.png$/i,
type: 'asset/resource'
},
{
test: /\.svg$/i,
type: 'asset/inline'
},
{
test: /\.jpg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
}
]
}
};
这个配置里,所有 PNG 图片都会作为独立文件输出,SVG 图标则会被内联成 data URI,而 JPG 图片根据 8KB 的阈值自动选择。相比旧版本需要为每种资源安装并配置不同 loader,这种内置能力明显减少了配置复杂度和依赖数量。
迁移时需要注意,旧 file-loader 的 name、outputPath、publicPath 等选项现在由 output.assetModuleFilename 或 Rule.generator.filename 承接。如果只在 output 级别配置 assetModuleFilename,所有资源模块都会使用同一套输出路径。若想针对特定资源类型设置不同目录,则应该使用 Rule.generator。
三、定制资源行为:generator 与 parser
仅有默认行为还不够,实际项目中往往需要更精细的控制。Webpack 5 在 Rule 对象上提供了 generator 和 parser 两个配置项。generator 负责控制输出相关行为,例如文件名、输出目录和公共路径;parser 负责控制解析相关行为,例如是否内联以及内联阈值。
下面是一个更贴近真实项目的图片处理配置。它把所有图片统一输出到 images 目录,使用 contenthash 作为文件名的一部分,并将内联阈值设置为 4KB。这样既能保证小图标减少请求数,也能让大图片获得稳定的缓存文件名。
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
},
generator: {
filename: 'images/[name].[contenthash:8][ext]'
}
}
]
}
};
字体文件也可以使用同样的思路处理。例如对字体资源统一使用 asset/resource,并输出到 fonts 目录。只需要把 test 改为 /\.(woff2?|eot|ttf|otf)$/i,type 改为 asset/resource,generator.filename 改为 fonts/[name].[contenthash:8][ext] 即可。这样每个资源类型的输出位置都非常清晰,不再需要分散在多个 loader 的 options 里。
generator.filename 还可以写成函数,根据 pathData 动态生成路径。虽然大多数项目用字符串模板就足够,但当需要根据文件来源目录保持结构时,函数形式会很有用。例如:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp)$/i,
type: 'asset/resource',
generator: {
filename: function (pathData) {
return 'images/' + pathData.filename;
}
}
}
]
}
};
这种定制能力正是所谓习惯权利的核心体现。开发者不再需要依赖第三方 loader 提供零散的选项,而是通过统一的 generator 和 parser 配置对象完成资源策略定义。
四、Module Federation 中的共享依赖约定
Module Federation 是 Webpack 5 引入的另一个重量级特性,它允许不同构建产物在运行时共享模块。虽然它和资源模块没有直接关系,但在配置 shared 依赖时,各个应用之间会形成一种隐性的权利协商:每个 remote 和 host 都希望使用自己熟悉的依赖版本,但为了避免重复实例和版本冲突,必须通过 shared 字段进行约定。
shared 配置中的 singleton 和 requiredVersion 是两个关键选项。singleton 为 true 时,该依赖在整份运行时环境中只允许存在一个实例。requiredVersion 则声明当前应用期望的版本范围,Webpack 会在构建阶段检查各参与方的版本是否满足要求,如果不匹配会给出警告。以下是一个微前端应用的典型 shared 配置:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
remotes: {
app2: 'app2@http://localhost:3002/remoteEntry.js'
},
shared: {
react: {
singleton: true,
requiredVersion: '^18.0.0',
eager: true
},
'react-dom': {
singleton: true,
requiredVersion: '^18.0.0'
}
}
})
]
};
这种配置让 React 和 ReactDOM 在 host 与 remote 之间保持单例,同时要求版本满足 18.x。eager 为 true 时,共享模块会被直接放到入口依赖中,适合 host 应用;对于 remote 应用,通常不设置 eager,让共享模块由异步加载流程按需获取。
尽管这与 Customary Rights 这个名词没有直接关联,但它体现了一种更现代的依赖管理习惯:不再通过全局变量或 external 等隐式约定,而是通过明确的 shared 配置把版本协商放在构建阶段完成。这样微前端架构下的依赖共享更透明,也更容易排查版本冲突问题。
五、让构建更可预期:持久化缓存与输出清理
资源处理之外,Webpack 5 还从构建层面强化了开发者对输出目录和缓存策略的控制。以前要清理输出目录,通常需要额外安装 clean-webpack-plugin;要实现持久化缓存,则可能使用 hard-source-webpack-plugin 或社区方案。现在这些能力已经内置,减少了插件依赖,也降低了配置出错的可能。
Webpack 5 的 output.clean 可以直接在每次构建前清空输出目录,避免旧文件残留。持久化缓存则通过 cache 字段开启,type 设置为 filesystem 后,Webpack 会把模块解析和构建结果缓存到文件系统,显著加快二次构建速度。以下配置同时启用了这两个能力:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
},
output: {
clean: true,
filename: '[name].[contenthash:8].js'
}
};
buildDependencies 表示当配置文件本身发生变化时,缓存需要失效并重新构建。这样可以避免修改 webpack 配置后仍然使用旧缓存的问题。output.clean 则确保每次构建产物都是干净的,不会因为旧文件残留导致部署包中混入无用资源。
这些特性共同构成了一种更符合开发者预期的默认体验:不需要额外插件,就能获得稳定、可预测的构建结果。回到 Customary Rights 这个说法,它虽然不是一个官方术语,但反映的正是开发者对构建流程中资源处理、依赖共享、缓存清理等环节应具备可控性的期待。Webpack 5 通过 Asset Modules、Module Federation、Persistent Caching 等能力,把这些期待转化成了实际配置项。因此,与其追求一个不存在的名词,不如掌握这些官方特性,真正获得属于自己的资源控制权。
Webpack 5Customary Rights习惯权利修改时间:2026-08-27 23:30:07