导读:本期聚焦于石川澪创作的《Webpack 5 真的有 Customary Rights 习惯权利这个新特性吗?》,敬请观看详情。为什么在 Webpack 5 官方更新日志里找不到 Customary Rights 这个词?它并不是一个实际存在的新特性,而是部分开发者对 Asset Modules 默认行为的一种习惯性概括。文中会从资源模块类型入手,解释 asset/resource、asset/inline、asset 三者如何替代 file-loader、url-loader 与 raw-loader,说明通过 Rule.generator 和 Rule.parser 可以更精确地控制输出文件名、内联阈值以及公共路径。文章还会涉及 Module Federation 中 shared 配置的版本协商,以及持久化缓存和 output.clean 带来的构建可预期性。读完可以理解为什么这类说法会在社区出现,以及如何利用 Webpack 5 的官方能力获得更清晰、更稳定的资源处理体验。

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

Webpack 5 真的有 Customary Rights 习惯权利这个新特性吗?

一、先澄清: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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。