webpack中[hash]和[chunkhash]的目的是什么?

54

有人能告诉我[hash]和[chunkhash]的用途及其来源吗?

output: {
    path: "/home/proj/cdn/assets/[hash]",
    publicPath: "http://cdn.example.com/assets/[hash]/"
} 

1
是的,但它仍然不清楚它是为什么构建的。 - Stepan Suvorov
1
嗯...这里也有一个关于它的非常有趣的话题:https://medium.com/@okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95#.oibt9ye3h对你来说理解起来可能会很容易。 - The Reason
@StepanSuvorov 我相信你现在已经弄清楚了,但也许我的答案可以帮助其他人理解这个问题。 - szegheo
2个回答

99

有一件事对我来说并不明显,所以我认为它值得更详细的解释。

官方文档的说法:

官方文档中对于它们目的的简要描述:

确保浏览器捕捉到已更改的文件的一种简单方法是使用 output.filename 替换。可以使用[hash]替换,在文件名中包含特定于构建的哈希,但更好的方法是使用[contenthash]替换,它是文件内容的哈希值,每个资源都不同。

官方文档output.filename的另一个逐个解释:

  • [hash] 是“每次构建生成的唯一哈希”
  • [chunkhash] 基于“每个块的内容”
  • [contenthash] 是“提取内容生成的哈希”

让我们通过示例使其更易理解:

在我的src目录下有3个文件:index.js, index.css, vendors.js

来自我的示例Webpack配置的相关部分:
(不是完整且可工作的配置!)

entry: {
  index: ["./src/index.js", "./src/index.css"],
  vendors: ["./src/vendors.js"]
},
output: {
  filename: "[name].[hash].js"
}
plugins: [
  new MiniCssExtractPlugin({
    filename: "[name].[hash].css"
  })
]

我有两个块名称,一个是index,另一个是vendors。但要注意的是,index块也将具有css内容,因为它在数组中导入了一个css文件。构建时,使用MiniCssExtractPlugin(在我的情况下)将css部分导出到单独的文件中,但Webpack知道index.jsindex.css属于同一块。

现在让我们尝试使用不同的哈希类型进行构建。(同样更改两个filename选项)

使用[hash]:

enter image description here

每个文件都具有相同的哈希值,因为[hash]是基于我们使用的所有源文件生成的。如果我重新运行构建而没有更改任何内容,则生成的哈希值将保持不变。如果我仅编辑一个文件,那么哈希值将更改,并且所有生成的捆绑包都将在其名称中具有此新哈希。

使用[chunkhash]:

enter image description here

正如您所看到的,第一个和第二个文件来自同一个index块,因此它们在名称中具有相同的哈希值。这是因为[chunkhash]是基于给定块的整个内容生成的。因此,如果我编辑了index.css并重新构建,则来自index块的文件将具有新的哈希值,但来自vendors块的哈希值将保持不变。

使用[contenthash]:

enter image description here

这很明显。每个生成的文件在其名称中具有唯一的哈希值,该哈希值是从该文件的内容计算出来的。如果我更改了index.css并重新构建,则只有生成的index.css将具有新的哈希值。


4
由于我使用了哈希值,我的用户总是得到更新后的应用程序版本,但缺点是,除非按Ctrl + F5刷新页面,否则当应用程序被拆分成代码并尝试动态提取旧版本/哈希(显然不再存在)的JS文件时,用户可能会遇到控制台错误。有没有什么最佳实践解决方法? - van_folmert
1
我认为最佳实践是在推送新代码并为非静态文件(如index.html)指定Cache-Control: no-cache之前不清空公共文件夹。 - sallf
@szegheo 你需要始终对主要的main.js文件进行缓存爆破。因此,每当任何块发生更改时,您肯定需要将版本控制添加到主js文件中。例如 main.js?v=new1.2 - Emmanuel David

11

这基本上与浏览器缓存有关 - 当您提供资源时,通常希望告诉客户端/浏览器他们可以重复使用相同的脚本/样式表/JPEG等,而不必每次都下载它。这是通过发送适当的HTTP标头字段来完成的。

然后问题就是应该告诉客户端他们可以继续使用相同的样式表多久时间?如果您重新设计您的网站,而他们没有下载新的样式表,他们将看不到这些更改。解决方案通常是向样式表文件名添加某种标识符或版本号 - 如果此id /版本在样式表更改时更改(因此文件名不同),则浏览器将再次下载它(这称为缓存破坏)。

基本上,webpack可以向捆绑输出名称添加哈希值,这个哈希值作为捆绑内容的函数会随着内容的更改而不同 - 从而自动化过程。chunkhash对于将捆绑拆分为多个块的情况也起到相同的作用。

以下是一些与webpack无关的讨论:破坏缓存的CSS策略


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接