★webpack 团队于北京时间 10 月 12 日凌晨发布了
”v5.0.0-beta.0
版本,本文译自webpack/changelog-v5
。此部分主要面向非插件开发的 webpack 使用者。
简要说明
此版本重点关注以下内容:
-
我们尝试通过持久化存储优化构建性能。
-
我们尝试采用更好的算法与 defalut 来改善长效缓存。
-
我们尝试通过更好的 Tree Shaking 和代码生成来改善 bundle 的大小。
-
我们尝试清除内部结构中奇怪的代码,同时在不影响 v4 功能基础上实现了新特性。
-
我们目前尝试通过引入破坏性更改来为新特性做准备,以便于我们能尽可能长期地使用 v5。
迁移指南
=> 查阅迁移指南[1] <=
主要更改
移除废弃的代码
v4 中所有废弃的代码均已删除。
迁移:以确保你的 webapck 4 不打印弃用警告。
以下是已删除但在 v4 中没有弃用警告的内容:
-
现在必须为 IgnorePlugin 和 BannerPlugin 传递一个 options 对象。
自动移除 Node.js Polyfills
早期,webpack 的目的是允许在浏览器中运行大多数 node.js 模块,但是模块整体格局发生了变化,现在许多模块的主要用途是以编写前端为目的。webpack <= 4 附带了许多 Node.js 核心模块的 polyfil,一旦模块中使用了任何核心模块(即 ”crypto“ 模块),这些模块就会被自动启用。
虽然这使得为 Node.js 编写模块变得简单,但它会将超大的 polyfill 添加到 package 中。在许多情况下,这些 polyfill 并非必要。
webpack 5 会停止自动 polyfill 这些核心模块,并专注于与前端兼容的模块。
迁移:
-
尽可能尝试使用与前端兼容的模块。
-
可以为 Node.js 核心模块手动添加 polyfill。错误信息将提示如何进行此操作。
-
package 作者:在
package.json
中使用browser
字段,以使得 package 与前端代码兼容。为 borwser 提供可选的 implementations/dependencies。
反馈:无论是否喜欢上述修改,请都向我们提出反馈。我们并不确定是否会纳入最终版本。
采用新算法生成 chunk ID 以及 module ID
添加了用于长效缓存的新算法。在生产模式下,默认启用这些功能。
chunkIds: "deterministic", moduleIds: "deterministic"
此算法采用确定性的方式将短数字 ID(3 或 4 个字符)分配给 modules 和 chunks。这是基于 bundle 大小和长效缓存间的折中方案。
迁移:最好使用 chunkIds
和 moduleIds
的默认值。你还可以选择使用旧的默认值,chunkIds: "size", modules: "size"
,这将生成较小的 bundle,但这会使得它们频繁地进行缓存。
以新算法混淆 export 名称
添加了新算法来处理 export 的名称。默认情况下启用。
如果可能,它将以确定性方式破坏 export 的名称。
迁移:不需要进行任何操作。
为 chunk IDs 命名
在开发模式下默认启用,以新的算法为 chunk id 命名,给 chunk(以及文件名)提供易于理解的名称。module ID 由其相对于 context
的路径决定。chunk ID 由 chunk 的内容决定。
因此,你不再需要使用 import(/* webpackChunkName: "name" */ "module")
进行调试。但是,如果你要控制生产环境的文件名,那仍可使用。
可以在生产中使用 chunkIds: "named"
,但要确保在使用时不会意外地泄露有关模块名称的敏感信息。
迁移:如果你不喜欢在开发中更改文件名,则可以传递 chunkIds: "natural"
以使用旧的数字模式。
JSON 模块
JSON 模块现在符合规范,并会在使用非默认导出时发出警告。
迁移:使用默认导出。
(自 alpha.16 起)
嵌套 tree-shaking
webpack 现在可以追踪对 exports 嵌套属性的访问。重新导出 namespace 对象,这可以改善 Tree Shaking 操作(未使用 export elimination 和 export mangling)。
// inner.jsexport const a = 1;export const b = 2;// module.jsimport * as inner from "./inner";export { inner }// user.jsimport * as module from "./module";console.log(module.inner.a);
在此示例中,可以在生成模式下移除 export b
。
(从 alpha.15 起)
内部模块(inner-module) tree-shaking
webpack 4 没有分析模块 export 与 import 之间的依赖关系。webpack 5 有一个新的选项 optimization.innerGraph
,该选项在生产模式下默认启用,它对模块中的符号进行分析以找出从 export 到 import 的依赖关系。
如下述模块所示:
import { something } from "./something";function usingSomething() { return something;}export function test() { return usingSomething();}
内部图算法将确定仅在使用 export 的 test
时使用 something
。这样可以将更多 export 标记为未使用,并从 bundle 中删除更多的代码。
如果设置了 "sideEffects": false
,则可以省略更多模块。在此示例中,当未使用 export 的 test
时,将忽略 ./something
。
如需获取有关未使用的 export 的信息,需使用 optimization.unusedExports
。如需删除无副作用的模块,需使用 optimization.sideEffects
。
此方式可以分析以下符号:
-
函数声明(function declarations)
-
class 声明(class declarations)
-
带有
export default
或带有变量声明(variable declarations)的 -
函数表达式(function expressions)
-
class 语句(class expressions)
-
/*#__PURE__*/
表达式 -
局部变量(local variables)
-
imported bindings
反馈:如果您发现此分析中缺少某些内容,请反馈 issues,我们考虑将其添加。
此优化也称为深度作用域分析(Deep Scope Analysis)。
(自 alpha.24 起)
编译器空闲并关闭(idle and close)
现在需要再使用编译器(compilers)后将其关闭。编译器具有 enter 和 leave 空闲状态,并具有这些状态的 hook。插件可以使用这些 hook 执行不重要的工作。(即,持久化缓存将延迟存储到磁盘)。在编译器关闭时,所有剩余工作应尽快完成。回调执行时,表明关闭已完成。
插件及其各自的作者应该会期望某些用户可能会忘记关闭编译器。因此,所有工作最终也应该在空闲时完成。当工作完成时,应防止进程退出。
当传递 callback 时,webpack()
实例会自动调用 close
。
迁移:使用 node.js API 时,请确保在完成后调用 Complier.close
。
改进代码生成
此版本添加了新的选项 output.ecmaVersion
。它允许为 webpack 生成的运行时代码指定最大 EcmaScript 版本。
webpack 4 仅能于生成 ES5 的代码。webpack 5 现支持 ES5 或 ES2015 的代码。
默认配置将生成 ES2015 的代码。如果你需要支持旧版浏览器(例如,IE11),则可以将其降为 output.ecmaVersion: 5
。
设置为 output.ecmaVersion: 2015
将使用箭头函数生成较短的代码,以及更多符合规范的代码,使用 const 声明(TDZ)作为 export default
。
(自 alpha.23 起)
生产模式中的默认压缩(default minimizing)也使用 ecmaVersion
选项生成较小的代码。(自 alpha.31 起)
chunk 分割以及 module size
与之前展示单个数值相比,模块现在以更好的方式展示其 size。除此之外,现在也拥有了不同类型的 size。
目前,SplitChunksPlugin 已知道如何处理这些不同的 size,并将它们应用于 minSize
和 maxSize
。默认情况下,仅处理 javascript 的 size,但你可以传递多个参数来管理它们:
minSize: { javascript: 30000, style: 50000,}
迁移:检查构建中使用了哪些类型的 size,并在 splitChunks.minSize
和可选的 splitChunks.maxSize
中进行配置。
持久化缓存
目前包含文件系统缓存。它是可选的,可以通过以下配置启用:
cache: { // 1. 设置缓存类型为 filesystem type: "filesystem", buildDependencies: { // 2. 将你的配置添加为 buildDependency 以在更改配置时,使得缓存失效。 config: [__filename] // 3. 如果你还有其他需要构建的内容,可以在此处添加它们 // 请注意,loader 和所有模块中配置中引用的内容会自动添加 }}
重要内容:
默认情况下,webpack 会假定其所处的 node_modules
目录仅由包管理器修改。针对 node_modules 目录,将跳过哈希和时间戳处理。出于性能方面考虑,仅使用 package 的名称和版本。symlinks(例如,npm/yarn link
)很友好。除非你使用 cache.managedPaths: []
选项取消此优化,否则请不要直接在 node_modules
中编辑文件。
默认情况下,缓存将分别存储在 node_modules/.cache/webpack
中(当使用 node_modules 时)和 .pnp/.cache/webpack
(当使用 Yarn PnP 时,自 alpha.21 起)。你可能永远不必手动删除它。
(自 alpha.20 起)
当使用 Yarn PnP webpack 时,如果 yarn 的缓存不可变(通常不会发生变化)。你可以通过 cache.immutablePaths: []
退出此优化。
(自 alpha.21 起)
用于 single-file-target 的 chunk 分割
目前,仅允许启动单个文件 target(如 node,WebWorker,electron main)支持在运行时自动加载引导程序所需的相关代码片段。
这允许对带有 chunks: "all"
的 target 使用 splitChunks
。
值得注意的是,由于 chunk 加载是异步的,因此这也会使初始估算也为异步操作。当使用 output.library
时,这可能会出现问题,因为导出的值的类型目前为 Promise。从 alpha.14 开始,这将不适用于 target: "node"
,因为 chunk 加载在此 target 下为同步。
(自 alpha.3 起)
更新解析器
enhanced-resolve
已更新至 v5。具体改进如下:
-
当使用 Yarn PnP 时,解析器将直接处理无需其他插件
-
此 resolve 可追踪更多的依赖项,例如文件缺失
-
别名(aliasing)可能包含多种选择
-
可以设置别名(aliasing)为
false
-
性能提升
(自 alpha.18 起)
不包含 JS 的 chunk
不包含 JS 代码的 chunk 将不再生成 JS 文件。
(自 alpha.14 起)
实验阶段特性
并非所有特性从开始就文档。在 webpack 4 中,我们添加了实验性功能,并在 changelog 中指出它们是实验性的,但是从配置中并不能很清楚的了解这些功能是实验性的。
在 webpack 5 中,有一个新的 experiments
配置项,允许启用实验性功能。这样可以清楚地了解启用/使用了哪些实验特性。
虽然 webpack 遵循语义版本控制,但是实验性功能将成为例外。它可能包含 webpack 次要版本的破坏性更改。发生这种情况时,我们将在 changelog 中添加清晰的注释。这促使我们可以更快地迭代实验性功能,同时还可以使用我们在主要版本上停留更长时间以获得稳定的功能。
以下实验性功能将随 webpack 5 一同发布:
-
像 webpack 4 一样对
.mjs
提供支持(experiments.mjs
) -
像 webpack 4 一样对旧版 WebAssembly 提供支持(
experiments.syncWebAssembly
) -
根据更新规范[2] 对新版 WebAssembly 提供支持(
experiments.asyncWebAssembly
) -
这使得 WebAssembly 模块成为异步模块
-
Top Level Await[3] Stage 3 阶段提案(
experiments.topLevelAwait
) -
在顶层使用
await
使模块成为异步模块 -
使用
import
引入异步模块(experiments.importAsync
) -
使用
import await
引入异步模块(experiments.importAwait
) -
asset
模块类似类似于file-loader
(experiments.asset
)(自 alpha.19 起) -
导出 bundle 作为模块(
experiments.outputModule
)(自 alpha.31 起) -
这将从 bundle 中移除 IIFE 的包装器,强制执行严格模式,通过
<script type="module">
进行懒加载,并在module
模式下将其进行压缩
请注意,这也意味着针对 .mjs
的支持和 WebAssembly 的支持将被默认禁用。
(自 alpha.15 起)
Stats
chunk 间关系默认情况下是隐藏的。可以使用 stats.chunkRelations
进行切换。
(自 alpha.1 起)
Stats 现阶段可以区分 files
和 auxiliaryFiles
。
(自 alpha.19 起)
默认情况下,Stats 会隐藏模块和 chunk id。可以使用 stats.ids
进行切换。
所有模块的列表均按照到 entrypoint 的距离排序。可以使用 stats.modulesSort
进行切换。
chunk 模块列表和 chunk 根模块列表分别根据模块名进行排序。可以分别使用 stats.chunkModulesSort
和 stats.chunkRootModulesSort
进行更改。
在串联模块中,嵌套模块列表进行拓扑排序。可以通过 stats.nestedModulesSort
进行更改。
chunks 和 assets 会显示 chunk id 的提示。
(自 alpha.31 起)
最低 Node.js 版本
Node.js 的最低支持版本从 6 变更为 8。
迁移:升级到最新的 node.js 可用版本。
配置变更
结构变更
-
移除
cache: Object
:不能设置为内存缓存对象 -
添加
cache.type
:可以设置为"memory"
或"filesystem"
-
为
cache.type = "filesystem"
添加新配置项: -
cache.cacheDirectory
-
cache.name
-
cache.version
-
cache.store
-
`cache.loglevel`(自 alpha.20 起被移除)
-
cache.hashAlgorithm
-
cache.idleTimeout
(自 alpha.8 起) -
cache.idleTimeoutForIntialStore
(自 alpha.8 起) -
cache.managedPaths
(自 alpha.20 起) -
cache.immutablePaths
(自 alpha.21 起) -
cache.buildDependencies
(自 alpha.20 起) -
添加
resolve.cache
:允许禁用/启用安全 resolve 缓存 -
移除
resolve.concord
-
移除用于原生 node.js 模块自动的 polyfill
-
移除
node.Buffer
-
移除
node.console
-
移除
node.process
-
移除
node.*
(node.js 原生模块) -
迁移:使用
resolve.alias
和ProvidePlugin
。发生错误会给出提示。 -
output.filename
可以赋值函数(自 alpha.17 起) -
添加
output.assetModuleFilename
(自 alpha.19 起) -
resolve.alias
的值可以为数组或false
(自 alpha.18 起) -
添加
optimization.chunkIds: "deterministic"
-
添加
optimization.moduleIds: "deterministic"
-
添加
optimization.moduleIds: "hashed"
-
添加
optimization.moduleIds: "total-size"
-
移除 module 和 chunk id 的相关的弃用选项
-
移除
optimization.hashedModuleIds
-
移除
optimization.namedChunks
(NamedChunksPlugin
与之相同) -
移除
optimization.namedModules
(NamedModulesPlugin
与之相同) -
移除
optimization.occurrenceOrder
-
迁移:使用
chunkIds
或moduleIds
-
optimization.splitChunks
test
不在匹配 chunk 名 -
迁移:使用 test 函数
(module, { chunkGraph }) => chunkGraph.getModuleChunks(module).some(chunk => chunk.name === "name")
-
在
optimization.splitChunks
中添加minRemainingSize
(自 alpha.13 起) -
optimization.splitChunks
filename
可以赋值函数 (since alpha.17) -
optimization.splitChunks
sizes 可以为每个源类型的 size 对象 -
minSize
-
minRemainingSize
-
maxSize
-
maxAsyncSize
(自 alpha.13 起) -
maxInitialSize
-
在
optimization.splitChunks
中添加maxAsyncSize
和maxInitialSize
:允许为初始和异步 chunk 指定不同的最大 size。 -
移除
optimization.splitChunks
中的name: true
:不再支持自动命名 -
迁移:使用默认值。
chunkIds: "named"
将为你的文件提供有用的名称以便于调试 -
添加
optimization.splitChunks.cacheGroups[].idHint
:将提示如何命名 chunk id -
移除
optimization.splitChunks
中的automaticNamePrefix
-
迁移:使用
idHint
替代 -
optimization.splitChunks
中的filename
不再局限于初始 chunk(自 alpha.11 起) -
添加
optimization.mangleExports
(自 alpha.10 起) -
移除
output.devtoolLineToLine
-
迁移:无替代方式
-
output.hotUpdateChunkFilename: Function
现在被禁止:不会生效。 -
output.hotUpdateMainFilename: Function
现在被禁止:不会生效。 -
module.rules
中的resolve
和parser
将以不同的方式合并(对象会进行深度合并,数组将采用"..."
进行展开以获取之前的值)(自 alpha.13 起) -
module.rules
中的query
和loaders
已被移除(自 alpha.13 起) -
添加
stats.chunkRootModules
:展示 chunk 的根模块 -
添加
stats.orphanModules
:展示未触发的模块。 -
添加
stats.runtime
:展示 runtime 模块 -
添加
stats.chunkRelations
:显示 parent/children/sibling chunk(自 alpha.1 起) -
添加
stats.preset
:选择 preset(自 alpha.1 起) -
BannerPlugin.banner
签名变更 -
移除
data.basename
-
移除
data.query
-
迁移:从
filename
中进行提取 -
移除
SourceMapDevToolPlugin
中的lineToLine
-
迁移:无替代方式
-
[hash]
不支持完整编译的 hash -
迁移:使用
[fullhash]
或采用更好的 hash 选项 -
[modulehash]
被废弃 -
迁移:使用
[hash]
代替 -
[moduleid]
被废弃 -
迁移:使用
[id]
代替 -
移除
[filebase]
-
迁移:使用
[base]
代替 -
基于文件模板的新占位符(即 SourceMapDevToolPlugin)
-
[name]
-
[base]
-
[path]
-
[ext]
-
当向
externals
传递一个函数时,它将具有不同的函数签名({ context, request }, callback)
-
迁移:更改函数签名
-
添加
experiments
(请参阅上述实验部分,自 alpha.19 起) -
添加
watchOptions.followSymlinks
(自 alpha.19 起)
默认值变更
-
默认情况下,仅对
node_modules
启用module.unsafeCache
-
在生产模式下,
optimization.moduleIds
的默认值从size
替换为deterministic
-
在生产模式下,
optimization.chunkIds
的默认值从total-size
替换为deterministic
-
在
none
模式下,optimization.nodeEnv
默认为false
-
optimization.splitChunks
中的minRemainingSize
默认为minSize
(自 alpha.13 起) -
如果剩余部分过小,这将减少创建 chunk 的数量
-
当使用
cache
时,resolve(Loader).cache
默认为true
-
resolve(Loader).cacheWithContext
默认为false
-
~
node.global
默认为false
~(自 alpha.4 起被移除) -
resolveLoader.extensions
移除.json
(自 alpha.8 起) -
当 node-
target
时,node.global
中的node.__filename
和node.__dirname
默认为false
(自 alpha.14 起)
参考资料
[1]查阅迁移指南: https://github.com/webpack/changelog-v5/blob/master/MIGRATION%20GUIDE.md
[2]更新规范: https://github.com/WebAssembly/esm-integration
[3]Top Level Await: https://github.com/tc39/proposal-top-level-await
勘误
如对译文有疑问,欢迎评论或点击阅读原文,也可扫描下方二维码留言。
关注我们
扫描下方二维码关注我们,我们将提供前端相关最新最优含量的资讯。同时还能添加小助手加群与我们谈论哟~