webpack学习记录(3)-文件指纹

325 阅读4分钟

前言

我们知道,为了优化体验,浏览器在加载资源时,有缓存机制。当浏览器判断待加载资源没有更新时,就从缓存中获取文件资源。

一般通用的方法是将资源设置为强制缓存,并给资源名称添加后缀值。当资源有更新时,修改其后缀值,重新获取HTML页面时,就可以实现资源的更新。

在webpack中,我们可以通过配置来实现自动给资源文件添加后缀值,即文件指纹。

配置文件指纹

我们在webpack中,通过outputfilenames属性,可以设置输出文件的名称。比如我们配置如下:

// index.js
console.log('hello world!');

// main.js
console.log('hello webpack!');

// webpack.prod.config.js
entry: {
    index: './src/index.js',
    main: './src/main.js',
},
output: {
    filename: '[name].js', // [name]是表示模块名称,对应entry的模块
    path: path.resolve(__dirname, 'dist')
}

则构建出来的文件如下所示:

hash

那么,我们怎么给文件添加文件指纹呢?这里我们需要使用[hash],来重新设置下filenames属性:

entry: {
    index: './src/index.js',
    main: './src/main.js',
},
output: {
    filename: '[name].[hash].js',
    path: path.resolve(__dirname, 'dist')
}

再次打包构建后,可以看到生成的文件已经自动添加了hash值。

但是,生成的这两个bundle文件,都有相同的hash值。这是个什么原因呢?在官网中,我们可以看见对[hash]的描述:

模块标识符(module identifier)的 hash

那么,什么是模块标识符?我们知道,webpack是一个打包编译的过程,这个标识符,标识的就是这个打包的过程。所以,在这个打包编译过程中生成的bundle文件,都具有统一的hash值。

并且,如果我们修改其中一个js文件,再次打包的话,则会将两个bundle文件的hash值一起修改,那么我们缓存的目的将失效。

chunkhash

我们了解了[hash]无法解决我们缓存的目目的,那么我们应该怎样解决这个问题?这里就需要[chunkhash]登场了。

我们先看下[chunkhash]的官方描述:

chunk 内容的 hash

在webpack中,chunk指代的是模块,所以,chunkhash就是模块的hash,会按照每个模块内容计算hash。

我们重新配置下filenames属性:

entry: {
    index: './src/index.js',
    main: './src/main.js',
},
output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
}

再次打包构建后,我们可以看见重新构建完成的bundle文件的hash值是不一样的。

contenthash

上面我们通过配置[chunkhash],来达到我们对js文件资源的缓存意义。

但是,在项目中不仅仅只有js文件,还有css文件和图片等静态资源。现在我们将入口文件index.js及其对应的依赖文件index.css打包在同一个模块,使用相同的chunkhash。若对应css改变,则构建出来的bundle文件的的chunkhash也会随之改变,但入口文件xx.js的内容并没有改变,所以没有完全达到缓存意义。

这里,我们首先需要将css从bundle文件抽离出来,这里我们使用插件mini-css-extract-plugin来达到我们的目的。

// webpack.prod.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /.css$/,
                use: [
                  MiniCssExtractPlugin.loader,
                  'css-loader'
                ],
            }
        ],
    },
    plugins: [
        new MiniCssExtractPlugin(),
    ],
}

这时,我们可以看见css已经单独抽离:

接下来,我们需要给css文件添加hash值。这里我们需要了解下[contenthash][contenthash]表示根据文件内容生成hash值,内容不同hash值不同。

// webpack.prod.config.js
plugins: [
    new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
    }),
],

注:我们需要在MiniCssExtratPlugin中设置filename

再次打包,就可以看见生成的css的hash值和js的hash值不同。

这样设置之后,我们单独修改css的话,也只会重新生成css的hash值,而不会修改js的hash。

图片的hash

我们在webpack中,通过file-loaderurl-loader来处理图片,这时设置图片的hash,需要注意的是[hash]表示的是根据文件内容生成hash

官网说明可以点击这里

总结

通过webpack设置文件指纹,达到缓存目的的一般方法:

  • js: 配置outputfilenames属性,文件指纹设置为[chunkhash]
  • css: 使用MiniCssExtratPlugin抽离文件,文件指纹设置为[contenthash]
  • 图片: 使用file-loaderurl-loader,文件指纹设置为[hash]

参考