webpack打包缓存_【第835期】Webpack 的静态资源持久缓存

原标题:【第835期】Webpack 的静态资源持久缓存

前言

你现在还在休假吗?早读课节前以web pack漫谈结尾,今年就以web pack开始吧。今日早读文章由众成翻译@yanni4night带来的翻译。

正文从这开始~

Webpack 是一个将你的所有 Java、CSS 甚至图片这样的静态资源打包的好方法,但是为了在生产环境中更有效地使用生成的资源,应该考虑使用持久缓存。

摘录

使用 webpack 开启静态资源的持久缓存:

使用 [chunkhash] 为每个文件增加一个内容相关的缓存清道夫;

使用编译统计在 HTML 中获取资源时取得文件名;

生成 JSON 格式的模块清单文件,并在 HTML 页面加载资源之前内联进去;

保证包含启动代码的入口块不会对于同样的依赖生成不同的哈希值;

开始收益!

问题

每次代码需要更新时,服务器必须重新部署,客户端也必须重新下载资源。因为从网络中获取资源会很慢,这显然非常低效。这就是为什么浏览器会缓存静态资源的原因。但是有一个缺陷:如果在部署新的版本中不修改文件名,浏览器会认为它没有更新,就会使用缓存中的版本。

可能告诉浏览器有更新的最简单方式是修改资源的文件名。在 webpack 之前的时代,我们一般在文件名后面追加参数,每次递增:

使用 webpack 就简单多了:每次构建时 webpack 都会生成一个唯一的哈希值,可用于组合到文件名中。下面的配置示例会生成2个在文件名中带哈希值的文件(每个都有入口):

使用这个配置运行 webpack 会生成下面的输出:

但是这种做法的问题是,每次构建,所有文件的的文件名都会被修改,客户端必须重新下载所有的代码。

并不是我们想要的,是吧?那么我们如何保证客户端总是获取到最新的版本,但不需要下载所有的资源?

为每个文件生成唯一的哈希值

如果文件内容不变,生成的文件名就不变会如何?比如说,依赖库文件以及其它不常变化的依赖之类的东西。

专业建议!

使用 CommonsChunkPlugin 区分你的依赖库和应用代码,显式创建一个依赖库的包,防止更新过多。

Webpack 允许根据文件内容生成哈希值。下面是新的配置:

这个配置也会生成两个文件,但是在这个例子中,每个文件会独立地得到唯一的哈希值。

专业建议!

不要在开发环境中使用 [chunkhash],因为它会增加编译时间。区分开发和生产环境的配置,使用 [name].js 应用于开发,使用 [name].[chunkhash].js 用于生产。

由于 Webpack 的一个问题,该生成哈希值的方法并不是确定的。保证哈希值是根据文件内容生成的,请使用 webpack-md5-hash 插件。这里是使用示例:https://github.com/okonet/webpack-long-term-cache-demo/pull/3/files。

根据 webpack 统计获取文件名

在开发模式下,在 HTML 中直接引用 Java 文件:

因此,每次在生产环境中构建时,我们会得到不同的文件名。类似这样:

为了在 HTML 中引用到正确的文件,我们需要知道构建的一些信息。可以使用一个简单的插件从 webpack 的编译统计中导出这些信息:

也可以使用 https://www.npmjs.com/package/webpack-manifest-plugin 或者 https://www.npmjs.com/package/assets-webpack-plugin 导出 JSON 文件。

在我们的配置下的 webpack-manifest-plugin 的一个输出看起来是:

剩下的就依赖你的服务器设置了,但我相信非常简单。如果你使用 Rails,这是一篇最佳指南。或者你的应用不依赖于任何服务端渲染技术,生成一个单独的 index.html 就足够了,那么建议使用下面两个称赞的插件,https://github.com/ampedandwired/html-webpack-plugin 和 https://github.com/szrenwei/inline-manifest-webpack-plugin,它们会显著地简化设置。

你会认为,到此为止了。然而,还没完。

确定性的哈希值

为了减少生成文件的体积,webpack 使用了标识符而不是文件名。在编译期,标识符是生成的,对于于模块的文件名,并放置于叫做 chunk manifest 的 Java 对象中。它(带着一些启动代码)被置于入口模块中,对于被 webpack 打包的代码来说极其关键。

问题与之前相同:当我们更改了代码的任何一部分,即使剩下的文件内容没有被修改,入口也会被更新以放入新的清单。这样反过来也就导致新的哈希值,影响了长期缓存。

为了修复这个问题,我们应该使用 chunk-manifest-webpack-plugin 插件来把清单导出到单独的 JSON 文件中。这是更新后的 webpack.config.js,它会在构建目录下创建 chunk-manifest.json 文件:

因为我们从入口模块中移除了清单,现在我们要把它提供给 webpack。你也许在上面的例子中注意到了 manifestVariable 选项。这是 webpack 寻找清单 JSON 的全局变量,因此它必须在 HTML 中出现在打包文件的前面。把 JSON 的内容内联进 HTML 很简单。HTML 的 head 部分应该是这样的:

第二个问题是 webpack 如何获取模块:默认地对于同样的依赖集合,模块在包中的顺序不是确定的。意思是:在两次构建之间,模块可能获取到不同的标识符,导致不同的内容,也就有了不同的哈希值。这是出现在 Github 上的 issue,建议使用 OccurenceOrderPlugin 来解决这个问题。

Webpack 2.0 已经修复了此问题,现在是 beta 阶段,如果你已经在使用了,就可以安全地移除 OccurenceOrderPlugin。

最后的 webpack.config.js:

使用了这个配置,依赖包就不会更改哈希值,除非你修改了代码或依赖。下面是两次构建的输出,期间修改了 moduleB.js:

注意依赖包有相同的名字,正是我们所需要的!

结论

Webpack 模块化程序很高,有很多优化在默认下都没有开启。Webpack 提供的灵活性是的任何可以想到的设置成为可能,但是要记住长期缓存是一个常用的优化实践,我希望 webpack 的下一个版本能够默认地让这些事情更容易做到。

关于本文

译者:@yanni4night

译文:http://www.zcfy.cc/article/long-term-caching-of-static-assets-with-webpack-1204.html

原文:https://medium.com/@okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95#.pi3t982sz返回搜狐,查看更多

责任编辑:

你可能感兴趣的:(webpack打包缓存)