在过去的几周里,我完成和合并了所有 webpack 4 的 PR ,其中有很多很大的变化。下面是一些重要的变化的总结,这样你在看到下边的更新日志的时候不会觉得惊讶。
Sets
在 API 层,现在很多类已经开始使用 Set(或者 SortableSet) 了。这个变化可能会破坏一些试着改变那些数组的插件。
Reason
原因
性能。“Deleting” 和 “Adding once” 操作的算法复杂度从 O(n) 降到 O(1) 了。
StackedSetMap
语法分析器 Parser 也开始使用数组/对象来跟踪重命名和定义变量动作了。这里的额外的挑战是 AST(Abstract Syntax Tree, 抽象语法树) 作用域的继承。以前我们只给数组添加了这个定义。当进入作用域时,我们把数组长度保存下来,这样当离开这个作用域时,我们可以把数组长度设置回这个值。这是非常有效的,因为数组没有被复制。对于对象,我们创建了一个原型链。
当用 Sets/Maps 和复制的时候性能下降同样是不可能的。所以我创建了一个新的类叫 stackedsetmap ,它结合了 Map 的原型链的优势。它是用一个 Map 堆来实现的。当进入到一个作用域时,来自当前的 map 堆被复制(浅拷贝),并且在上面添加一个新的 Map。添加元素的时候总是将它们添加到最上面的 Map。读取元素会遍历堆的所有 maps 来获取值,并将值缓存在最顶层的 map 中。删除一个值添加一个
thumbstone 对象作为值(感谢 LevelDB,推荐大家看一下它的数据结构)。Set 的版本可以在 Map 版本的上面实现。
数组推送的块加载
在 webpack 3 和更低版本的主分支中加载的方式如下:
第一个 bundle 文件(入口块) 包含了 webpack 运行环境和注册默认名称为 webpackJsonp 的全局函数。所有其他块在加载时调用这个函数。所以这和 JSONP 很相似,但是又不完全一样,因为它的内容不是 JSON 而是真正的 JS (主要函数)。
这种方法的问题是运行环境必须在任何其他块之前加载。→没有异步脚本,运行环境块包含了块的清单。
现在 webpack 4 使用了一种新的方式:
(window.webpackJsonp = window.webpackJsonp || []).push([...])
这并不需要从运行环境中注册全局函数。将参数 … push 进数组(如果不存在就创建)。运行环境使用块加载函数重写了数组的 “push” 函数,并从数组中处理所有 “排队” 项。
- 这允许块以任意顺序执行“块”(
<script async>),如果某些文件已经缓存,那就非常好了。 -
这允许把 webpack 运行环境放到任何块中。在很多情况下不再需要清单块,可以将运行环境放入应用程序块中,并保持 vendor 块被缓存。
无副作用的模块
我已经在上一篇博客中讨论了这个("Pure Modules")。这个标志位被重新命名为 "side-effects": false。可以看看这个 例子。
Deprecated stuff
过时的东西
The following API-things were removed: 下面的 API 已经被删除了:
module.loaders(替换成module.rules)Compilation.notCacheable- HMR
orignalError→originalError - loaderContext
resolveSync( 替换成resolve) -
只有一个字符串参数的 SourceMapDevToolPlugin
- loaderContext
options( →LoaderOptionsPlugin兼容不相容的 loaders,但最终 loaders 应该被修复)