webpack5新特性

175 阅读4分钟

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-utilsgetOptions()来获取,并带有校验功能。

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'