// 在项目中我使用到了 crypto 模块,webpack5会询问是否引入对应的 polyfill。
Module not found: Error: Can't resolve 'crypto' in '/Users/xxx/Documents/private-project/webpack/ac_repair_mobile_webpack_5/node_modules/sshpk/lib/formats'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need these module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add an alias 'resolve.alias: { "crypto": "crypto-browserify" }'
- install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.alias: { "crypto": false }
使用webpack5后,项目运行始终报错:Uncaught ReferenceError: process is not defined. 这是因为webpack5 删减了node:{}的配置内容,并且将node.process 始终设为false。但是目前无法通过resolve.alias来给process指明polyfill。(buffer也同理)如果项目里用到了process这个node模块的话如何解决?
Persistent Caching
webpack4时代
从webpack4开始,我们需要指定配置的 mode 为
production
或develop
。当我们指定为production
的时候,webpack会将 optimization.minimize 的值置为 true,然后使用terser-webpack-plugin
来进行代码压缩:我们也可以覆盖webpack默认的
terser-webpack-plugin
的配置:我们也可以使用其他JavaScript压缩插件来替代
terser-webpack-plugin
,比如uglifyjs-webpack-plugin
。但是官方更推荐的是
terser-webpack-plugin
,因为uglifyjs-webpack-plugin
基于 uglifyjs,而 uglifyjs 不支持es6语法。也就是说,如果你需要压缩的代码具有es6代码的话,压缩就会失败。uglifyjs-webpack-plugin
为了支持es6的压缩曾经将uglifyjs换成了uglify-es,但由于uglify-es停止了维护,所以uglifyjs-webpack-plugin
又用回了uglifyjs。可以参考无论是
terser-webpack-plugin
还是uglifyjs-webpack-plugin
,我们都可以开启多线程parallel以及缓存cache来提高我们的打包效率。缓存会存放到 node_module/.cache/terser-webpack-plugin 或 node_module/.cache/uglifyjs-webpack-plugin 文件夹下。每当我们的webpack配置发送改变的时候,就会重新生成缓存。webpack5 的改变
到了webpack5 这一块并没有太大的变化,依旧是推荐使用
terser-webpack-plugin
来进行JS的压缩,但是我们除了可以使用插件plugin提供的cache机制外,webpack5 自身也提供了缓存机制webpack5 为了提高打包编译的速度,添加了cache特性。在development模式下默认会设为 cache: memory;production模式下会默认会取消该配置。我们可以通过设置:
来让webpack将缓存保存到本地硬盘中,默认保存的路径是 node_modules/.cache/webpack。这里要注意每当我们修改了webpack配置,记得更新cache的version,否则可能会出现因为重用了缓存导致配置没生效的问题。
Node.js Polyfills
在webpack5之前,webpack会自动的帮我们项目引入Node全局模块polyfill。我们可以通过node配置
但是webpack团队认为,现在大多数工具包多是为前端用途而编写的,所以不再自动引入polyfill。我们需要自行判断是否需要引入polyfill,当我们用weback5打包的时候,webpack会给我们类似如下的提示:
webpack5中,增加了resolve.alias配置项来告诉webpack是否需要引入对应polyfill。node配置项也做了调整。
也就是说到了webpack5,我们需要清楚自己的项目需要引入哪些node polyfill。更加了配置的门槛,但是减少了代码的体积。
node: {}
配置项来改成mock或不提供模块resolve.alias
配置项决定每个node模块是否引入polyfill问题
使用webpack5后,项目运行始终报错:Uncaught ReferenceError: process is not defined. 这是因为webpack5 删减了
node:{}
的配置内容,并且将node.process 始终设为false。但是目前无法通过resolve.alias
来给process指明polyfill。(buffer也同理)如果项目里用到了process这个node模块的话如何解决?Deterministic Chunk and Module IDs
在日常开发中,我们会对打包出来的代码文件加上哈希后缀,以便做版本管理。同时也带来了另一个问题:哈希改变导致缓存失效。我们需要尽量减少哈希改变的情况,这就是我们一直说的“优化持久化缓存”。一个最普遍的问题就是chunkId或moduleId的改变导致文件哈希后缀的改变。(业务逻辑没有变化的情况下)
比如,我们项目打包结构如下图:
当我们新增一个模块时:
所有文件的哈希后缀都发生了改变,不符合期望,vender~xxx.js的hash不应发生变化。
继续当我们新增一个入口的时候:
同样的所有文件的哈希后缀都发生了改变,不符合期望,原有文件hash不应发生变化。
webpack4可以通过设置optimization.moduleIds = 'hashed'与optimization.namedChunks=true来解决这写问题,但都有性能损耗等副作用。而webpack5 在production模式下optimization.chunkIds和optimization.moduleIds默认会设为'deterministic',webpack会采用新的算法来计算确定性的chunkI和moduleId。进而避免上述情况发生。
SplitChunks and Module Sizes
在项目中有时候我们需要将一些重复的公用代码或一些异步加载的代码提取出来从而对打包出来的代码进行体积或网络缓存方面的优化。webpack3的时候,我可以通过 CommonsChunkPlugin 来进行处理:
到了webpack4以及webpack5,我们可以通过 SplitChunksPlugin 来处理,我们利用它来对代码进行分割:
SplitChunksPlugin的默认配置是经过webpack团队经过大量测试精心挑选的较为通用的配置,对于我们大部分的项目我们直接使用默认配置即可,当然为了更大程度的利用代码分割的特性,我们可以将chunks修改为
chunks: 'all'
,这样webpack就会对我们应用的entry points以及import() 的模块进行分割处理。提取webpack runtime代码
另外还可以通过 optimization.runtimeChunk 配置将webpack运行时的代码提取出来,因为这部分代码理论上是不会变的。可以通过将这部分文件进行缓存。同时也可以以防万一避免这部分代码的改变导致其他提出出来的模块的哈希后缀发送变化而导致缓存失效。
最大化利用缓存
在日常开发中,我们还会给打包出来的文件加上哈希后缀,以便缓存以及版本管理。而添加哈希后缀有以下几种常规做法:
为了做到版本控制的同时最大化利用缓存,我们要避免每个文件之间的哈希后缀的耦合。每个文件的哈希后缀应该只与它自身的内容有关。使用 contenthash 可以在你修改了业务代码重新打包的时候,提取自node_modules以及webpack runtime的文件哈希后缀保持不变,继续利用缓存。而且在webpack5中,我们可以对
minSize
和maxSize
进行更详细的配置(而不是只能填一个数字),并且还可以设置js之外的文件类型的size:tree-shaking
webpack5的tree-shaking可以涵盖更多的场景:
在小型项目,或比较少问题的项目里感知不强。
总结:
等到webpack v5发布和相关生态跟上后,还是非常建议在新项目上去使用webpack5的。整体的效果就是: