原创翻译,转载请注明出处。
原文地址:https://webpack.js.org/guides/caching/
为了使webpack生成的静态资源能长时间的缓存:
- 使用[chunkhash],为每一个文件添加一个基于内容的cache-buster。
- 把webpack的对象清单提取到单独的文件里。
- 确保在依赖群没有发生变化的时候,包含启动引导指令代码的入口点代码块不会更改哈希值。
- 使用编译器统计来获得在HTML里请求的资源的名称。
- 生成代码块的清单JSON,并且在加载资源之前把它写入到HTML页面里。
问题
每一次我们的代码需要更新的时候,它们都需要在服务器上再次发布,然后由所有的客户端再次下载。这很明显非常低效因为通过网络获取资源将可能会很慢。这就是浏览器缓存静态文件的原因。
这种处理方式有个问题:如果我们部署新版本的时候没有更改资源文件名,浏览器会认为它没有被更新,所以客户端会得到一个缓存的版本。
告诉浏览器去下载新版本的一个简单的做法就是更改资源名称。在webpack之前,我们经常在文件名上加一个构建号作为参数,然后累加:
application.js?build=1 application.css?build=1
在webpack里会更容易。每一次webpack编译的时候都会生成一个独一无二的哈希值,把它放在output的占位符里,来构成文件名。下面的配置示例会生成2个文件名里包含哈希值的文件(每个入口文件生成一个):
// webpack.config.js const path =require("path"); module.exports ={ entry:{ vendor:"./src/vendor.js", main:"./src/index.js" }, output:{ path: path.join(__dirname,"build"), filename:"[name].[hash].js" } };
用这个配置运行webpack时会产生下面的输出:
Hash: 2a6c1fee4b5b0d2c9285 Version: webpack 2.2.0 Time: 62ms Asset Size Chunks Chunk Names vendor.2a6c1fee4b5b0d2c9285.js 2.58 kB 0 [emitted] vendor main.2a6c1fee4b5b0d2c9285.js 2.57 kB 1 [emitted] main [0] ./src/index.js 63 bytes {1}[built] [1] ./src/vendor.js 63 bytes {0}[built]
这里有个问题,任何一个文件更新之后的编译,会更新所有文件名,客户端不得不再次下载所有代码。我们怎么能确保客户端不用通过下载所有资源就总会得到最新版本的资源?
为每一个文件生成唯一的哈希值
如果文件的内容在两次编译之间没有发生变化,我们生成了同样的文件名将会怎样呢?例如,当依赖没有更新,只有应用代码被更新了,那么它将不需要再次下载vendor文件。
Webpack通过把占位符[hash]替换成[chunkhash],允许你根据内容来生成哈希值。这里是更新后的配置:
module.exports = { /*...*/ output: { /*...*/ - filename: "[name].[hash].js" + filename: "[name].[chunkhash].js" } };
这个配置也会生成两个文件,但是在这里,每一个文件都回得到属于它们自己的唯一哈希值。
Hash: cfba4af36e2b11ef15db Version: webpack 2.2.0 Time: 66ms Asset Size Chunks Chunk Names vendor.50cfb8f89ce2262e5325.js 2.58 kB 0 [emitted] vendor main.70b594fe8b07bcedaa98.js 2.57 kB 1 [emitted] main [0] ./src/index.js 63 bytes {1}[built] [1] ./src/vendor.js 63 bytes {0}[built]
从webpack编译统计信息里得到文件名一览
在开发模式时,你只需在HTML文件里引用以入口点名字命名的文件。
<script src="vendor.js"></script> <script src="main.js"></script>
但是,每次编译产品时,我们会得到不同的文件名。有时它们看起来像这样:
<script src="vendor.50cfb8f89ce2262e5325.js"></script> <script src="main.70b594fe8b07bcedaa98.js"></script>
为了在HTML里引用正确的文件,我们需要得到编译信息。使用下面的插件就可以从webpack编译统计信息里提取出来。
// webpack.config.js const path =require("path"); module.exports ={ /*...*/ plugins:[ function(){ this.plugin("done",function(stats){ require("fs").writeFileSync( path.join(__dirname,"build","stats.json"), JSON.stringify(stats.toJson())); }); } ] };
从下面插件里选取一个来导出JSON文件:
- https://www.npmjs.com/package/webpack-manifest-plugin
- https://www.npmjs.com/package/assets-webpack-plugin
在配置里使用WebpackManifestPlugin时的输出例子:
{ "main.js":"main.155567618f4367cd1cb8.js", "vendor.js":"vendor.c2330c22cd2decb5da5a.js" }
确定的哈希值
为了让生成文件最小化,webpack用识别码取代模块名称。在编译的时候,生成识别码,映射到代码块的文件名,然后被放到一个叫代码块清单的JavaScript对象里。为了生成保留在整个编译期里的识别码,webpack提供了NamedModulesPlugin(推荐开发使用)和HashedModuleIdsPlugin插件(推荐产品使用)。
代码块清单然后被(连同引导指令代码,运行代码)放到入口代码块里,它对用webpack打包代码的运行至关重要。
和之前的问题一样:不管何时我们更改代码的任何部分,即使其他内容没有被改过,它将更新入口代码块,包含新的清单信息。这样的话就会生成一个新的哈希值,也就不能长期缓存了。
为了解决这个,我们应该使用ChunkManifestWebpackPlugin插件,它会把清单信息提取到一个独立的JSON文件里。在webpack运行时代码里,通过一个变量代替代码块清单信息。但是我们可以做的更好;通过使用CommonsChunkPlugin插件把运行时代码提取到独立的入口文件。下面是更新后的webpack.config.js,将会在编译路径下生成清单信息文件和运行时代码文件。
// webpack.config.js var ChunkManifestPlugin =require("chunk-manifest-webpack-plugin"); module.exports ={ /*...*/ plugins:[ /*...*/ newwebpack.optimize.CommonsChunkPlugin({ name:["vendor","manifest"],// vendor libs + extracted manifest minChunks:Infinity, }), /*...*/ newChunkManifestPlugin({ filename:"chunk-manifest.json", manifestVariable:"webpackManifest" }) ] };
我们把清单信息从入口代码块移走之后,下一步我们需要做的是把它提供给webpack。上面例子里的manifestVariable配置定义了一个全局变量的名字,webpack用它来查找保存清单信息的JSON文件。它应该定义在HTML请求代码包之前。通过在HTML文件里内嵌JSON的内容来实现。我们的HTML文件的头部看起来像这样:
<html> <head> <script> //<![CDATA[ window.webpackManifest = {"0":"main.5f020f80c23aa50ebedf.js","1":"vendor.81adc64d405c8b218485.js"} //]]> </script> </head> <body> </body> </html>
最后,文件的哈希值是基于文件的内容。我们使用webpack-chunk-hash或者webpack-md5-hash来实现。
最终webpack.config.js应该是这样:
var path =require("path"); var webpack =require("webpack"); var ChunkManifestPlugin =require("chunk-manifest-webpack-plugin"); var WebpackChunkHash =require("webpack-chunk-hash"); module.exports ={ entry:{ vendor:"./src/vendor.js",// vendor reference file(s) main:"./src/index.js"// application code }, output:{ path: path.join(__dirname,"build"), filename:"[name].[chunkhash].js", chunkFilename:"[name].[chunkhash].js" }, plugins:[ newwebpack.optimize.CommonsChunkPlugin({ name:["vendor","manifest"],// vendor libs + extracted manifest minChunks:Infinity, }), newwebpack.HashedModuleIdsPlugin(), newWebpackChunkHash(), newChunkManifestPlugin({ filename:"chunk-manifest.json", manifestVariable:"webpackManifest" }) ] };
用这个配置,第三方库的代码块将不会改变哈希值,除非你修改了它们的代码或者依赖。下面是moduleB.js在两次编译之间被修改之后的输出:
> node_modules/.bin/webpack Hash: f0ae5bf7c6a1fd3b2127 Version: webpack 2.2.0 Time: 102ms Asset Size Chunks Chunk Names main.9ebe4bf7d99ffc17e75f.js 509 bytes 0, 2 [emitted] main vendor.81adc64d405c8b218485.js 159 bytes 1, 2 [emitted] vendor chunk-manifest.json 73 bytes [emitted] manifest.d41d8cd98f00b204e980.js 5.56 kB 2 [emitted] manifest
> node_modules/.bin/webpack Hash: b5fb8e138b039ab515f3 Version: webpack 2.2.0 Time: 87ms Asset Size Chunks Chunk Names main.5f020f80c23aa50ebedf.js 521 bytes 0, 2 [emitted] main vendor.81adc64d405c8b218485.js 159 bytes 1, 2 [emitted] vendor chunk-manifest.json 73 bytes [emitted] manifest.d41d8cd98f00b204e980.js 5.56 kB 2 [emitted] manifest
注意,第三方库的代码块文件名不变,清单信息文件也是一样(如果我们把清单信息提取成清单信息代码块的话)
内嵌清单信息
内嵌代码块清单信息和webpack运行时代码(防止想定外的HTTP请求),取决与你的服务器设置。
参考文献
https://medium.com/@okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95#.vtwnssps4
https://gist.github.com/sokra/ff1b0290282bfa2c037bdb6dcca1a7aa
https://github.com/webpack/webpack/issues/1315
https://github.com/webpack/webpack.js.org/issues/652
https://presentations.survivejs.com/advanced-webpack/
-- End --
相关推荐
10. **其他**:如`package.json`(如果项目使用了前端构建工具如Webpack)或者`.gitignore`(定义了版本控制忽略的文件)等。 要深入学习这个项目,你需要先解压缩文件,然后根据README的指示设置环境,安装依赖,...
1. **Laravel 文档**:官方文档是学习 Laravel 的最佳资源,涵盖了从入门到高级的全面教程。 2. **社区与资源**:Laracasts 提供丰富的视频教程,Stack Overflow 和 Laravel.io 社区可以解决开发中的疑问。 3. **...
- [Webpack 官方文档](https://webpack.js.org/) - [Webpack 中文指南](https://zhcn.webpack.js.org/) #### 六、总结 Webpack 作为一款强大的前端打包工具,在现代前端开发中扮演着重要的角色。通过合理配置和...
- **错误排查**: 查阅Webpack官方文档或社区资源寻找解决方案。 - **优化策略**: 如代码拆分、缓存机制等提升构建速度。 #### 三、Webpack进阶 - **模块化标准**: - **CommonJS**: 节点环境的模块化标准。 - *...
4. **.gitignore**: 这个文件定义了Git版本控制系统应该忽略哪些文件或目录,通常包括编译生成的临时文件、缓存文件等,以保持仓库的整洁。 5. **vue.config.js**: 这是Vue CLI项目的配置文件,可以自定义Webpack...
10. `README.md` - 项目说明文件,通常包含项目的简介、安装步骤、使用方法和贡献指南等内容,帮助开发者理解和使用项目。 通过这些文件,我们可以看出这个项目是一个使用 TypeScript 开发的前端应用,借助 Babel ...
总结来说,Iview-admin 2.3.0 技术文档提供了详细的 Vue.js 项目配置和路由管理指南,包括基础配置、端口设置、跨域配置、路由元信息以及独立页面的处理,有助于开发者高效地搭建和维护基于 Vue 和 Iview 的管理后台...
全栈增长工程师需要知道如何优化网站性能,比如通过压缩图片、使用缓存技术和提高服务器响应速度等方法。同时,了解搜索引擎的爬虫和索引机制,以及如何为网站实施SEO策略也是必要的。 ### 架构模式与博客系统构建 ...
- `docs`:项目文档,包括用户手册、API文档、开发者指南等。 - `scripts`:自动化脚本,如部署脚本、构建脚本等。 2. **技术栈**: - 前端:可能是React、Vue.js、Angular等现代前端框架,配合Webpack进行模块...
7. **许可证和贡献指南**:开源项目通常会包含LICENSE文件和CONTRIBUTING指南,这些规定了代码的使用和贡献规则。 8. **打包与发布流程**:扩展可能有自动化的构建和打包脚本,如Webpack或Rollup,以及发布到浏览器...
10. **环境变量**:Webpack 支持通过 `process.env` 访问环境变量,这在开发和生产环境中很有用。可以使用 `dotenv` 插件和 `DefinePlugin` 来管理这些变量。 11. **TypeScript 支持**:Webpack 5 可以与 ...
5. **文档完善**:提供详尽的`README.md`,包括安装、使用示例、API文档等。 6. **代码风格**:遵循一定的编码风格,如ESLint,确保代码整洁一致。 7. **打包优化**:利用`npm pack`或`webpack`等工具进行打包,...
10. **webpack.config.js** 或 **gulpfile.js**:构建工具配置文件,用于处理源代码的打包、压缩、合并等任务。 11. **tests** 目录:单元测试和集成测试的代码,用于验证代码功能和质量。 12. **docs** 或 **wiki...
这通常包括编译后的文件、缓存文件等,避免将不必要的文件推送到远程仓库。 3. **vue.config.js**:这是Vue CLI项目的配置文件,允许开发者自定义Vue CLI服务和构建设置,如端口号、publicPath、代理配置等。在这个...
### Webpack2 中文文档概览 #### Webpack 概述 Webpack 是一款现代前端项目的模块打包工具。它能够将项目中的多个独立模块按照依赖关系和规则打包成适合生产环境部署的静态资源,并且支持按需加载的代码分割功能。...
**Webpack 5 全流程升级与配置优化** Webpack 5 是一个重要的版本更新,它带来了许多性能提升和新特性。本教程将引导你逐步完成一个已有项目的Webpack 5升级,并进行配置优化,确保项目的启动和构建速度得到显著...
10. **docs**:这个目录可能包含了项目相关的文档,如API参考、用户指南等,便于开发者和用户理解项目。 总的来说,`vue-templates/webpack` 提供了一套完整的Vue.js开发环境,包含了Webpack的配置、项目管理和自动...
`README.md`文件是项目说明文档,通常包含项目介绍、安装指南、使用方法和开发者注意事项等内容,帮助其他人理解和使用项目。 `screenshot.png`和`qr.png`可能是游戏的截图和二维码图片,用于展示游戏界面和方便...
- **官方网站**: 提供最新资讯和文档更新。 - **源码下载**: GitHub仓库,可以获取项目的源代码。 - **QQ交流群**: 提供技术交流和问题解答的社区。 - **在线演示**: 可以预览Jeecg-Boot的功能。 - **版本日志**: ...
3. **缓存系统**:支持多种缓存驱动,如 Redis、Memcached。 4. **事件系统**:用于在应用中触发和监听事件。 5. **文件存储**:支持本地、S3 等多种存储方式。 6. **队列任务调度**:异步处理任务,提高应用性能...