webpack 完全指南:文件指纹策略

2,500 阅读3分钟

什么是文件指纹?

01.png

如果在网上冲浪的时候,你打开过 chrome 的控制台,可能会看到上图这样的文件名,其中的一串数字后缀就被称之为“文件指纹”。

为什么需要文件指纹?

文件指纹通常有两个用途:

  • 版本管理: 在发布版本时,通过文件指纹来区分 修改的文件 和 未修改的文件。
  • 使用缓存: 未修改的文件,文件指纹保持不变,浏览器继续使用缓存访问。

常见的文件指纹

在了解文件指纹之前,我们需要先认识一下 webpack 的 CompilerCompilation

Compiler 模块是 webpack 的主要引擎,在 webpack 首次启动时会返回一个 Compiler 实例,而 Compiler 通过 Compilation 模块可以创建新的 compilation 实例,这个 compilation 实例能够访问依赖图中所有模块,也就是说项目中的任一文件的变化都会引起 compilation 实例的变化。

Hash

Hash 是和整个项目的构建相关,compilation 实例的变化就会触发 Hash 的变化。

Chunkhash

Chunkhash 是和 webpack 打包的模块相关,每一个 entry 作为一个模块,会产生不同的 Chunkhash 值,所以他们之间的变化是互不影响的。

Contenthash

Contenthash 是和根据文件内容相关,比如一个页面内的 JS 内容、CSS 内容都会拥有自己的 Contenthash,可以保持各自的独立更新。

文件指纹设置

我们在配置文件(webpack.config.js)中,通过占位符设置文件指纹。

占位符

名称含义
[ext]资源后缀名
[id]文件标识符
[name]文件名称
[path]文件的相对路径
[folder]文件所在的文件夹
[hash]模块标识符的 hash
[chunkhash]chunk 内容的 hash
[contenthash]文件内容的 hash
[query]文件的 query,例如,文件名 ? 后面的字符串
[emoji]一个随机的指代文件内容的 emoji

JS 文件

使用 [chunkhash] 设置 outputfilename

// webpack.config.js

module.exports = {
  // ...
  entry: {
    app: "./src/app.js",
    index: "./src/index.js",
  },
  output: {
    filename: "[name][chunkhash:8].js",
    // ...path
  },
};

CSS 文件

当我们使用 style-loader 编译 CSS 文件时,内容会被放置在 <style> 标签内,并插入 <head> 里,这样在打包后是得不到一个独立的 CSS 文件。所以,我们想要的到独立的 CSS 文件不能使用 style-loader ,并且需要借助一个插件从每个包含 CSS 的 JS 文件中提取出 CSS 文件 -- MiniCssExtractPlugin,然后使用 [contenthash] 设置 MiniCssExtractPluginfilename

先安装一下 MiniCssExtractPlugin

npm install mini-css-extract-plugin -D

建议 MiniCssExtractPlugincss-loader 一起使用。

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

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name][contenthash:hash].css",
    }),
  ],
};

图片、字体等

文件解析篇 一样,我们还是从两种方式 file-loader(webpack 4) 和 资源模块(webpack 5)介绍图片、字体等资源的文件指纹设置。

file-loader

使用 [hash] 设置 file-loadername

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.png/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "images/[name][hash:8].[ext]",
            },
          },
        ],
      },
    ],
  },
};

资源模块

默认情况下,asset/resource 模块以 [hash][ext][query] 文件名发送到输出目录,可以通过在 webpack 配置中设置。

设置统一的文件指纹:

// webpack.config.js

module.exports = {
  // ...
  output: {
    // ...filename, ....path
    assetModuleFilename: "images/[hash][ext][query]",
  },
};

也可以单独设置文件指纹:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.png/,
        type: "asset/resource",
        generator: {
          filename: "static/[hash][ext][query]",
        },
      },
    ],
  },
};

webpack 系列