Webpack 5 发布 (2020-10-10)

Webpack 4 于 2018 年 2 月发布。此后,我们发布了许多不包含重大变更的功能。我们知道人们不喜欢带来重大变更的主要版本更新。尤其是对于 webpack 来说,人们通常每年只接触两次,而其余时间它都能“正常工作”。但发布不带重大变更的功能也有代价:我们无法进行重大的 API 或架构改进。

因此,时常会出现困难累积到一定程度的情况,我们不得不进行重大变更,以免搞砸一切。这就是新主版本发布的时候。所以 webpack 5 包含了这些架构改进以及没有这些改进就无法实现的功能。

主版本更新也是一个修订某些默认设置、并与同期出现的提案和规范保持一致的机会。

所以今天(2020-10-10)webpack 5.0.0 发布了,但这并不意味着它已经完成、没有bug或功能完整。与 webpack 4 一样,我们将继续通过修复问题和增加功能来开发。未来几天可能会有很多bug修复。功能将在之后到来。

常见问题

那么发布意味着什么?

这意味着我们已经完成了重大变更。许多重构工作已经完成,以提升架构并为未来的功能(和当前功能)打下良好基础。

那么何时是升级的时机?

这取决于具体情况。升级很可能会失败,你可能需要尝试第二次或第三次。如果你愿意接受这一点,现在就尝试升级,并向 webpack、插件和加载器提供反馈。我们非常乐意修复这些问题。总要有人开始,而你将是首批受益者之一。

赞助更新

Webpack 完全依赖于赞助。它不像其他一些开源项目那样由大公司资助(并支付报酬)。99% 的赞助收入根据贡献者和维护者的贡献分配给他们。我们相信将资金投入到改进 webpack 上。

但现在正值疫情,公司对赞助的意愿也大不如前。Webpack 在这些情况下也受到了影响(就像许多其他公司和个人一样)。

我们从未能够支付给贡献者我们认为他们应得的报酬,但现在我们只有一半的可用资金,所以我们需要做出更严重的削减。在情况改善之前,我们每月只支付贡献者和维护者前10天的工作报酬。剩余的时间他们可以自愿工作,由雇主支付,或者从事其他工作,或者休假。这使我们能够在前10天支付给他们与投入时间更对等的报酬。

最大的“感谢”要献给 trivago,它在过去三年中为 webpack 提供了巨额赞助。不幸的是,由于受到 Covid-19 的严重冲击,他们今年无法继续提供赞助。我希望有其他公司能够挺身而出,追随这些(巨大)的脚步。

感谢所有赞助商

总体方向

本次发布专注于以下几点:

  • 通过持久缓存(Persistent Caching)提升构建性能。
  • 通过更优的算法和默认值改善长期缓存(Long Term Caching)。
  • 通过更好的摇树优化(Tree Shaking)和代码生成(Code Generation)减小打包体积。
  • 提升与 Web 平台的兼容性。
  • 清理在实现 v4 功能时遗留下来的、处于奇怪状态的内部结构,而不引入任何重大变更。
  • 通过现在引入重大变更,为未来的功能做好准备,使我们能够在 v5 上尽可能长时间地保持稳定。

迁移指南

有关迁移指南,请参阅此处

主要变更:移除项

已移除的废弃项

v4 中所有已废弃的项都已移除。

迁移:确保你的 webpack 4 构建不会打印弃用警告。

以下是一些已移除但 v4 中未显示弃用警告的项:

  • IgnorePlugin 和 BannerPlugin 现在必须只传入一个参数,该参数可以是对象、字符串或函数。

废弃代码

新的废弃警告包含废弃代码,以便于引用。

语法废弃

require.include 已被废弃,默认情况下使用时会发出警告。

可以通过 Rule.parser.requireInclude 将行为更改为 allowed(允许)、deprecated(废弃)或 disabled(禁用)。

自动 Node.js Polyfills 已移除

在早期,webpack 的目标是允许在浏览器中运行大多数 Node.js 模块,但模块生态系统发生了变化,许多模块现在主要是为前端目的而编写的。Webpack <= 4 附带了许多 Node.js 核心模块的 polyfill,一旦模块使用了任何核心模块(例如 crypto 模块),这些 polyfill 就会自动应用。

虽然这使得使用为 Node.js 编写的模块变得更容易,但它会将这些巨大的 polyfill 添加到 bundle 中。在许多情况下,这些 polyfill 是不必要的。

Webpack 5 停止自动为这些核心模块提供 polyfill,并专注于前端兼容模块。我们的目标是提高与 Web 平台的兼容性,因为 Web 平台中不提供 Node.js 核心模块。

迁移:

  • 尽可能使用前端兼容模块。
  • 可以手动为 Node.js 核心模块添加 polyfill。错误消息会提示如何实现。
  • 包作者:在 package.json 中使用 browser 字段使包与前端兼容。为浏览器提供替代实现/依赖。

主要变更:长期缓存

确定性块、模块 ID 和导出名称

已添加用于长期缓存的新算法。这些算法在生产模式下默认启用。

chunkIds: "deterministic" moduleIds: "deterministic" mangleExports: "deterministic"

这些算法以确定性方式为模块和块分配短(3 或 5 位数字)ID,并为导出分配短(2 个字符)名称。这是在打包大小和长期缓存之间的一种权衡。

moduleIds/chunkIds/mangleExports: false 会禁用默认行为,可以通过插件提供自定义算法。请注意,在 webpack 4 中,moduleIds/chunkIds: false 如果没有自定义插件,仍然可以正常构建,但在 webpack 5 中,你必须提供自定义插件。

迁移:最好使用 chunkIdsmoduleIdsmangleExports 的默认值。你也可以选择旧的默认值 chunkIds: "size", moduleIds: "size", mangleExports: "size",这将生成更小的 bundle,但会更频繁地使其缓存失效。

注意:在 webpack 4 中,哈希模块 ID 会降低 gzip 性能。这与模块顺序更改有关,现已修复。

注意:在 webpack 5 中,deterministic ID 默认在生产模式下启用。

真实内容哈希

Webpack 5 现在在使用 [contenthash] 时将使用文件内容的真实哈希。之前它“只”使用了内部结构的哈希。当只更改注释或重命名变量时,这可能会对长期缓存产生积极影响。这些更改在最小化后是不可见的。

主要变更:开发支持

命名块 ID

开发模式下默认启用了一种新的命名块 ID 算法,它为块(和文件名)提供人类可读的名称。模块 ID 由其相对于 context 的路径确定。块 ID 由块的内容确定。

因此,你不再需要使用 import(/* webpackChunkName: "name" */ "module") 进行调试。但如果你想控制生产环境的文件名,这样做仍然有意义。

可以在生产环境中使用 chunkIds: "named",但请确保不要意外暴露模块名称的敏感信息。

迁移:如果你不喜欢开发环境中文件名被更改,可以传入 chunkIds: "natural" 来使用旧的数字模式。

模块联邦

Webpack 5 增加了一个名为“模块联邦”的新功能,它允许多个 webpack 构建协同工作。从运行时角度来看,来自多个构建的模块将表现得像一个巨大的连接模块图。从开发人员角度来看,模块可以从指定的远程构建中导入,并以最小的限制使用。

有关更多详细信息,请参阅此单独指南

主要变更:新的 Web 平台特性

JSON 模块

JSON 模块现在与提案保持一致,并在使用非默认导出时发出警告。从严格的 ECMAScript 模块导入时,JSON 模块不再具有命名导出。

迁移:使用默认导出。

即使使用默认导出,未使用的属性也会被 optimization.usedExports 优化删除,属性也会被 optimization.mangleExports 优化重命名。

可以在 Rule.parser.parse 中指定自定义 JSON 解析器来导入类似 JSON 的文件(例如,用于 toml, yaml, json5 等)。

import.meta

  • import.meta.webpackHotmodule.hot 的别名,在严格 ESM 中也可用
  • import.meta.webpack 是 webpack 主版本号
  • import.meta.url 是当前文件的 file: URL(类似于 __filename 但作为文件 URL)

资源模块

Webpack 5 现在原生支持表示资源的模块。这些模块将把文件输出到输出文件夹中,或者将 DataURI 注入到 javascript bundle 中。无论哪种方式,它们都提供一个 URL 供使用。

