Webpack 5 发布 (2020-10-10)

Webpack 4 于 2018 年 2 月发布。从那时起,我们发布了许多功能,但没有破坏性更改。我们知道人们不喜欢带有破坏性更改的重大更改。特别是对于 webpack,人们通常每年只接触两次,其余时间它“正常工作”。但是,在没有破坏性更改的情况下发布功能也会带来成本:我们无法进行重大的 API 或架构改进。

因此,有时会达到一个点,困难会堆积起来,我们被迫进行破坏性更改,以免搞砸一切。这是新主要版本的时间。因此,webpack 5 包含这些架构改进以及没有它们就无法实现的功能。

主要版本也是修改一些默认值以及与在此期间出现的提案和规范保持一致的机会。

因此,今天(2020-10-10)发布了 webpack 5.0.0,但这并不意味着它已经完成、没有错误或功能齐全。与 webpack 4 一样,我们将继续开发,通过修复问题和添加功能。在接下来的几天里,可能会出现很多错误修复。功能将在稍后提供。

常见问题

那么发布意味着什么?

这意味着我们完成了破坏性更改。已经进行了许多重构,以提升架构并为未来的功能(以及当前功能)奠定良好的基础。

那么什么时候升级?

这取决于。升级失败的可能性很大,您可能需要尝试第二次或第三次。如果您对此持开放态度,请尝试立即升级并向 webpack、插件和加载器提供反馈。我们渴望解决这些问题。有人必须开始,您将成为第一个从中受益的人之一。

赞助更新

Webpack 完全基于 赞助。它不与(也不由)像其他一些开源项目那样的大公司支付。赞助收入的 99% 分配给贡献者和维护者,根据他们所做的贡献进行分配。我们相信将资金投入到使 webpack 变得更好的工作中。

但现在正值疫情,很多公司都不愿意再赞助了。Webpack 也在这些情况下遭受了损失(就像许多其他公司和个人一样)。

我们从未能支付给贡献者他们应得的报酬,但现在我们只有之前一半的资金,因此我们需要进行更大幅度的削减。在情况好转之前,我们只会在每个月的头 10 天支付贡献者和维护者的报酬。在剩下的日子里,他们可以自愿工作,由他们的雇主支付报酬,从事其他工作,或者休假。这样一来,我们就可以在头 10 天内支付的报酬更接近他们投入的时间。

最大的“感谢”要献给 trivago,他们在过去 3 年中一直为 Webpack 提供大量赞助。不幸的是,他们今年无法继续赞助,因为他们受到了 Covid-19 的严重影响。我希望其他公司能站出来,延续这种(巨大的)脚步。

感谢 所有赞助商

总体方向

此版本侧重于以下方面:

  • 通过持久缓存提高构建性能。
  • 通过更好的算法和默认值改进长期缓存。
  • 通过更好的树摇和代码生成来减小包大小。
  • 提高与 Web 平台的兼容性。
  • 清理在 v4 中实现功能时遗留的内部结构,同时不引入任何破坏性更改。
  • 通过现在引入破坏性更改来为未来功能做好准备,使我们能够尽可能长时间地保留 v5。

迁移 指南

请参阅此处的 迁移 指南。

重大更改:移除

已移除的弃用项

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

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

以下是一些在 v4 中没有弃用警告但已被移除的项:

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

弃用代码

新的弃用包含弃用代码,以便于参考。

语法弃用

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

可以使用 Rule.parser.requireInclude 将行为更改为允许、弃用或禁用。

自动 Node.js Polyfills 已移除

在早期,webpack 的目标是允许在浏览器中运行大多数 Node.js 模块,但模块环境发生了变化,许多模块现在主要用于前端目的。Webpack <= 4 附带了许多 Node.js 核心模块的 polyfills,这些 polyfills 在模块使用任何核心模块(例如 crypto 模块)时会自动应用。

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

