Webpack5更新指南
2020-10-10 Webpack5 正式 realease 相较于 Webpack4 已经过了两年多了.在这期间并没有什么重大的改变,因为同学们并不喜欢重大的改变尤其是像 Webpack 这种你一年可能就用两次. 但由于没有去做一些重大的改变,我们不能去做一些重要的 api 和
架构上的改变来提升效率,所以 Webpack5 出现了.
这次主要在这几点上:
- Improve build performance with Persistent Caching (通过使用持久性缓存来提高构建性能)
- Improve Long Term Caching with better algorithms and defaults.(通过算法和默认设置来提升长期缓存)
- Improve bundle size with better Tree Shaking and Code Generation.(通过更好的 Tree Shaking 和代码生成来压缩包大小)
- Improve compatibility with the web platform. (提升网络平台的兼容性)
- Clean up internal structures that were left in a weird state while implementing features in v4 - without introducing any breaking changes.(清除一些内部架构,这些架构在v4版本中很奇怪.但并不会引起重大的改变)
- Prepare for future features by introducing breaking changes now, allowing us to stay on v5 for as long as possible. (为了以后的release,我们现在引入了一些重大的改变,使我们可以在v5停留尽可能长的时间)
既然官方都说了要待一段时间我们就好好学吧,反正早用早享受!!!
我们先从这几个重大的变化娓娓道来
Improve build performance with Persistent Caching
Webpack5官方并没有将 Persistent Caching作为默认设置,而是需要我们去配置.因为Webpack5更主张安全而不是效率.不希望因为提升95%的表现而导致5%的出错.
当我们设置cache.type为 filesystem时 相对于webpack4 我们多了以下几点。
buildDependencies
buildDependencies指定构建过程的代码依赖性.让webpack负责解析和遵循指定值的依赖项.
官方推荐设置为 [__filename].
[__filename] depends在你的config文件.
当你任何使用require()的module发生改变时Persistent Caching就会无效.
module.exports = {
cache: {
buildDependencies: {
// This makes all dependencies of this file - build dependencies
config: [__filename]
// By default webpack and loaders are build dependencies
}
}
};
如果是类似fs.readFile的话就不会
version
一些build的依赖是不能压缩成文件的像从数据库读取数据或者环境变量.对于这些值我们可以使用version
我们可以通过传递不一样的string来使Persistent Caching无效
如果你的config读取环境变量GIT_REV并且使用DefinePlugin来嵌入打包. 我们就可以将GIT_REV作为依赖.
仅当将cache.type设置为filesystem时,cache.version才有意义
cache: {
version: `${process.env.GIT_REV}`
}
name
传送门
cache的名字,不同的名字将会导致不同的共存缓存。当具有多个应该具有独立缓存的配置时,使用cache.name才有意义
仅当将cache.type设置为filesystem时,cache.name才有意义
store
传送门
cache.store告诉了webpack什么时候存储data在filesystem
'pack':当编译器空闲时,将所有缓存项的数据存储在单个文件中
仅当将cache.type设置为filesystem时,cache.store选项才可用
module.exports = {
//...
cache: {
type: 'filesystem',
store: 'pack'
}
};
cacheDirectory
传送门
缓存的基本目录 默认node_modules/.cache/webpack
仅当将cache.type设置为filesystem时,cache.cacheDirectory选项才可用
最终路径为cache.directory + cache.name
const path = require('path');
module.exports = {
//...
cache: {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, '.temp_cache')
}
};
cacheLocation
传送门
cache路径 默认path.resolve(cache.cacheDirectory, cache.name).
仅当将cache.type设置为filesystem时,cache.cacheLocation才可用
const path = require('path');
module.exports = {
//...
cache: {
type: 'filesystem',
cacheLocation: path.resolve(__dirname, '.test_cache')
}
};
Improve Long Term Caching with better algorithms and defaults.
确定的 Chunk、模块 ID 和导出名称
这些是自动加入生产模式的
chunkIds: "deterministic" moduleIds: "deterministic" mangleExports: "deterministic"
该算法以确定性方式为modules和chunks 分配短(3或5位数字)数字ID,并为导出分配短(2个字符)名称。这是包大小和长期缓存之间的折衷方案。
真正的content hash
之前只是使用内部结构的哈希值。当只有注释被修改或变量被重命名时,这对长期缓存会有积极影响。这些变化在压缩后是不可见的。
Improve bundle size with better Tree Shaking and Code Generation.(通过更好的 Tree Shaking 和代码生成来压缩包大小)
嵌套的 tree-shaking
传送门
webpack 现在能够跟踪对导出的嵌套属性的访问。这可以改善重新导出命名空间 对象时的 Tree Shaking(清除未使用的导出和混淆导出)。
// 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会被删除
内部模块的 tree-shaking
webpack 4 没有分析模块的导出和引用之间的依赖关系。webpack 5 有一个新的选项 optimization.innerGraph,在生产模式下是默认启用的,它可以对模块中的标志进行分析,找出导出和引用之间的依赖关系。
import { something } from './something';
function usingSomething() {
return something;
}
export function test() {
return usingSomething();
}
innerGraph会找出 something 只有在使用 test 导出时才会使用。这允许将更多的出口标记为未使用,并从代码包中省略更多的代码。
当设置"sideEffects": false时,可以省略更多的模块。在这个例子中,当 test 导出未被使用时,./something 将被省略。
要获得未使用的导出信息,需要使用 optimization.unusedExports。要删除无副作用的模块,需要使用optimization.sideEffects。可以分析以下标记:
- 函数声明
- 类声明
- 默认导出export default 或定义变量以下的:
- 函数表达式
- 类表达式
- 顺序表达式
- /#PURE/ 表达式
- 局部变量
- 引入的捆绑(bindings)
使用 eval() 将为一个模块放弃这个优化,因为经过 eval 的代码可以引用范围内的任何标记。这种优化也被称为深度范围分析。
CommonJs Tree的 Shaking
传送门
webpack used to opt-out from used exports analysing for CommonJs exports and require() calls.
webpack 5 增加了 一些CommonJs 构造的支持,允许消除未使用的 CommonJs 导出,并从 require() 调用中跟踪引用的导出名称。
以下结构是支持的:
- exports|this|module.exports.xxx = ...
- exports|this|module.exports = require("...") (reexport)
- exports|this|module.exports.xxx = require("...").xxx (reexport)
- Object.defineProperty(exports|this|module.exports, "xxx", ...)
- require("abc").xxx
- require("abc").xxx()
- importing from ESM
- require() a ESM
- flagged exportType (special handling for non-strict ESM import):
- Object.defineProperty(exports|this|module.exports, "__esModule", { value: true|!0 })
- exports|this|module.exports.__esModule = true|!0
- It's planned to support more constructs in future
当检测到不可分析的代码时,webpack 会放弃,并且完全不跟踪这些模块的导出信息(为了性能考虑)。
一般的Tree Shaking提升
传送门
export * 已得到改进,可以跟踪更多信息,并且不再将默认导出标记为已使用。
export * 当webpack确定出口冲突时,将显示警告。
import()允许通过/ * webpackExports:[“ abc”,“ default”] * /魔术注释来手动tree shake。
Improve compatibility with the web platform.
webpack 5停止了nodejs中的polyfill并且专注于前端兼容模块。
我们的目标是提高与Web平台的兼容性,在Web平台上,Node.js核心模块不可用。
参考文档:
introducing-federated-modules-in-webpack-5
module-federation-guide-offical
persistent-caching-guide-offical
webpackv5-realease-changelog
精读module-federation