它们可以通过多种方式使用:

  • import url from "./image.png" 并在 module.rules 中匹配此类导入时设置 type: "asset"。(旧方式)
  • new URL("./image.png", import.meta.url)(新方式)

选择“新方式”语法是为了允许代码在没有打包器的情况下也能运行。这种语法在浏览器中的原生 ECMAScript 模块中也可用。

原生 Worker 支持

当将用于资源的 new URLnew Worker/new SharedWorker/navigator.serviceWorker.register 结合使用时,webpack 将自动为 Web Worker 创建一个新的入口点。

new Worker(new URL("./worker.js", import.meta.url))

选择此语法是为了允许代码在没有打包器的情况下也能运行。这种语法在浏览器中的原生 ECMAScript 模块中也可用。

URI

Webpack 5 支持处理请求中的协议。

  • 支持 data:。支持 Base64 或原始编码。Mimetype 可以在 module.rules 中映射到加载器和模块类型。示例:import x from "data:text/javascript,export default 42"
  • 支持 file:
  • 支持 http(s):,但需要通过 new webpack.experiments.schemesHttp(s)UriPlugin() 手动选择启用。
    • 默认情况下,当目标为 "web" 时,这些 URI 会导致对外部资源的请求(它们是外部的)。

支持请求中的片段:示例:./file.js#fragment

异步模块

Webpack 5 支持所谓的“异步模块”。这些模块不是同步评估,而是异步的、基于 Promise 的。

通过 import 导入它们会自动处理,不需要额外的语法,并且几乎注意不到差异。

通过 require() 导入它们将返回一个解析为导出内容的 Promise。

在 webpack 中有多种方式可以实现异步模块:

  • 异步外部模块 (async externals)
  • 新规范中的 WebAssembly 模块
  • 使用 Top-Level-Await 的 ECMAScript 模块

外部模块

Webpack 5 增加了额外的外部模块类型以覆盖更多应用:

promise:一个解析为 Promise 的表达式。外部模块是一个异步模块,解析值用作模块导出。

import:使用原生 import() 加载指定请求。外部模块是异步模块。

module:尚未实现,但计划通过 import x from "..." 加载模块。

script:通过 <script> 标签加载 URL,并从全局变量(以及可选的其属性)获取导出。外部模块是异步模块。

主要变更:新的 Node.js 生态系统特性

解析

现在支持 package.json 中的 exportsimports 字段。

Yarn PnP 得到原生支持。

更多详细信息请参阅包导出

主要变更:开发体验

改进的 target

Webpack 5 允许传递目标列表,并支持目标版本。

示例:target: "node14" target: ["web", "es2020"]

这使我们能够向 webpack 提供所需的所有信息,以确定:

  • 块加载机制,以及
  • 支持的语法,例如箭头函数

统计信息

Stats 测试格式在可读性和详细程度方面得到了改进。默认值已得到改善,使其更简洁,也适用于大型构建。

  • 块关系现在默认隐藏。可以通过 stats.chunkRelations 进行切换。
  • Stats 现在区分 filesauxiliaryFiles
  • Stats 模块和块 ID 现在默认隐藏。可以通过 stats.ids 进行切换。
  • 所有模块的列表现在按距入口点的距离排序。可以通过 stats.modulesSort 更改。
  • 块模块的列表现在按模块名称排序。可以通过 stats.chunkModulesSort 更改。
  • 串联模块中嵌套模块的列表现在按拓扑排序。可以通过 stats.nestedModulesSort 更改。
  • 块和资源现在显示块 ID 提示。
  • 资源和模块将以树形结构而不是列表/表格显示。
  • 一般信息现在在末尾的摘要中显示。它显示 webpack 版本、配置名称以及警告/错误计数。
  • 哈希值现在默认隐藏。可以通过 stats.hash 更改。
  • 构建时间戳不再默认显示。可以通过 stats.builtAt 启用。它将在摘要中显示时间戳。
  • 子编译现在默认不再显示。它们可以通过 stats.children 显示。

进度

ProgressPlugin 已经进行了一些改进,它被 CLI 用于 --progress,但也可以作为插件手动使用。

它以前只计算已处理的模块。现在它可以计算 entriesdependenciesmodules。所有这些现在都默认显示。

它以前显示当前正在处理的模块。这导致了大量的 stderr 输出,并在某些控制台上产生了性能问题。现在默认禁用此功能(activeModules 选项)。这也减少了控制台上的垃圾信息量。现在构建模块时写入 stderr 的操作被限制为 500ms。

分析模式也得到了升级,将显示嵌套进度消息的时间。这使得更容易找出哪个插件导致性能问题。

新增的 percentBy 选项告诉 ProgressPlugin 如何计算进度百分比。

new webpack.ProgressPlugin({ percentBy: 'entries' });

为了使进度百分比更准确,ProgressPlugin 缓存了最后已知的模块总数,并在下一次构建时重用此值。第一次构建将预热缓存,但随后的构建将使用并更新此值。

自动唯一命名

在 webpack 4 中,多个 webpack 运行时可能会在同一个 HTML 页面上发生冲突,因为它们使用相同的全局变量进行块加载。为了解决这个问题,需要为 output.jsonpFunction 配置提供一个自定义名称。

Webpack 5 会自动从 package.jsonname 推断出构建的唯一名称,并将其用作 output.uniqueName 的默认值。

此值用于使所有潜在冲突的全局变量保持唯一。

迁移:删除 output.jsonpFunction,转而在你的 package.json 中使用唯一名称。

自动公共路径

Webpack 5 将尽可能自动确定 output.publicPath

TypeScript 类型定义

Webpack 5 从源代码生成 TypeScript 类型定义并通过 npm 包暴露它们。

迁移:移除 @types/webpack。当名称不同时,更新引用。

主要变更:优化

嵌套摇树优化

Webpack 现在能够跟踪对导出嵌套属性的访问。当重新导出命名空间对象时,这可以改进摇树优化(未使用的导出消除和导出重命名)。

// inner.js
export const a = 1;
export const b = 2;

// module.js
export * as inner from './inner';
// or import * as inner from './inner'; export { inner };

// user.js
import * as module from './module';
console.log(module.inner.a);

在此示例中,导出 b 可以在生产模式下被移除。

模块内部摇树优化

Webpack 4 不会分析模块的导出和导入之间的依赖关系。Webpack 5 有一个新的选项 optimization.innerGraph,它在生产模式下默认启用,对模块中的符号运行分析,以找出从导出到导入的依赖关系。

在这样的模块中

import { something } from './something';

function usingSomething() {
  return something;
}

export function test() {
  return usingSomething();
}

内部图算法将识别出 something 仅在 test 导出被使用时才被使用。这允许标记更多导出为未使用,并从 bundle 中省略更多代码。

当设置 "sideEffects": false 时,这允许省略更多的模块。在此示例中,当 test 导出未使用时,./something 将被省略。

为了获取未使用导出的信息,需要 optimization.usedExports。为了移除无副作用的模块,需要 optimization.sideEffects

以下符号可以被分析:

  • 函数声明
  • 类声明
  • export default 或变量声明与
    • 函数表达式
    • 类表达式
    • 序列表达式
    • /*#__PURE__*/ 表达式
    • 局部变量
    • 导入的绑定

反馈:如果您发现此分析中缺少任何内容,请报告问题,我们将考虑添加。

使用 eval() 将会导致此模块的优化中止,因为 evaled 代码可以引用作用域中的任何符号。

这种优化也称为深度作用域分析(Deep Scope Analysis)。

CommonJS 摇树优化

Webpack 以前会选择退出 CommonJS 导出和 require() 调用的已使用导出分析。

Webpack 5 增加了对某些 CommonJS 构造的支持,允许消除未使用的 CommonJS 导出,并跟踪 require() 调用中引用的导出名称。

支持以下结构:

  • exports|this|module.exports.xxx = ...
  • exports|this|module.exports = require("...") (重新导出)
  • exports|this|module.exports.xxx = require("...").xxx (重新导出)
  • Object.defineProperty(exports|this|module.exports, "xxx", ...)
  • require("abc").xxx
  • require("abc").xxx()
  • 从 ESM 导入
  • require() 一个 ESM
  • flagged exportType(非严格 ESM 导入的特殊处理)
    • Object.defineProperty(exports|this|module.exports, "__esModule", { value: true|!0 })
    • exports|this|module.exports.__esModule = true|!0
  • 未来计划支持更多结构。

当检测到不可分析的代码时,webpack 会退出,并且根本不会跟踪这些模块的导出信息(出于性能原因)。

副作用分析

package.json 中的 "sideEffects" 标志允许手动将模块标记为无副作用,这允许在未使用时丢弃它们。

Webpack 5 还可以根据源代码的静态分析自动将模块标记为无副作用。

按运行时优化

Webpack 5 现在能够(并且默认如此)按运行时分析和优化模块(运行时通常等于一个入口点)。这允许只在真正需要它们的入口点中导出。入口点之间互不影响(只要每个入口点使用一个运行时)。

模块串联

模块串联也按运行时工作,允许每个运行时有不同的串联。

模块串联已成为一流公民,现在任何模块和依赖项都可以实现它。最初 webpack 5 已经添加了对 ExternalModules 和 json 模块的支持,更多功能可能很快就会发布。

通用摇树优化改进

export * 已得到改进,可以跟踪更多信息,并且不再将 default 导出标记为已使用。

当 webpack 确定存在冲突的导出时,export * 现在将显示警告。

import() 允许通过 /* webpackExports: ["abc", "default"] */ 魔术注释手动摇树优化模块。

开发与生产环境相似性

我们努力在开发模式下的构建性能与通过提高两种模式之间的相似性来避免仅生产环境问题之间找到一个良好的平衡点。

Webpack 5 默认在两种模式下都启用 sideEffects 优化。在 webpack 4 中,由于 package.json 中 "sideEffects" 标志不正确,此优化导致了一些仅在生产环境下的错误。在开发环境中启用此优化可以更快、更轻松地发现这些问题。

在许多情况下,开发和生产发生在不同操作系统上,文件系统的大小写敏感性也不同,因此 webpack 5 在存在奇怪的大小写问题时会添加更多警告/错误。

改进的代码生成

Webpack 会检测何时发生 ASI,并在不插入分号时生成更短的代码。Object(...) -> (0, ...)

Webpack 将多个导出 getter 合并为单个运行时函数调用:r.d(x, "a", () => a); r.d(x, "b", () => b); -> r.d(x, {a: () => a, b: () => b});

现在 output.environment 中有更多选项。它们允许指定 webpack 生成的运行时代码可以使用哪些 ECMAScript 功能。

通常不需要直接指定此选项,而是使用 target 选项。

Webpack 4 以前只输出 ES5 代码。Webpack 5 现在可以同时生成 ES5 和 ES6/ES2015 代码。

仅支持现代浏览器将生成更短的代码,使用箭头函数和更符合规范的代码,并使用带有 TDZ 的 const 声明来处理 export default

改进的 target 选项

在 webpack 4 中,target 是在 "web""node"(以及其他一些)之间粗略的选择。Webpack 5 在这里提供了更多选项。