Webpack 5 停止自动填充这些核心模块,并专注于与前端兼容的模块。我们的目标是提高与 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",这将生成更小的捆绑包,但会更频繁地使它们失效以进行缓存。

注意:在 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.webpackHot 是 `module.hot` 的别名,它在严格的 ESM 中也可用
  • import.meta.webpack 是 webpack 的主要版本号
  • import.meta.url 是当前文件的 `file:` URL(类似于 `__filename`,但作为文件 URL)

资产模块

Webpack 5 现在原生支持表示资产的模块。这些模块要么将文件输出到输出文件夹,要么将 DataURI 注入到 JavaScript 包中。无论哪种方式,它们都会提供一个 URL 来使用。

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

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

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

原生 Worker 支持

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

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

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

URI

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

  • data: 受支持。支持 Base64 或原始编码。可以在 `module.rules` 中将 MIME 类型映射到加载器和模块类型。示例: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,该 Promise 解析为导出。

在 webpack 中,有多种方法可以拥有异步模块

  • 异步外部资源
  • 新规范中的 WebAssembly 模块
  • 使用顶层等待的 ECMAScript 模块

外部资源

Webpack 5 添加了额外的外部资源类型以涵盖更多应用程序

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

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

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

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

重大变化:新的 Node.js 生态系统功能

解析

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

Yarn PnP 原生支持。

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

重大变化:开发体验

改进的目标

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

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

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

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

统计信息

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

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

进度

ProgressPlugin 进行了一些改进,ProgressPlugin 用于 CLI 的 --progress,但也可以手动用作插件。

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

它过去显示当前正在处理的模块。这会导致大量的 stderr 输出,并在某些控制台上产生性能问题。现在默认情况下已禁用此功能(activeModules 选项)。这也减少了控制台上的垃圾邮件数量。现在,在构建模块期间写入 stderr 的频率已限制为 500 毫秒。

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

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

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

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

自动唯一命名

在 webpack 4 中,多个 webpack 运行时可能会在同一个 HTML 页面上发生冲突,因为它们使用相同的全局变量进行 chunk 加载。为了解决这个问题,需要为 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 导出时才使用。这允许将更多导出标记为未使用,并从捆绑包中省略更多代码。

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

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

可以分析以下符号

  • 函数声明
  • 类声明
  • export default 以及变量声明,使用
    • 函数表达式
    • 类表达式
    • 序列表达式
    • /*#__PURE__*/ 表达式
    • 局部变量
    • 导入绑定

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

使用 eval() 将使模块的此优化失效,因为 evaled 代码可能引用作用域中的任何符号。

此优化也称为深度作用域分析。

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
  • 标记的 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 模块的支持,更多模块可能会很快发布。

通用 Tree Shaking 改进

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

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

import() 允许通过 /* webpackExports: ["abc", "default"] */ 魔术注释手动进行模块的 Tree Shaking。

开发与生产相似性

我们试图在开发模式下的构建性能和避免生产模式独有的问题之间找到一个良好的平衡点,方法是提高两种模式之间的相似性。

Webpack 5 在两种模式下默认启用 sideEffects 优化。在 webpack 4 中,这种优化会导致一些生产模式独有的错误,因为 package.json 中的 "sideEffects" 标志不正确。在开发中启用此优化可以更快、更容易地发现这些问题。

在许多情况下,开发和生产发生在不同的操作系统上,文件系统的区分大小写也不同,因此 webpack 5 在存在大小写方面奇怪的问题时添加了一些额外的警告/错误。

改进的代码生成

Webpack 检测到 ASI 发生时,在没有插入分号的情况下生成更短的代码。Object(...) -> (0, ...)

Webpack 将多个导出获取器合并到单个运行时函数调用中: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 代码。

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

改进的 target 选项

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

