返回首页

文件指纹是什么?怎么用?

问题解析

文件指纹是 Webpack 打包后输出文件名的后缀,用于解决浏览器缓存问题。通过给文件名添加唯一的哈希标识,可以在文件内容变化时强制浏览器重新加载资源。

核心概念

三种文件指纹类型

指纹类型 作用范围 特点
Hash 整个项目构建 任何文件修改都会导致所有 hash 变化
Chunkhash Webpack 打包的 chunk 不同 entry 生成不同的 chunkhash
Contenthash 文件内容 内容不变则 contenthash 不变,最精确

占位符说明

占位符 含义
[ext] 文件后缀名
[name] 文件名
[path] 文件相对路径
[folder] 文件所在文件夹
[contenthash] 文件内容的 hash
[hash] 模块标识符的 hash
[chunkhash] chunk 内容的 hash
[emoji] 随机 emoji 表情

详细解答

不同资源的指纹选择策略

// webpack.config.js
module.exports = {
  output: {
    // JS 使用 chunkhash:入口文件变化时,对应 chunk 的 hash 变化
    filename: 'js/[name]_[chunkhash:8].js',
    // 动态导入的 chunk 也使用 chunkhash
    chunkFilename: 'js/[name]_[chunkhash:8].js'
  },

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        use: {
          loader: 'file-loader',
          options: {
            // 图片使用 hash:通常图片内容独立,使用 hash 即可
            name: 'img/[name]_[hash:8].[ext]'
          }
        }
      }
    ]
  },

  plugins: [
    // CSS 使用 contenthash:CSS 内容变化时才改变 hash
    new MiniCssExtractPlugin({
      filename: 'css/[name]_[contenthash:8].css'
    })
  ]
};

三种 Hash 的详细对比

1. Hash(项目级)

// 不推荐:任何文件修改都会导致所有文件缓存失效
module.exports = {
  output: {
    filename: 'bundle_[hash:8].js'  // 项目任意文件修改,hash 都会变
  }
};

缺点

  • 无法利用浏览器缓存
  • 每次构建所有文件名都变化

2. Chunkhash(Chunk 级)

// 推荐用于 JS 文件
module.exports = {
  entry: {
    main: './src/main.js',
    vendor: './src/vendor.js'
  },
  output: {
    filename: '[name]_[chunkhash:8].js'
  }
};

优点

  • 不同入口文件独立计算 hash
  • 修改 main.js 不会导致 vendor.js 缓存失效

3. Contenthash(内容级)

// 推荐用于 CSS 文件
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name]_[contenthash:8].css'
    })
  ]
};

优点

  • 最精确的缓存控制
  • 只有内容真正变化时才改变文件名

深入理解

为什么 CSS 要用 Contenthash 而不是 Chunkhash?

// 场景:使用 MiniCssExtractPlugin 提取 CSS
// 如果 CSS 使用 chunkhash,会出现问题:

// main.js 修改了,但 main.css 内容没变
// 使用 chunkhash:main.css 的 hash 也会变(因为属于同一个 chunk)
// 使用 contenthash:main.css 的 hash 不变(因为内容没变)

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      // 正确做法:CSS 使用 contenthash
      filename: 'css/[name]_[contenthash:8].css'
    })
  ]
};

Hash 长度控制

module.exports = {
  output: {
    // :8 表示取 hash 的前 8 位
    // 长度越长,冲突概率越低,但文件名越长
    filename: 'js/[name]_[chunkhash:8].js'
  }
};

推荐长度

  • 开发环境:不需要 hash 或很短(如 4 位)
  • 生产环境:8-12 位(平衡唯一性和文件名长度)

最佳实践

完整的文件指纹配置

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: {
    app: './src/index.js',
    vendor: './src/vendor.js'
  },

  output: {
    path: path.resolve(__dirname, 'dist'),
    // JS 使用 chunkhash
    filename: 'js/[name]_[chunkhash:8].js',
    chunkFilename: 'js/[name]_[chunkhash:8].chunk.js',
    // 资源文件路径
    assetModuleFilename: 'assets/[name]_[hash:8][ext]'
  },

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        type: 'asset/resource',
        generator: {
          // 图片使用 hash
          filename: 'images/[name]_[hash:8][ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)$/,
        type: 'asset/resource',
        generator: {
          // 字体使用 hash
          filename: 'fonts/[name]_[hash:8][ext]'
        }
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin({
      // CSS 使用 contenthash
      filename: 'css/[name]_[contenthash:8].css',
      chunkFilename: 'css/[name]_[contenthash:8].chunk.css'
    })
  ]
};

缓存策略总结

资源类型          推荐指纹类型       原因
-------------------------------------------------
JS 入口文件       chunkhash         按入口独立缓存
JS 异步 chunk     chunkhash         按 chunk 独立缓存
CSS 文件          contenthash       按内容精确缓存
图片/字体         hash              内容独立,hash 足够

面试要点

  1. 三种文件指纹的区别:Hash(项目级)、Chunkhash(Chunk 级)、Contenthash(内容级)

  2. 使用场景

    • JS 文件使用 chunkhash
    • CSS 文件使用 contenthash
    • 图片等资源使用 hash
  3. 为什么 CSS 用 contenthash:避免 JS 修改导致 CSS 缓存失效,实现更精确的缓存控制

  4. 缓存优化原理:通过文件名变化强制浏览器重新加载,内容不变则利用缓存

  5. 注意事项

    • 提取 CSS 时务必使用 contenthash
    • 合理控制 hash 长度(推荐 8 位)
    • 配合 HTML 插件自动更新引用