target 选项现在比以前对生成的代码有更多的影响:

  • 块加载方式
  • 块格式
  • WASM 加载方式
  • worker 中块和 WASM 的加载方式
  • 使用的全局对象
  • 是否应自动确定 publicPath
  • 生成代码中使用的 ECMAScript 功能/语法
  • 默认启用 externals
  • 某些 Node.js 兼容层的行为(global, __filename, __dirname
  • 模块解析(browser 字段,exportsimports 条件)
  • 一些加载器可能会因此改变行为

对于其中一些情况,在 "web""node" 之间选择太粗略了,我们需要更多信息。因此,我们允许指定最低版本,例如 "node10.13",并推断有关目标环境的更多属性。

现在也允许使用数组组合多个 target,webpack 将确定所有 target 的最小属性。当使用没有提供完整信息的目标(例如 "web""node"(不带版本号))时,使用数组也很有用。例如,["web", "es2020"] 结合了这两个部分目标。

有一个 "browserslist" 目标,它将使用 browserslist 数据来确定环境属性。当项目中存在 browserslist 配置时,此目标也默认使用。如果没有此类配置,则默认使用 "web" 目标。

某些组合和功能尚未实现,并将导致错误。它们是为未来功能做准备。示例:

  • ["web", "node"] 将导致通用块加载方法,这尚未实现。
  • ["web", "node"] + output.module: true 将导致模块块加载方法,这尚未实现。
  • "web" 将导致 http(s): 导入被视为 module 外部模块,这尚未实现(解决方法:externalsPresets: { web: false, webAsync: true },它将改为使用 import())。

SplitChunks 和模块大小

模块现在以比单一数字更好的方式表达大小。现在有不同类型的大小。

SplitChunksPlugin 现在知道如何处理这些不同的大小,并将其用于 minSizemaxSize。默认情况下,只处理 javascript 大小,但你现在可以传递多个值来管理它们。

module.exports = {
  optimization: {
    splitChunks: {
      minSize: {
        javascript: 30000,
        webassembly: 50000,
      },
    },
  },
};

你仍然可以使用单个数字来表示大小。在这种情况下,webpack 将自动使用默认的大小类型。

mini-css-extract-plugin 使用 css/mini-extra 作为大小类型,并自动将此大小类型添加到默认类型中。

主要变更:性能

持久缓存

现在有一个文件系统缓存。它是可选的,可以通过以下配置启用:

module.exports = {
  cache: {
    // 1. Set cache type to filesystem
    type: 'filesystem',

    buildDependencies: {
      // 2. Add your config as buildDependency to get cache invalidation on config change
      config: [__filename],

      // 3. If you have other things the build depends on you can add them here
      // Note that webpack, loaders and all modules referenced from your config are automatically added
    },
  },
};

重要注意事项:

默认情况下,webpack 假定它所在的 node_modules 目录由包管理器修改。出于性能原因,node_modules 的哈希和时间戳会被跳过。相反,只使用包名和版本。符号链接(即 npm/yarn link)只要未指定 resolve.symlinks: false 就没有问题(无论如何也应避免)。不要直接编辑 node_modules 中的文件,除非你通过 snapshot.managedPaths: [] 选择退出此优化。使用 Yarn PnP 时,webpack 假定 yarn 缓存是不可变的(通常是)。你可以通过 snapshot.immutablePaths: [] 选择退出此优化。

默认情况下,缓存将存储在 node_modules/.cache/webpack(使用 node_modules 时)或 .yarn/.cache/webpack(使用 Yarn PnP 时)。当所有插件都正确处理缓存时,你可能永远不需要手动删除它。

许多内部插件也将使用持久缓存。示例:SourceMapDevToolPlugin(用于缓存 SourceMap 生成)或 ProgressPlugin(用于缓存模块数量)。

持久缓存将根据使用情况自动创建多个缓存文件,以优化对缓存的读写访问。

默认情况下,在开发模式下使用时间戳进行快照,在生产模式下使用文件哈希。文件哈希允许在 CI 上也使用持久缓存。

编译器空闲和关闭

现在编译器在使用后需要关闭。编译器现在进入和离开空闲状态,并为这些状态设置了钩子。插件可以使用这些钩子来执行不重要的工作(例如,持久缓存缓慢地将缓存存储到磁盘)。在编译器关闭时,所有剩余的工作应尽快完成。回调函数会发出关闭完成的信号。

插件及其各自的作者应该预料到有些用户可能会忘记关闭编译器。因此,所有工作最终也应该在空闲时完成。当工作正在进行时,应防止进程退出。

当传递回调函数时,webpack() 门面会自动调用 close

迁移:在使用 Node.js API 时,请确保在完成后调用 Compiler.close

文件输出

Webpack 以前总是在第一次构建时输出所有输出文件,但在增量(watch)构建期间跳过写入未更改的文件。它假设在 webpack 运行时,没有其他东西会更改输出文件。

随着持久缓存的加入,即使重新启动 webpack 进程,也应该提供类似于 watch 的体验,但是认为即使 webpack 未运行时输出目录也不会被其他东西更改,这是一个过于强烈的假设。

因此,webpack 现在将检查输出目录中的现有文件,并将其内容与内存中的输出文件进行比较。只有当文件发生更改时,才会写入文件。这仅在第一次构建时完成。任何增量构建都会在运行中的 webpack 进程中生成新资产时始终写入文件。

我们假设 webpack 和插件只在内容更改时生成新资产。应使用缓存来确保在输入相同时不生成新资产。不遵循此建议将降低性能。

被标记为 [immutable](包含内容哈希)的文件,如果同名文件已存在,则绝不会被写入。我们假设当文件内容更改时,内容哈希也会更改。这通常是正确的,但在 webpack 或插件开发期间可能并非总是如此。

主要变更:长期存在的问题

单文件目标的代码分割

只允许启动单个文件的目标(如 node、WebWorker、electron main)现在支持运行时自动加载引导所需的相关部分。

这允许在这些目标中使用 opimization.splitChunks 并设置 chunks: "all",以及 optimization.runtimeChunk

请注意,对于块加载是异步的目标,这也使得初始评估变为异步。这在使用 output.library 时可能会出现问题,因为导出的值现在是一个 Promise。

更新的解析器

enhanced-resolve 已更新至 v5。这带来了以下改进:

  • 解析器跟踪更多依赖项,例如缺失文件
  • 别名可能具有多种替代方案
  • 现在可以将别名设置为 false
  • 支持 exportsimports 字段等功能
  • 性能提升

无 JS 的块

不包含 JS 代码的块将不再生成 JS 文件。这允许创建只包含 CSS 的块。

主要变更:未来

实验性功能

并非所有功能从一开始就稳定。在 webpack 4 中,我们添加了实验性功能并在更新日志中注明它们是实验性的,但从配置中并不总是清楚这些功能是实验性的。

在 webpack 5 中,有一个新的 experiments 配置选项,允许启用实验性功能。这使得哪些功能已启用/使用变得清晰。

虽然 webpack 遵循语义版本控制,但它将为实验性功能破例。实验性功能在 webpack 的次要版本中可能包含重大变更。如果发生这种情况,我们将在更新日志中添加明确的说明。这将使我们能够更快地迭代实验性功能,同时也能让我们在稳定功能上保持更长时间的主版本。

以下实验性功能将随 webpack 5 一同发布:

  • 与 webpack 4 相同的旧 WebAssembly 支持(experiments.syncWebAssembly
  • 根据更新后的规范新的 WebAssembly 支持(experiments.asyncWebAssembly
    • 这将使 WebAssembly 模块成为一个异步模块。
  • Top Level Await Stage 3 提案(experiments.topLevelAwait
    • 在顶层使用 await 会使模块成为一个异步模块。
  • 将 bundle 作为模块输出(experiments.outputModule
    • 这从 bundle 中移除了包装 IIFE,强制严格模式,通过 <script type="module"> 惰性加载,并在模块模式下最小化。

请注意,这也意味着 WebAssembly 支持现在默认禁用。

最低 Node.js 版本

支持的最低 Node.js 版本已从 6 提高到 10.13.0 (LTS)。

迁移:升级到可用的最新 Node.js 版本。

配置变更

结构变更

  • entry: {} 现在允许空对象(以便允许插件添加入口)
  • target 支持数组、版本和 browserslist
  • cache: Object 已移除:不再可能设置为内存缓存对象。
  • cache.type 已添加:现在可以选择 "memory""filesystem"
  • 新增了 cache.type = "filesystem" 的配置选项:
    • cache.cacheDirectory
    • cache.name
    • cache.version
    • cache.store
    • cache.hashAlgorithm
    • cache.idleTimeout
    • cache.idleTimeoutForInitialStore
    • cache.buildDependencies
  • snapshot.resolveBuildDependencies 已添加
  • snapshot.resolve 已添加
  • snapshot.module 已添加
  • snapshot.managedPaths 已添加
  • snapshot.immutablePaths 已添加
  • resolve.cache 已添加:允许禁用/启用安全解析缓存。
  • resolve.concord 已移除
  • resolve.moduleExtensions 已移除
  • resolve.alias 值现在可以是数组或 false
  • resolve.restrictions 已添加:允许限制潜在的解析结果。
  • resolve.fallback 已添加:允许为解析失败的请求创建别名。
  • resolve.preferRelative 已添加:允许将模块请求解析为相对请求。
  • 自动的 Node.js 原生模块 polyfills 已被移除。
    • node.Buffer 已移除
    • node.console 已移除
    • node.process 已移除
    • node.* (Node.js 原生模块) 已移除
    • 迁移resolve.aliasProvidePlugin。错误会提供提示。(参考 node-libs-browser 以获取 v4 中使用的 polyfills 和模拟)
  • output.filename 现在可以是函数。
  • output.assetModuleFilename 已添加
  • output.jsonpScriptType 已重命名为 output.scriptType
  • devtool 更严格了
    • 格式:false | eval | [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
  • optimization.chunkIds: "deterministic" 已添加
  • optimization.moduleIds: "deterministic" 已添加
  • optimization.moduleIds: "hashed" 已废弃
  • optimization.moduleIds: "total-size" 已移除
  • 模块和块 ID 的废弃标志已移除。
    • optimization.hashedModuleIds 已移除
    • optimization.namedChunks 已移除(NamedChunksPlugin 也已移除)
    • optimization.namedModules 已移除(NamedModulesPlugin 也已移除)
    • optimization.occurrenceOrder 已移除
    • 迁移:使用 chunkIdsmoduleIds
  • optimization.splitChunkstest 不再匹配块名称。
    • 迁移:使用测试函数 (module, { chunkGraph }) => chunkGraph.getModuleChunks(module).some(chunk => chunk.name === "name")
  • optimization.splitChunks minRemainingSize 已添加
  • optimization.splitChunks filename 现在可以是函数。
  • optimization.splitChunkssizes 现在可以是包含每个源类型大小的对象。
    • minSize
    • minRemainingSize
    • maxSize
    • maxAsyncSize
    • maxInitialSize
  • optimization.splitChunksmaxAsyncSizemaxInitialSize 已添加到 maxSize 旁边:允许为初始和异步块指定不同的最大大小。
  • optimization.splitChunks name: true 已移除:不再支持自动命名。
    • 迁移:使用默认值。chunkIds: "named" 将为你的文件提供有用的调试名称。
  • optimization.splitChunks.cacheGroups[].idHint 已添加:提供了如何选择命名块 ID 的提示。
  • optimization.splitChunks automaticNamePrefix 已移除
    • 迁移:请改用 idHint
  • optimization.splitChunksfilename 不再仅限于初始块。
  • optimization.splitChunks usedExports 已添加,用于在比较模块时包含已使用的导出。
  • optimization.splitChunks.defaultSizeTypes 已添加:在使用数字表示大小时指定大小类型。
  • optimization.mangleExports 已添加
  • optimization.minimizer 可以使用 "..." 来引用默认值。
  • optimization.usedExports 增加了 "global" 值,允许禁用按运行时分析,而是全局进行(性能更好)。
  • optimization.noEmitOnErrors 重命名为 optimization.emitOnErrors,逻辑反转。
  • optimization.realContentHash 已添加
  • output.devtoolLineToLine 已移除
    • 迁移:无替代方案
  • output.chunkFilename: Function 现在允许使用。
  • output.hotUpdateChunkFilename: Function 现在被禁止:它以前从未起作用。
  • output.hotUpdateMainFilename: Function 现在被禁止:它以前从未起作用。
  • output.importFunctionName: string 指定了用于替换 import() 的名称,以允许对不支持的环境进行 polyfilling。
  • output.charset 已添加:将其设置为 false 将省略脚本标签上的 charset 属性。
  • output.hotUpdateFunction 重命名为 output.hotUpdateGlobal
  • output.jsonpFunction 重命名为 output.chunkLoadingGlobal
  • output.chunkCallbackFunction 重命名为 output.chunkLoadingGlobal
  • output.chunkLoading 已添加
  • output.enabledChunkLoadingTypes 已添加
  • output.chunkFormat 已添加
  • module.rulesresolveparser 将以不同方式合并(对象会进行深度合并,数组可能包含 "..." 来引用前一个值)
  • module.rules parser.worker 已添加:允许配置支持的 worker。
  • module.rulesqueryloaders 已移除。
  • module.rulesoptions 传入字符串已被废弃。
    • 迁移:传入一个 options 对象,如果加载器不支持,请向加载器提交问题。
  • module.rules mimetype 已添加:允许匹配 DataURI 的 mimetype。
  • module.rules descriptionData 已添加:允许匹配 package.json 中的数据。
  • module.defaultRules 可以使用 "..." 来引用默认值。
  • stats.chunkRootModules 已添加:显示块的根模块。
  • stats.orphanModules 已添加:显示未输出的模块。
  • stats.runtime 已添加:显示运行时模块。
  • stats.chunkRelations 已添加:显示父/子/兄弟块。
  • stats.errorStack 已添加:显示 webpack 内部的错误堆栈跟踪。
  • stats.preset 已添加:选择预设。
  • stats.relatedAssets 已添加:显示与其他资源相关的资源(例如 SourceMaps)。
  • stats.warningsFilter 已废弃,转而使用 ignoreWarnings
  • BannerPlugin.banner 签名已更改。
    • data.basename 已移除
    • data.query 已移除
    • 迁移:从 filename 中提取。
  • SourceMapDevToolPlugin lineToLine 已移除
    • 迁移:无替代方案
  • [hash] 作为整个编译的哈希值现已废弃。
    • 迁移:请改用 [fullhash],或者更好地使用其他哈希选项。
  • [modulehash] 已废弃。
    • 迁移:请改用 [hash]
  • [moduleid] 已废弃。
    • 迁移:请改用 [id]
  • [filebase] 已移除。
    • 迁移:请改用 [base]
  • 基于文件模板(即 SourceMapDevToolPlugin)的新占位符:
    • [name]
    • [base]
    • [path]
    • [ext]
  • externals 在传入函数时,现在具有不同的签名 ({ context, request }, callback)
    • 迁移:更改签名。
  • externalsPresets 已添加
  • experiments 已添加(参见上面的实验性功能部分)
  • watchOptions.followSymlinks 已添加
  • watchOptions.ignored 现在可以是正则表达式。
  • webpack.util.serialization 现已暴露。

默认值变更

  • 当 browserslist 配置可用时,target 现在默认是 "browserslist"
  • module.unsafeCache 现在默认只在 node_modules 中启用。
  • optimization.moduleIds 在生产模式下默认为 deterministic,而不是 size
  • optimization.chunkIds 在生产模式下默认为 deterministic,而不是 total-size
  • optimization.nodeEnvnone 模式下默认为 false
  • optimization.splitChunks.minSize 在生产环境下默认为 20k
  • optimization.splitChunks.enforceSizeThreshold 在生产环境下默认为 50k
  • optimization.splitChunks minRemainingSize 默认为 minSize
    • 这将导致在剩余部分过小的情况下,生成的分割块更少。
  • optimization.splitChunks maxAsyncRequestsmaxInitialRequests 的默认值已增加到 30。
  • optimization.splitChunks.cacheGroups.vendors 已重命名为 optimization.splitChunks.cacheGroups.defaultVendors
  • optimization.splitChunks.cacheGroups.defaultVendors.reuseExistingChunk 现在默认为 true
  • optimization.minimizer 的默认目标现在在 terser 选项中使用了 compress.passes: 2
  • 当使用 cache 时,resolve(Loader).cache 默认为 true
  • resolve(Loader).cacheWithContext 默认为 false
  • resolveLoader.extensions 移除了 .json
  • 在 node target 中,node.globalnode.__filenamenode.__dirname 默认为 false
  • stats.errorStack 默认为 false

加载器相关变更

this.getOptions

这个新的 API 应该能简化加载器中选项的使用。它允许传递 JSON Schema 进行验证。详情请参阅 PR

this.exec

这已从加载器上下文中移除。

迁移:这可以在加载器本身中实现。

this.getResolve

加载器 API 中的 getResolve(options) 将以不同的方式合并选项,请参阅 module.rulesresolve

由于 webpack 5 在不同依赖项发出方面有所不同,因此传入 dependencyType 作为选项(例如 "esm""commonjs" 或其他)可能是有意义的。

主要内部变更

以下更改仅与插件作者相关:

新插件顺序

Webpack 5 中的插件现在在配置默认值应用之前应用。这允许插件应用自己的默认值,或充当配置预设。

但这同时也是一个重大变更,因为插件在应用时不能再依赖已设置的配置值。

迁移:仅在插件钩子中访问配置。或者最好完全避免访问配置,并通过构造函数获取选项。

运行时模块

大部分运行时代码已被移至所谓的“运行时模块”中。这些特殊模块负责添加运行时代码。它们可以被添加到任何块中,但目前总是添加到运行时块中。“运行时需求”控制哪些运行时模块(或核心运行时部分)被添加到 bundle 中。这确保只有使用的运行时代码才被添加到 bundle 中。将来,运行时模块也可以按需加载的块中,以便在需要时加载运行时代码。

在大多数情况下,核心运行时允许内联入口模块,而不是使用 __webpack_require__ 调用它。如果 bundle 中没有其他模块,则根本不需要 __webpack_require__。这与模块串联结合得很好,模块串联将多个模块串联成一个模块。

在最佳情况下,根本不需要运行时代码。

迁移:如果你在插件中将运行时代码注入 webpack 运行时,请考虑使用运行时模块。

序列化

已添加序列化机制,以允许 webpack 中复杂对象的序列化。它具有可选语义,因此需要显式标记应序列化的类(并实现其序列化)。这已针对大多数模块、所有依赖项和某些错误完成。

迁移:当使用自定义模块或依赖项时,建议使其可序列化以受益于持久缓存。

缓存插件

已添加一个带有插件接口的 Cache 类。这个类可以用于写入和读取缓存。根据配置,不同的插件可以为缓存添加功能。MemoryCachePlugin 添加内存缓存。FileCachePlugin 添加持久(文件系统)缓存。

FileCachePlugin 使用序列化机制将缓存项持久化到磁盘并从中恢复。

钩子对象被冻结

带有 hooks 的类的 hooks 对象已被冻结,因此无法再通过这种方式添加自定义钩子。

迁移:添加自定义钩子的推荐方法是使用 WeakMap 和静态的 getXXXHooks(XXX) 方法(例如 getCompilationHook(compilation))。内部类使用与自定义钩子相同的机制。

Tapable 升级

webpack 3 插件的兼容层已移除。它在 webpack 4 中就已经被废弃了。

一些不常用的 Tapable API 已被移除或废弃。

迁移:使用新的 Tapable API。

分阶段钩子

在封装过程的几个步骤中,曾有针对不同阶段的多个钩子。例如 optimizeDependenciesBasicoptimizeDependenciesoptimizeDependenciesAdvanced。这些已被移除,取而代之的是一个可带 stage 选项的单一钩子。有关可能的阶段值,请参阅 OptimizationStages

迁移:请改为连接到剩余的钩子。你可以添加一个 stage 选项。

Main/Chunk/ModuleTemplate 废弃

Bundle 模板化已被重构。MainTemplate/ChunkTemplate/ModuleTemplate 已被废弃,现在由 JavascriptModulesPlugin 负责 JS 模板化。

在此重构之前,JS 输出由 Main/ChunkTemplate 处理,而其他输出(即 WASM、CSS)由插件处理。这看起来像 JS 是一等公民,而其他输出是二等公民。重构改变了这一点,所有输出都由其插件处理。

仍然可以钩入模板化的某些部分。这些钩子现在位于 JavascriptModulesPlugin 中,而不是 Main/ChunkTemplate 中。(是的,插件也可以有钩子。我称它们为附加钩子。)

存在一个兼容层,因此 Main/Chunk/ModuleTemplate 仍然存在,但只将 tap 调用委托给新的钩子位置。

迁移:遵循废弃消息中的建议。主要指向不同位置的钩子。

入口点描述符

如果传入一个对象作为入口点,其值可以是字符串、字符串数组或描述符。

module.exports = {
  entry: {
    catalog: {
      import: './catalog.js',
    },
  },
};

描述符语法可用于向入口点传递额外选项。

入口点输出文件名

默认情况下,入口块的输出文件名是从 output.filename 中提取的,但你可以为特定入口指定自定义输出文件名。

module.exports = {
  entry: {
    about: { import: './about.js', filename: 'pages/[name][ext]' },
  },
};

入口点依赖

默认情况下,每个入口块都存储它使用的所有模块。通过 dependOn 选项,你可以将一个入口块的模块共享给另一个入口块。

module.exports = {
  entry: {
    app: { import: './app.js', dependOn: 'react-vendors' },
    'react-vendors': ['react', 'react-dom', 'prop-types'],
  },
};

app 块将不包含 react-vendors 中的模块。

入口点库

入口描述符允许为每个入口点传递不同的 library 选项。

module.exports = {
  entry: {
    commonjs: {
      import: './lib.js',
      library: {
        type: 'commonjs-module',
      },
    },
    amd: {
      import: './lib.js',
      library: {
        type: 'amd',
      },
    },
  },
};

入口点运行时

入口描述符允许为每个入口指定一个 runtime。当指定时,将创建一个以此名称命名的块,其中只包含该入口的运行时代码。当多个入口指定相同的 runtime 时,该块将包含所有这些入口的通用运行时。这意味着它们可以在同一个 HTML 页面上一起使用。

module.exports = {
  entry: {
    app: {
      import: './app.js',
      runtime: 'app-runtime',
    },
  },
};

入口点分块加载

入口描述符允许为每个入口指定一个 chunkLoading。此入口的运行时将使用它来加载分块。

module.exports = {
  entry: {
    app: {
      import: './app.js',
    },
    worker: {
      import: './worker.js',
      chunkLoading: 'importScripts',
    },
  },
};

顺序和 ID

Webpack 以前在编译阶段以特定方式对模块和分块进行排序,以增量方式分配 ID。现在不再是这样了。顺序将不再用于 ID 生成,ID 生成的完全控制权在插件中。

用于优化模块和分块顺序的 Hooks 已被移除。

迁移:您不能再依赖编译阶段模块和分块的顺序。

数组到集合

  • Compilation.modules 现在是一个 Set(集合)
  • Compilation.chunks 现在是一个 Set(集合)
  • Chunk.files 现在是一个 Set(集合)

有一个兼容层会打印弃用警告。

迁移:使用 Set 方法代替 Array 方法。

Compilation.fileSystemInfo

这个新类可以用于以缓存方式访问文件系统信息。目前,它允许查询文件和目录的时间戳。如果可能,时间戳信息从观察器(watcher)传输,否则通过文件系统访问确定。

未来,将添加查询文件内容哈希的功能,模块将能够通过文件内容而不是文件哈希来检查有效性。

迁移:请使用 compilation.fileSystemInfo API 代替 file/contextTimestamps

现在可以为目录打时间戳,这允许 ContextModules 的序列化。

已添加 Compiler.modifiedFiles(在 Compiler.removedFiles 旁边),以便更容易引用已更改的文件。

文件系统

除了 compiler.inputFileSystemcompiler.outputFileSystem 之外,还有一个新的 compiler.intermediateFileSystem 用于所有不被视为输入或输出的文件系统操作,例如写入记录、缓存或性能分析输出。

文件系统现在具有 fs 接口,并且不再需要 joinmkdirp 等额外方法。但是,如果它们具有 joindirname 等方法,则会使用这些方法。

热模块替换

HMR 运行时已重构为运行时模块(Runtime Modules)。HotUpdateChunkTemplate 已合并到 ChunkTemplate 中。ChunkTemplates 和插件现在也应该处理 HotUpdateChunk

HMR 运行时的 JavaScript 部分已与核心 HMR 运行时分离。其他模块类型现在也可以以自己的方式处理 HMR。未来,这将允许例如 mini-css-extract-plugin 或 WASM 模块的 HMR。

迁移:由于这是新引入的功能,因此无需迁移。

import.meta.webpackHot 暴露了与 module.hot 相同的 API。这也可以用于严格的 ESM 模块(.mjs,package.json 中的 type: "module"),这些模块无法访问 module

工作队列

Webpack 以前通过函数调用函数以及限制并行性的 semaphore 来处理模块。Compilation.semaphore 已被移除,异步队列现在处理工作排队和处理。每个步骤都有一个单独的队列

  • Compilation.factorizeQueue:为一组依赖调用模块工厂。
  • Compilation.addModuleQueue:将模块添加到编译队列(可能会从缓存中恢复模块)。
  • Compilation.buildQueue:如有必要,构建模块(可能会将模块存储到缓存)。
  • Compilation.rebuildQueue:如果手动触发,再次构建模块。
  • Compilation.processDependenciesQueue:处理模块的依赖。

这些队列有一些钩子(hooks)来监视和拦截任务处理。

将来,多个编译器可能会协同工作,通过拦截这些队列可以进行任务编排。

迁移:由于这是新引入的功能,因此无需迁移。

日志记录

Webpack 内部现在包含一些日志记录。stats.logginginfrastructureLogging 选项可用于启用这些消息。

模块和分块图

Webpack 以前将解析后的模块存储在依赖中,并将包含的模块存储在分块中。现在不再是这样了。关于模块如何在模块图中连接的所有信息现在都存储在 ModuleGraph 类中。关于模块如何与分块连接的所有信息现在都存储在 ChunkGraph 类中。依赖于分块图的信息也存储在相关类中。

这意味着关于模块的以下信息已移动

  • 模块连接 -> ModuleGraph
  • 模块发出者 -> ModuleGraph
  • 模块优化退出 -> ModuleGraph (TODO: 检查是否应该是 ChunkGraph)
  • 模块 usedExports -> ModuleGraph
  • 模块 providedExports -> ModuleGraph
  • 模块预排序索引 -> ModuleGraph
  • 模块后排序索引 -> ModuleGraph
  • 模块深度 -> ModuleGraph
  • 模块配置文件 -> ModuleGraph
  • 模块 ID -> ChunkGraph
  • 模块哈希 -> ChunkGraph
  • 模块运行时要求 -> ChunkGraph
  • 模块在分块中 -> ChunkGraph
  • 模块是分块中的入口 -> ChunkGraph
  • 模块是分块中的运行时模块 -> ChunkGraph
  • 分块运行时要求 -> ChunkGraph

Webpack 以前在从缓存恢复时将模块从图中分离。现在不再需要这样做。模块不存储关于图的信息,并且技术上可以在多个图中使用。这使得缓存更容易。

这些更改中的大部分都有一个兼容层,在使用时会打印弃用警告。

迁移:使用 ModuleGraph 和 ChunkGraph 上的新 API

初始化片段

已移除 DependenciesBlockVariables,转而使用 InitFragments。DependencyTemplates 现在可以添加 InitFragments 以将代码注入到模块源代码的顶部。InitFragments 允许去重。

迁移:使用 InitFragments 代替在源代码中负索引处插入内容。

模块源类型

模块现在必须通过 Module.getSourceTypes() 定义它们支持的源类型。根据这些类型,不同的插件会使用这些类型调用 source()。例如,对于源类型 javascriptJavascriptModulesPlugin 将源代码嵌入到 bundle 中。源类型 webassembly 将使 WebAssemblyModulesPlugin 发出 wasm 文件。还支持自定义源类型,例如 mini-css-extract-plugin 可能会使用源类型 stylesheet 将源代码嵌入到 css 文件中。

模块类型和源类型之间没有关系。例如,模块类型 json 也使用源类型 javascript,模块类型 webassembly/experimental 使用源类型 javascriptwebassembly

迁移:自定义模块需要实现这些新的接口方法。

Stats 的插件

Stats 的 presetdefaultjsontoString 现在通过插件系统内置。已将当前的 Stats 转换为插件。

迁移:现在您可以自定义 Stats 功能,而不是替换它。额外的信息现在可以添加到 stats json 中,而不是写入单独的文件。

新的观察机制

webpack 使用的观察器(watcher)已重构。以前它使用 chokidar 和原生依赖 fsevents(仅在 macOS 上)。现在它只基于原生 Node.js fs。这意味着 webpack 中不再有原生依赖。

它还在观察时捕获更多关于文件系统的信息。它现在捕获修改时间(mtimes)和观察事件时间,以及有关缺失文件的信息。为此,WatchFileSystem API 略有改变。同时,我们还将数组转换为集合(Sets),对象转换为映射(Maps)。

emit 后 SizeOnlySource

Webpack 现在将 Compilation.assets 中的 Sources 替换为 SizeOnlySource 变体,以减少内存使用。

多次发出(emitting)资源

警告 Multiple assets emit different content to the same filename 已变为错误。

ExportsInfo

模块导出信息的存储方式已重构。ModuleGraph 现在为每个 Module 提供一个 ExportsInfo,其中存储了每个导出的信息。它还存储了有关未知导出以及模块是否仅以副作用方式使用的信息。

每个导出存储以下信息

  • 导出是否被使用?是、否、非静态已知、未确定。(另请参阅 optimization.usedExports
  • 导出是否已提供?是、否、非静态已知、未确定。(另请参阅 optimization.providedExports
  • 导出名称可以重命名吗?是、否、未确定。
  • 如果导出已重命名,则为新名称。(另请参阅 optimization.mangleExports
  • 嵌套的 ExportsInfo,如果导出本身是一个附带信息的对象
    • 用于重新导出命名空间对象:import * as X from "..."; export { X };
    • 用于表示 JSON 模块中的结构

代码生成阶段

Compilation 现在将代码生成作为独立的编译阶段。它不再隐藏在 Module.source()Module.getRuntimeRequirements() 中运行。

这应该使流程更清晰。它还允许报告此阶段的进度,并在性能分析时使代码生成更可见。

迁移Module.source()Module.getRuntimeRequirements() 现在已弃用。请改用 Module.codeGeneration()

DependencyReference

Webpack 以前只有一个方法和类型来表示依赖项的引用(Compilation.getDependencyReference 返回一个 DependencyReference)。这种类型曾经包含有关此引用的所有信息,例如引用的模块、导入了哪些导出、是否是弱引用以及一些与排序相关的信息。

将所有这些信息捆绑在一起会使获取引用变得昂贵,而且它也经常被调用(每次有人需要一条信息时)。

在 webpack 5 中,这部分代码库进行了重构,并且该方法已被拆分。

  • 被引用的模块可以从 ModuleGraphConnection 中读取
  • 导入的导出名称可以通过 Dependency.getReferencedExports() 获取
  • Dependency 类上有一个 weak 标志
  • 排序仅与 HarmonyImportDependencies 相关,可以通过 sourceOrder 属性获取

展示性依赖

现在 NormalModules 中有一种新型依赖:展示性依赖(Presentational Dependencies)

这些依赖仅在代码生成阶段使用,而不用于模块图构建。因此,它们永远不能拥有引用的模块或影响导出/导入。

这些依赖的处理成本更低,webpack 在可能的情况下会使用它们

已弃用的加载器

  • null-loader

    它将被弃用。请使用

    module.exports = {
      resolve: {
        alias: {
          xyz$: false,
        },
      },
    };

    或使用绝对路径

    module.exports = {
      resolve: {
        alias: {
          [path.resolve(__dirname, '....')]: false,
        },
      },
    };

小改动

  • Compiler.name:当生成带绝对路径的编译器名称时,请确保使用 |! 分隔名称的两个部分。
    • 使用空格作为分隔符现在已弃用。(路径可能包含空格)
    • 提示:在 Stats 字符串输出中,| 被替换为空格。
  • SystemPlugin 现在默认禁用。
    • 迁移:避免使用它,因为其规范已被移除。您可以通过 Rule.parser.system: true 重新启用它。
  • ModuleConcatenationPluginDependencyVariables 已被移除,因此不再阻止串联
    • 这意味着它现在可以在 moduleglobalprocess 或 ProvidePlugin 的情况下进行串联。
  • 已移除 Stats.presetToOptions
    • 迁移:请改用 compilation.createStatsOptions
  • 已移除 SingleEntryPluginSingleEntryDependency
    • 迁移:请使用 EntryPluginEntryDependency
  • 分块现在可以有多个入口模块
  • 已移除 ExtendedAPIPlugin
    • 迁移:不再需要,__webpack_hash____webpack_chunkname__ 总是可以使用,并且运行时代码在需要时会被注入。
  • ProgressPlugin 不再对 reportProgress 使用 tapable 上下文
    • 迁移:请改用 ProgressPlugin.getReporter(compiler)
  • ProvidePlugin 现在为 .mjs 文件重新启用
  • Stats json 中的 errorswarnings 不再包含字符串,而是包含将信息拆分为属性的对象。
    • 迁移:访问属性上的信息。例如 message
  • Compilation.hooks.normalModuleLoader 已弃用
    • 迁移:请改用 NormalModule.getCompilationHooks(compilation).loader
  • NormalModuleFactory 中的钩子从 waterfall 更改为 bailing,并更改和重命名了返回 waterfall 函数的钩子
  • 已移除 compilationParams.compilationDependencies
    • 插件可以通过添加到 compilation.file/context/missingDependencies 来向编译添加依赖
    • 兼容层会将 compilationDependencies.add 委托给 fileDependencies.add
  • stats.assetsByChunkName[x] 现在总是数组
  • 添加了 __webpack_get_script_filename__ 函数以获取脚本文件的文件名
  • package.json 中的 "sideEffects" 将由 glob-to-regex 处理,而不是 micromatch
    • 这可能在边缘情况下改变了语义
  • 已从 IgnorePlugin 中移除 checkContext
  • 新的 __webpack_exports_info__ API 允许导出使用内省
  • SourceMapDevToolPlugin 现在也适用于非分块资源
  • 当引用的环境变量缺失且没有回退时,EnvironmentPlugin 现在会显示错误
  • 从 schema 中移除 serve 属性

其他小改动

  • 移除了 builtin 目录并将内置功能替换为运行时模块
  • 移除了已弃用的功能
    • BannerPlugin 现在只支持一个参数,可以是对象、字符串或函数
  • 已移除 CachePlugin
  • Chunk.entryModule 已弃用,请改用 ChunkGraph
  • Chunk.hasEntryModule 已弃用
  • Chunk.addModule 已弃用
  • Chunk.removeModule 已弃用
  • Chunk.getNumberOfModules 已弃用
  • Chunk.modulesIterable 已弃用
  • Chunk.compareTo 已弃用
  • Chunk.containsModule 已弃用
  • Chunk.getModules 已弃用
  • Chunk.remove 已弃用
  • Chunk.moveModule 已弃用
  • Chunk.integrate 已弃用
  • Chunk.canBeIntegrated 已弃用
  • Chunk.isEmpty 已弃用
  • Chunk.modulesSize 已弃用
  • Chunk.size 已弃用
  • Chunk.integratedSize 已弃用
  • Chunk.getChunkModuleMaps 已弃用
  • Chunk.hasModuleInGraph 已弃用
  • Chunk.updateHash 签名已更改
  • Chunk.getChildIdsByOrders 签名已更改 (TODO: 考虑移至 ChunkGraph)
  • Chunk.getChildIdsByOrdersMap 签名已更改 (TODO: 考虑移至 ChunkGraph)
  • 已移除 Chunk.getChunkModuleMaps
  • 已移除 Chunk.setModules
  • 已移除弃用的 Chunk 方法
  • 已添加 ChunkGraph
  • 已移除 ChunkGroup.setParents
  • 已移除 ChunkGroup.containsModule
  • 已移除 Compilation.cache,转而使用 Compilation.getCache()
  • ChunkGroup.remove 不再将组与块分离
  • ChunkGroup.compareTo 签名已更改
  • ChunkGroup.getChildrenByOrders 签名已更改
  • ChunkGroup 的 index 和 index 已重命名为 pre/post order index
    • 旧的 getter 已弃用
  • ChunkTemplate.hooks.modules 签名已更改
  • ChunkTemplate.hooks.render 签名已更改
  • ChunkTemplate.updateHashForChunk 签名已更改
  • 已移除 Compilation.hooks.optimizeChunkOrder
  • 已移除 Compilation.hooks.optimizeModuleOrder
  • 已移除 Compilation.hooks.advancedOptimizeModuleOrder
  • 已移除 Compilation.hooks.optimizeDependenciesBasic
  • 已移除 Compilation.hooks.optimizeDependenciesAdvanced
  • 已移除 Compilation.hooks.optimizeModulesBasic
  • 已移除 Compilation.hooks.optimizeModulesAdvanced
  • 已移除 Compilation.hooks.optimizeChunksBasic
  • 已移除 Compilation.hooks.optimizeChunksAdvanced
  • 已移除 Compilation.hooks.optimizeChunkModulesBasic
  • 已移除 Compilation.hooks.optimizeChunkModulesAdvanced
  • 已移除 Compilation.hooks.optimizeExtractedChunksBasic
  • 已移除 Compilation.hooks.optimizeExtractedChunks
  • 已移除 Compilation.hooks.optimizeExtractedChunksAdvanced
  • 已移除 Compilation.hooks.afterOptimizeExtractedChunks
  • 已添加 Compilation.hooks.stillValidModule
  • 已添加 Compilation.hooks.statsPreset
  • 已添加 Compilation.hooks.statsNormalize
  • 已添加 Compilation.hooks.statsFactory
  • 已添加 Compilation.hooks.statsPrinter
  • Compilation.fileDependenciesCompilation.contextDependenciesCompilation.missingDependencies 现在是 LazySets
  • 已移除 Compilation.entries
    • 迁移:请改用 Compilation.entryDependencies
  • 已移除 Compilation._preparedEntrypoints
  • dependencyTemplates 现在是一个 DependencyTemplates 类,而不是原始的 Map
  • 已移除 Compilation.fileTimestampscontextTimestamps
    • 迁移:请改用 Compilation.fileSystemInfo
  • 已移除 Compilation.waitForBuildingFinished
    • 迁移:请使用新队列
  • 已移除 Compilation.addModuleDependencies
  • 已移除 Compilation.prefetch
  • Compilation.hooks.beforeHash 现在在模块哈希创建后调用
    • 迁移:请改用 Compiliation.hooks.beforeModuleHash
  • 已移除 Compilation.applyModuleIds
  • 已移除 Compilation.applyChunkIds
  • 已添加 Compiler.root,它指向根编译器
    • 它可用于在 WeakMaps 中缓存数据,而不是静态作用域
  • 已添加 Compiler.hooks.afterDone
  • Source.emitted 不再由编译器设置
    • 迁移:请改检查 Compilation.emittedAssets
  • 已添加 Compiler/Compilation.compilerPath:它是编译器树中编译器的唯一名称。(在根编译器作用域内唯一)
  • Module.needRebuild 已弃用
    • 迁移:请改用 Module.needBuild
  • Dependency.getReference 签名已更改
  • Dependency.getExports 签名已更改
  • Dependency.getWarnings 签名已更改
  • Dependency.getErrors 签名已更改
  • Dependency.updateHash 签名已更改
  • 已移除 Dependency.module
  • 现在有一个 DependencyTemplate 的基类
  • 已移除 MultiEntryDependency
  • 已添加 EntryDependency
  • 已移除 EntryModuleNotFoundError
  • 已移除 SingleEntryPlugin
  • 已添加 EntryPlugin
  • 已添加 Generator.getTypes
  • 已添加 Generator.getSize
  • Generator.generate 签名已更改
  • 已添加 HotModuleReplacementPlugin.getParserHooks
  • Parser 已移至 JavascriptParser
  • ParserHelpers 已移至 JavascriptParserHelpers
  • 已移除 MainTemplate.hooks.moduleObj
  • 已移除 MainTemplate.hooks.currentHash
  • 已移除 MainTemplate.hooks.addModule
  • 已移除 MainTemplate.hooks.requireEnsure
  • 已移除 MainTemplate.hooks.globalHashPaths
  • 已移除 MainTemplate.hooks.globalHash
  • 已移除 MainTemplate.hooks.hotBootstrap
  • MainTemplate.hooks 的一些签名已更改
  • Module.hash 已弃用
  • Module.renderedHash 已弃用
  • 已移除 Module.reasons
  • Module.id 已弃用
  • Module.index 已弃用
  • Module.index2 已弃用
  • Module.depth 已弃用
  • Module.issuer 已弃用
  • 已移除 Module.profile
  • 已移除 Module.prefetched
  • 已移除 Module.built
  • 已移除 Module.used
    • 迁移:请改用 Module.getUsedExports
  • Module.usedExports 已弃用
    • 迁移:请改用 Module.getUsedExports
  • Module.optimizationBailout 已弃用
  • 已移除 Module.exportsArgument
  • Module.optional 已弃用
  • 已移除 Module.disconnect
  • 已移除 Module.unseal
  • 已移除 Module.setChunks
  • Module.addChunk 已弃用
  • Module.removeChunk 已弃用
  • Module.isInChunk 已弃用
  • Module.isEntryModule 已弃用
  • Module.getChunks 已弃用
  • Module.getNumberOfChunks 已弃用
  • Module.chunksIterable 已弃用
  • 已移除 Module.hasEqualsChunks
  • Module.useSourceMap 已移至 NormalModule
  • 已移除 Module.addReason
  • 已移除 Module.removeReason
  • 已移除 Module.rewriteChunkInReasons
  • 已移除 Module.isUsed
    • 迁移:请改用 isModuleUsedisExportUsedgetUsedName
  • Module.updateHash 签名已更改
  • 已移除 Module.sortItems
  • 已移除 Module.unbuild
    • 迁移:请改用 invalidateBuild
  • 已添加 Module.getSourceTypes
  • 已添加 Module.getRuntimeRequirements
  • Module.size 签名已更改
  • ModuleFilenameHelpers.createFilename 签名已更改
  • 已添加 ModuleProfile 类,包含更多数据
  • 已移除 ModuleReason
  • ModuleTemplate.hooks 签名已更改
  • ModuleTemplate.render 签名已更改
  • 已移除 Compiler.dependencies
    • 迁移:请改用 MultiCompiler.setDependencies
  • 已移除 MultiModule
  • 已移除 MultiModuleFactory
  • NormalModuleFactory.fileDependenciesNormalModuleFactory.contextDependenciesNormalModuleFactory.missingDependencies 现在是 LazySets
  • RuntimeTemplate 方法现在接受 runtimeRequirements 参数
  • 已移除 serve 属性
  • 已移除 Stats.jsonToString
  • 已移除 Stats.filterWarnings
  • 已移除 Stats.getChildOptions
  • 已移除 Stats 辅助方法
  • Stats.toJson 签名已更改(第二个参数已移除)
  • 已移除 ExternalModule.external
  • 已移除 HarmonyInitDependency
  • Dependency.getInitFragments 已弃用
    • 迁移:请改用 apply initFragements
  • DependencyReference 现在接受一个指向模块的函数,而不是一个 Module
  • 已移除 HarmonyImportSpecifierDependency.redirectedId
    • 迁移:请改用 setId
  • acorn 5 -> 8
  • 测试
    • HotTestCases 现在为多个目标运行:async-nodenodewebwebworker
    • TestCases 现在也支持文件系统缓存,使用 store: "instant"store: "pack"
    • TestCases 现在也支持确定性模块 ID
  • 添加了用于排序导入的工具(在 CI 中检查)
  • 当分块名称等于分块 ID 时,运行时中的分块名称映射不再包含条目
  • 在 Stats 中,为 reasons 添加 resolvedModuleIdresolvedModuleIdentifierresolvedModule,这些指向优化(如作用域提升)之前的模块
  • 在 Stats 的 toString 输出中显示 resolvedModule
  • loader-runner 已升级:https://github.com/webpack/loader-runner/releases/tag/v3.0.0
  • Compilation 中的 file/context/missingDependencies 出于性能原因不再排序
    • 不要依赖其顺序
  • webpack-sources 已升级到版本 2:https://github.com/webpack/webpack-sources/releases/tag/v2.0.1
  • 已移除 webpack-command 支持
  • 使用 schema-utils@2 进行 schema 验证
  • Compiler.assetEmitted 的第二个参数已改进,包含更多信息
  • BannerPlugin 会省略尾随空格
  • 已从 LimitChunkCountPlugin 中移除 minChunkSize 选项
  • 将与 JavaScript 相关的文件重组到子目录中
    • webpack.JavascriptModulesPlugin -> webpack.javascript.JavascriptModulesPlugin
  • 已添加 Logger.getChildLogger
  • 将 DllPlugin 的 entryOnly 默认值更改为 true
  • 移除了特殊的请求缩短逻辑,并使用单一相对路径来获得可读的模块名称
  • 允许 SourceMaps 中的 webpack:// URL 提供相对于 webpack 根上下文的路径
  • 添加 API 以生成和处理针对 webpack 配置的 CLI 参数
  • 当使用 System.js 作为 libraryTarget 时,添加 __system_context__ 作为来自 System.js 的上下文
  • 为 DefinePlugin 添加 bigint 支持
  • 为基本的求值(如数学运算)添加 bigint 支持
  • 移除了在哈希创建后修改编译哈希的能力
  • 移除了 HotModuleReplacementPlugin 的 multiStep 模式
  • 当使用嵌套对象或数组时,emitAsset 中的 assetInfo 现在将合并
  • 当路径基于 filename(例如资源)时,[query] 现在是一个有效的占位符
  • 添加 Compilation.deleteAsset 以正确删除资产和非共享相关资产
  • require("webpack-sources") 暴露为 require("webpack").sources
  • terser 5
  • 当句子开头时,Webpack 可以大写 W

2 贡献者

sokrachenxsan