target 选项现在比以前影响生成的代码的更多方面

  • 块加载方法
  • 块格式
  • Wasm 加载方法
  • 工作线程中 chunk 和 Wasm 加载方法
  • 使用的全局对象
  • 是否应自动确定 publicPath
  • 生成的代码中使用的 ECMAScript 特性/语法
  • 默认情况下启用的 externals
  • 一些 Node.js 兼容层 (global, __filename, __dirname) 的行为
  • 模块解析 (browser 字段,exportsimports 条件)
  • 一些加载器可能会根据此改变行为

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

现在还可以使用数组组合多个目标,Webpack 将确定所有目标的最小属性。当使用没有提供完整信息的目标(例如 "web""node"(没有版本号))时,使用数组也很有用。例如,["web", "es2020"] 将这两个部分目标组合在一起。

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

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

  • ["web", "node"] 将导致通用 chunk 加载方法,该方法尚未实现
  • ["web", "node"] + output.module: true 将导致模块 chunk 加载方法,该方法尚未实现
  • "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 目录(webpack 所在的目录)**仅**由包管理器修改。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 以前总是会在第一次构建期间发出所有输出文件,但在增量(监视)构建期间会跳过写入未更改的文件。假设在 webpack 运行时没有其他内容会更改输出文件。

添加了持久缓存后,即使重新启动 webpack 进程,也应该提供类似监视的体验,但认为即使 webpack 未运行,也没有其他内容会更改输出目录,这将是一个过于强烈的假设。

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

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

标记为 [immutable](包括内容哈希)的文件,如果同名文件已存在,将永远不会被写入。我们假设文件内容发生更改时内容哈希会发生更改。这通常是正确的,但在 webpack 或插件开发过程中可能并不总是正确。

重大更改:长期存在的问题

针对单文件目标的代码拆分

现在,仅允许启动单个文件(如 node、WebWorker、electron 主进程)的目标支持通过运行时自动加载启动所需的依赖项。

这允许针对这些目标使用 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 一起发布

  • 旧的 WebAssembly 支持,如 webpack 4 中的 (experiments.syncWebAssembly)
  • 根据 更新规范 的新的 WebAssembly 支持 (experiments.asyncWebAssembly)
    • 这使得 WebAssembly 模块成为异步模块
  • 顶层等待 阶段 3 提案 (experiments.topLevelAwait)
    • 在顶层使用 await 使模块成为异步模块
  • 将捆绑包作为模块发出 (experiments.outputModule)
    • 这将从捆绑包中删除包装 IIFE,强制执行严格模式,通过 <script type="module"> 进行延迟加载,并在模块模式下最小化

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

最低 Node.js 版本

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

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

配置更改

