webpack5新增了很多新的特性,对Node.js版本有要求,最低版本是10.13.0
功能清除
所有在webpack4中被废弃的功能都会被清除,因此要确保webpack4没有打印警告。
清理配置
rules配置
在webpack5之前,我们会用到各种loader来进行转译,例如:raw-loader用于将文件导入为字符串、url-loader将文件作为data URI内联到bundle中和file-loader将文件发送到输出目录等,如下:
module.exports = {
module: {
rules: [
{
test: /.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
}
}
]
}
]
}
}
data URI也稍微提下,url-loader会将图片等资源直接编译成某格式填充到引入的地方。这样好处很明显,不会受引用路径的影响,因为直接指向的是资源本身。示例如下:
<img src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" alt="star" width="16" height="16">
以上是webpack5之前的用法,在webpack5中用了个资源模块类型的概念来替换所有这些loader:
- asset/resource:发送一个单独的文件并导出URL,相当于
file-loader的功能 - asset/inline:导出一个资源的data URI,就是
url-loader的功能 - asset/source:导出资源的源代码,可以替换
raw-loader - asset:意思是在导出一个资源
data URI和发送一个单独的文件并导出URL两者之间自动选择,相当于url-loader,但配置了体积的限制,如果超过了配置的体积大小,就单独生成独立的文件。
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /.png/,
type: 'asset/resource'
}
]
}
}
新增内置getOptions方法
在扩展loader插件的时候,我们可以通过内置的loader上下文调用this.getOptions()来获取参数。之前,常用的是使用schema-utils的getOptions()来获取,并带有校验功能。
loader-utils在早期版本中也支持getOptions()方法获取插件配置的参数,在3.x版本开始就废弃了这种获取方式,在webpack5之前的版本,可以直接通过上下文this.query来实现。而到了webpack5,内置了getOptions()方法,它本质上是使用 Node 原生的querystring方法进行解析。对于获取之后的各种校验,可以自定义来完成。
polyfill
Webpack5不再为Node.js模块引入polyfill。在之前的版本,如果某个模板依赖Node.js里面的核心模块,那这个模块被引入时会把Node.js整个polyfill一起带过来编译,这样最后打包后的体积就会比较大。
比如crypto这个库,是Node.js提供的,只能运行于Node环境中,在浏览器运行就会报错,在webpack5之前构建的时候,会打入大量的polyfill代码,目的就是为了让这个库能在浏览器中正常运行。如果现在是用webpack5来构建的话,在浏览器运行就会报错。
类似这种情况,官方推荐就是避免使用。当然还有其他方法,在package.json中可以配置替换项,如:
"browser": {
"crypto": "crypto-js"
}
长期缓存
用webpack打包项目,一般都会在文件名后面加上一串数字,也叫做文件指纹,作用是解决缓存问题,因为每次构建部署后文件名都相同,浏览器就还是会请求老的文件,而不会更新,就造成了严重的缓存问题。文件指纹就是一串hash值,常用的hash有三种:hash、chunkhash和contenthash。
三者的区别是:
- hash:只要项目中有一个文件发生了改变,再次构建时hash值都会变化
- chunkhash:某个chunk下的文件发生了改变,则该chunkhash会变化
- contenthash:颗粒度更小,仅修改的那个文件的hash值会变化,而对应的chunk都不受影响
不能以颗粒度影响的大小乱配hash类型,一般contenthash用于css样式文件,如果配置到js文件:[name].[contenthash].js,那它引用的css文件变化了,而本身没变的话,那就有缓存了。
这三种模式是不是对缓存利用的不够,当某个文件一直未修改时,它的文件指纹会不会也经常被动变化了,根据上面的分析完全有可能。而长期缓存优化的就是这个问题,当某个文件一直未被修改时,则文件指纹不会被修改。
在生产模式下,默认:
chunkIds: 'deterministic' // deterministic 默认最小3位数字
moduleIds: 'deterministic'