Webpack 缓存
缓存
使用 webpack 来打包我们的模块化后的应用程序,webpack 会生成一个可部署的 /dist 目录,然后把打包后的内容放置在此目录中。只要把 /dist 目录中的内容部署到服务器上,客户端(通常是浏览器)就能够访问此服务器的网站及其资源。
获取资源是比较耗费时间的,这就是为什么浏览器使用一种名为缓存的技术。
可以通过命中缓存,以降低网络流量,使网站加载速度更快,然而,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
也就是说,对于不会经常更新的文件,我们要保证它们的文件名不变,这样就可以命中缓存,浏览器就会直接从本地取出,从而提高性能;对于需要经常更新的文件,我们又要保证它们的文件名,会随着文件内容的改变而改变,这样,浏览器就会从服务器请求更新后的文件。
输出文件的文件名
通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件。[hash] 替换可以用于在文件名中包含一个与构建相关(build-specific)的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 与 chunk 相关(chunk-specific)的哈希。
修改 webpack.config.js 文件:
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new HTMLWebpackPlugin({
title: '缓存'
}),
new CleanWebpackPlugin(['dist'])
],
output: {
filename: '[name].[chunkhash].js', // 与 chunk 相关的哈希
path: path.resolve(__dirname, 'dist')
}
};
src/index.js 的内容为:
import _ from 'lodash';
function component() {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
运行 npm run dev,应该产生以下输出:
Hash: f0f47a8eaf7c0a917ac9
Version: webpack 4.0.0
Time: 565ms
Built at: 2018-3-3 21:23:10
Asset Size Chunks Chunk Names
main.dd35d7c54baa3d259f9e.js 550 KiB main [emitted] [big] main
index.html 200 bytes [emitted]
Entrypoint main [big] = main.dd35d7c54baa3d259f9e.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 509 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 519 bytes {main} [built]
[./src/index.js] 228 bytes {main} [built]
可以发现,bundle 的名称是它内容(通过 hash)的映射。如果我们不做修改,然后再次运行构建,我们原以为文件名会保持不变。然而,如果我们真的运行,可能会发现情况并非一定如此。
再次运行 npm run dev,输出结果为:
Hash: f0f47a8eaf7c0a917ac9
Version: webpack 4.0.0
Time: 590ms
Built at: 2018-3-3 21:28:55
Asset Size Chunks Chunk Names
main.dd35d7c54baa3d259f9e.js 550 KiB main [emitted] [big] main
index.html 200 bytes [emitted]
Entrypoint main [big] = main.dd35d7c54baa3d259f9e.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 509 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 519 bytes {main} [built]
[./src/index.js] 228 bytes {main} [built]
【 输出可能会因当前的 webpack 版本而稍有差异。新版本不一定有和旧版本相同的 hash 问题,但我们以下推荐的步骤,仍然是可靠的。】
缓存第三方库
就像我们之前从代码分离了解到的,CommonsChunkPlugin 可以用于将模块分离到单独的文件中。我们可以将公共库拆分出来,让浏览器对其缓存。
由于在 webpack 4.0.0 中,CommonsChunkPlugin 插件被移除了,而改用 config.optimization.splitChunks。故这里,我们使用 splitChunks。
webpack.config.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new HTMLWebpackPlugin({
title: '缓存'
}),
new CleanWebpackPlugin(['dist'])
],
output: {
filename: '[name].[chunkhash].js', // 与 chunk 相关的哈希
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: "initial", // "initial" | "all"(默认就是all) | "async"
name : 'vendor'
// minSize: 0, // 最小尺寸,默认0
// minChunks: 1, // 最小 chunk ,默认1
// maxAsyncRequests: 1, // 最大异步请求数, 默认1
// maxInitialRequests : 1, // 最大初始化请求数,默认1
// cacheGroups:{ // 这里开始设置缓存的 chunks
// // priority: 0, // 缓存组优先级
// vendor: { // key 为entry中定义的 入口名称
// chunks: "initial", // "initial" | "all" | "async"(默认就是异步)
// test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
// name: "vendor", // 要缓存的 分隔出来的 chunk 名称
// // minSize: 0,
// // minChunks: 1,
// enforce: true,
// // maxAsyncRequests: 1, // 最大异步请求数, 默认1
// // maxInitialRequests : 1, // 最大初始化请求数,默认1
// // reuseExistingChunk: true // 可设置是否重用该chunk(查看源码没有发现默认值)
// }
// }
}
}
};
运行 npm run dev,输出结果为:
Hash: 4f6c4c5f88f59746b875
Version: webpack 4.0.0
Time: 574ms
Built at: 2018-3-3 22:28:36
Asset Size Chunks Chunk Names
main.b7ee0df3852ecc0ea76b.js 5.9 KiB main [emitted] main
vendor.62788e75196910a94bb9.js 547 KiB vendor [emitted] [big] vendor
index.html 277 bytes [emitted]
Entrypoint main [big] = vendor.62788e75196910a94bb9.js main.b7ee0df3852ecc0ea76b.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 509 bytes {vendor} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 519 bytes {vendor} [built]
[./src/index.js] 226 bytes {main} [built]
可以发现,第三方库 lodash 被单独分离出来了,保存在 vendor.62788e75196910a94bb9.js 这个 bundle 中。
这种将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。
然后,我们新建 src/print.js 文件:
export default function print(text) {
console.log(text);
};
并在 src/index.js 文件中引入它:
import _ from 'lodash';
import Print from './print';
function component() {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.onclick = Print.bind(null, 'Hello webpack!');
return element;
}
document.body.appendChild(component());
然后,运行 npm run dev,查看各个 bundle 的名称变化。
Hash: d15457d1538e0935727e
Version: webpack 4.0.0
Time: 598ms
Built at: 2018-3-3 22:38:54
Asset Size Chunks Chunk Names
main.4848aa5ef67e9b5b310e.js 6.62 KiB main [emitted] main
vendor.62788e75196910a94bb9.js 547 KiB vendor [emitted] [big] vendor
index.html 277 bytes [emitted]
Entrypoint main [big] = vendor.62788e75196910a94bb9.js main.4848aa5ef67e9b5b310e.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 509 bytes {vendor} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 519 bytes {vendor} [built]
[./src/index.js] 317 bytes {main} [built]
[./src/print.js] 65 bytes {main} [built]
可以发现,vendor bundle 的名称一直是 vendor.62788e75196910a94bb9.js,而 main bundle 的名称变了。这正是我们需要的预期结果。
还没有评论,来说两句吧...