结构更改

  • entry: {} 现在允许使用空对象(允许使用插件添加条目)
  • target 支持数组、版本和浏览器列表
  • 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 模块的自动 polyfill
    • node.Buffer 已移除
    • node.console 已移除
    • node.process 已移除
    • node.*(Node.js 原生模块)已移除
    • 迁移resolve.aliasProvidePlugin。错误将给出提示。(有关 v4 中使用的 polyfill 和模拟,请参阅 node-libs-browser
  • 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.splitChunks test 不再匹配块名称
    • 迁移:使用测试函数 (module, { chunkGraph }) => chunkGraph.getModuleChunks(module).some(chunk => chunk.name === "name")
  • optimization.splitChunks minRemainingSize 已添加
  • optimization.splitChunks filename 现在可以是函数
  • optimization.splitChunks 大小现在可以是包含每个源类型大小的对象
    • minSize
    • minRemainingSize
    • maxSize
    • maxAsyncSize
    • maxInitialSize
  • optimization.splitChunks maxAsyncSizemaxInitialSize 已添加到 maxSize 旁边:允许为初始块和异步块指定不同的最大大小
  • optimization.splitChunks name: true 已移除:不再支持自动命名
    • 迁移: 使用默认值。chunkIds: "named" 将为您的文件提供有用的名称以进行调试
  • optimization.splitChunks.cacheGroups[].idHint 已添加:提示如何选择命名的 chunk id
  • optimization.splitChunks automaticNamePrefix 已移除
    • 迁移: 使用 idHint 代替
  • optimization.splitChunks filename 不再限于初始 chunk
  • 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.rules resolveparser 将以不同的方式合并(对象深度合并,数组可能包含 "..." 以引用先前值)
  • module.rules parser.worker 已添加:允许配置支持的 worker
  • module.rules queryloaders 已移除
  • module.rules 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: 显示与其他资产相关的资产(例如 SourceMap)
  • stats.warningsFilter 已弃用,取而代之的是 ignoreWarnings
  • BannerPlugin.banner 的签名已更改
    • 已删除 data.basename
    • 已删除 data.query
    • 迁移: 从 filename 中提取
  • 已删除 SourceMapDevToolPluginlineToLine
    • 迁移: 没有替代
  • [hash] 作为完整编译的哈希值现在已弃用
    • 迁移: 使用 [fullhash] 代替,或者最好使用其他哈希选项
  • [modulehash] 已弃用
    • 迁移: 使用 [hash] 代替
  • [moduleid] 已弃用
    • 迁移: 使用 [id] 代替
  • 已删除 [filebase]
    • 迁移: 使用 [base] 代替
  • 基于文件的模板(例如 SourceMapDevToolPlugin)的新占位符
    • [name]
    • [base]
    • [path]
    • [ext]
  • 传递函数时,externals 现在具有不同的签名 ({ context, request }, callback)
    • 迁移: 更改签名
  • 添加了 externalsPresets
  • 添加了 experiments(参见上面的实验部分)
  • 添加了 watchOptions.followSymlinks
  • watchOptions.ignored 现在可以是 RegExp
  • 现在公开了 webpack.util.serialization

默认值的更改

  • 当有 browserslist 配置时,target 现在默认情况下为 "browserslist"
  • module.unsafeCache 现在默认情况下仅对 node_modules 启用
  • 在生产模式下,optimization.moduleIds 默认情况下为 deterministic,而不是 size
  • 在生产模式下,optimization.chunkIds 默认情况下为 deterministic,而不是 total-size
  • none 模式下,optimization.nodeEnv 默认情况下为 false
  • 在生产环境中,optimization.splitChunks.minSize 默认情况下为 20k
  • 在生产环境中,optimization.splitChunks.enforceSizeThreshold 默认情况下为 50k
  • optimization.splitChunksminRemainingSize 默认情况下为 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
  • resolve(Loader).cache 在使用 cache 时默认值为 true
  • resolve(Loader).cacheWithContext 默认值为 false
  • resolveLoader.extensions 删除 .json
  • node.global node.__filenamenode.__dirname 在 node-target 中默认值为 false
  • stats.errorStack 默认值为 false

加载器相关更改

this.getOptions

此新 API 应该简化加载器中选项的使用。它允许传递 JSON 架构以进行验证。有关详细信息,请参阅 PR

this.exec

此项已从加载器上下文移除。

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

this.getResolve

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

由于 webpack 5 区分了不同的发出依赖项,因此将选项作为 dependencyType 传递可能是有意义的(例如 "esm""commonjs" 或其他)。

主要内部更改

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

新的插件顺序

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

但这也是一个重大变更,因为插件无法依赖于应用时设置的配置值。

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

运行时模块

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

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

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

迁移:如果您正在将运行时代码注入到 webpack 运行时中,请考虑使用 RuntimeModules 代替。

序列化

添加了一个序列化机制,允许在 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 弃用

捆绑模板已重构。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 生成。

优化模块和块顺序的钩子已被删除。

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

数组到集合

  • Compilation.modules 现在是一个 Set
  • Compilation.chunks 现在是一个 Set
  • Chunk.files 现在是一个 Set

存在一个兼容层,它会打印弃用警告。

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

Compilation.fileSystemInfo

这个新类可以用来以缓存的方式访问文件系统信息。目前,它允许查询文件和目录的时间戳。时间戳信息如果可能的话会从监视器中获取,否则通过访问文件系统来确定。

将来,将添加对文件内容哈希的查询,模块将能够使用文件内容而不是文件哈希来检查有效性。

迁移:不要再使用 file/contextTimestamps,而是使用 compilation.fileSystemInfo API。

现在可以对目录进行时间戳,这允许序列化 ContextModules。

Compiler.modifiedFiles 已被添加(与 Compiler.removedFiles 相邻),以便更容易地引用已更改的文件。

文件系统

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

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

热模块替换

HMR 运行时已重构为运行时模块。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 以前通过函数调用函数来处理模块处理,以及一个限制并发的 semaphoreCompilation.semaphore 已被移除,异步队列现在处理工作排队和处理。每个步骤都有一个单独的队列

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

这些队列有一些钩子来观察和拦截作业处理。

将来,多个编译器可以协同工作,作业编排可以通过拦截这些队列来完成。

迁移:由于这是一个新引入的功能,因此没有需要迁移的内容。

日志记录

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

模块和块图

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

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

  • 模块连接 -> ModuleGraph
  • 模块发行者 -> ModuleGraph
  • 模块优化跳出 -> ModuleGraph(待办事项:检查是否应该改为 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 会将源代码嵌入到捆绑包中。源代码类型 webassembly 将使 WebAssemblyModulesPlugin 发出一个 wasm 文件。自定义源代码类型也受支持,例如,mini-css-extract-plugin 可能使用源代码类型 stylesheet 将源代码嵌入到一个 css 文件中。

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

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

用于统计的插件

统计 presetdefaultjsontoString 现在由插件系统内置。将当前统计信息转换为插件。

迁移: 现在可以自定义统计信息,而不是替换整个统计信息功能。现在可以将额外信息添加到统计信息 json 中,而不是写入单独的文件。

新的观察

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

它还捕获了更多有关文件系统的信息,同时进行观察。它现在捕获 mtimes 和观察事件时间,以及有关丢失文件的信息。为此,WatchFileSystem API 有所改变。同时,我们还将数组转换为集合,将对象转换为映射。

发射后 SizeOnlySource

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

多次发出资产

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

ExportsInfo

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

每个导出都存储以下信息

  • 导出是否被使用? 是,否,静态未知,未确定。(另请参见 optimization.usedExports
  • 导出是否已提供? 是,否,静态未知,未确定。(另请参见 optimization.providedExports
  • 导出名称可以重命名吗? 是,否,未确定。
  • 新名称,如果导出已重命名。(另请参见 optimization.mangleExports
  • 嵌套的 ExportsInfo,如果导出是带有附加信息的 object
    • 用于重新导出命名空间对象: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` 中有一种新的依赖类型:表现性依赖。

这些依赖只在代码生成阶段使用,但在模块图构建期间不使用。因此,它们永远不会有引用的模块或影响导出/导入。

这些依赖处理起来更便宜,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` 重新启用它。
  • `ModuleConcatenationPlugin`:由于 `DependencyVariables` 已被删除,连接不再被它们阻止。
    • 这意味着它现在可以在moduleglobalprocess或ProvidePlugin的情况下进行连接
  • Stats.presetToOptions已移除
    • 迁移:使用compilation.createStatsOptions代替
  • SingleEntryPluginSingleEntryDependency已移除
    • 迁移:使用EntryPluginEntryDependency
  • 块现在可以有多个入口模块
  • ExtendedAPIPlugin已移除
    • 迁移:不再需要,__webpack_hash____webpack_chunkname__始终可以使用,并且运行时代码将在需要时注入。
  • ProgressPlugin不再使用tapable上下文用于reportProgress
    • 迁移:使用ProgressPlugin.getReporter(compiler)代替
  • ProvidePlugin现在已重新启用,用于.mjs文件
  • Stats json errorswarnings不再包含字符串,而是包含将信息拆分为属性的对象。
    • 迁移:访问属性上的信息。例如message
  • Compilation.hooks.normalModuleLoader已弃用
    • 迁移:使用NormalModule.getCompilationHooks(compilation).loader代替
  • 更改了NormalModuleFactory中的钩子,从瀑布式改为退出式,更改并重命名了返回瀑布式函数的钩子
  • 已移除compilationParams.compilationDependencies
    • 插件可以通过添加到compilation.file/context/missingDependencies来将依赖项添加到编译中
    • 兼容层将把compilationDependencies.add委托给fileDependencies.add
  • stats.assetsByChunkName[x]现在始终是一个数组
  • 添加了__webpack_get_script_filename__函数来获取脚本文件的名称
  • "sideEffects"在package.json中将由glob-to-regex而不是micromatch处理
    • 这可能在边缘情况下改变了语义
  • checkContext已从IgnorePlugin中移除
  • 新的__webpack_exports_info__ API允许导出使用内省
  • SourceMapDevToolPlugin现在也适用于非块资产
  • EnvironmentPlugin现在在引用的环境变量丢失且没有回退时显示错误
  • 从模式中移除serve属性

其他细微更改

  • 删除内置目录,并用运行时模块替换内置模块
  • 删除弃用功能
    • 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 索引和索引已重命名为前/后序索引
    • 旧的 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 已移除
    • 迁移: 使用 isModuleUsed, isExportUsedgetUsedName 代替
  • 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 现在接受一个指向模块的函数,而不是一个模块
  • HarmonyImportSpecifierDependency.redirectedId 已移除
    • 迁移: 使用 setId 代替
  • acorn 5 -> 8
  • 测试
    • HotTestCases 现在针对多个目标运行 async-node node web webworker
    • TestCases 现在也针对具有 store: "instant"store: "pack" 的文件系统缓存运行
    • TestCases 现在也针对确定性模块 ID 运行
  • 添加了工具来对导入进行排序(在 CI 中检查)
  • 运行时中的块名称映射不再包含块名称等于块 ID 时的条目
  • 在 Stats 中添加 resolvedModuleId resolvedModuleIdentifierresolvedModule 到原因,这些原因指向优化(如作用域提升)之前的模块
  • 在 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 进行模式验证
  • Compiler.assetEmitted 的第二个参数已改进,包含更多信息
  • BannerPlugin 忽略尾随空格
  • LimitChunkCountPlugin 中删除了 minChunkSize 选项
  • 将与 JavaScript 相关的文件重组到子目录中
    • webpack.JavascriptModulesPlugin -> webpack.javascript.JavascriptModulesPlugin
  • 添加了 Logger.getChildLogger
  • 将 DllPlugin 的 entryOnly 默认值更改为 true
  • 删除特殊的请求缩短逻辑,并使用单个相对路径来获得可读的模块名称
  • 允许 SourceMap 中的 webpack:// URL 指向相对于 webpack 根上下文提供的路径
  • 添加 API 来生成和处理针对 webpack 配置的 CLI 参数
  • 当使用 System.js 作为 libraryTarget 时,添加 __system_context__ 作为来自 System.js 的上下文
  • 为 DefinePlugin 添加 BigInt 支持
  • 为基本计算(如数学运算)添加 BigInt 支持
  • 删除在哈希创建后修改编译哈希的能力
  • 删除 HotModuleReplacementPlugin 的 multiStep 模式
  • 当使用嵌套对象或数组时,emitAsset 中的 assetInfo 现在将合并
  • [query] 现在是基于 filename(如资产)的路径的有效占位符
  • 添加 Compilation.deleteAsset 以正确删除资产和非共享相关资产
  • require("webpack-sources") 暴露为 require("webpack").sources
  • terser 5
  • Webpack 在句首时可以用大写 W

2 位贡献者

sokrachenxsan