这一篇主要讲缓存,内容基本与webpack的文档部分-指南-缓存保持一致~已经了解过的同学不必要再看了
是的,上面这段文字,我是直接复制的官网~
看前面两篇文章应该已经看到了,我在output配置中,已经使用了如下表示:
output: {
path: path.resolve(__dirname, "dist/"),
filename: "[name].bundle.js"
},
这里的[name] 我们称之为:substitutions --- 也就是一个占位符,执行build后被会替换。
在客户端向服务端请求资源时候,对应的资源匹配符一般是 url/path/filename,因此,当filename不发生变化时候,客户端会命中缓存,当我们文件发生修改,构建后的文件名字就需要更改,这样客户端就不会使用缓存文件,我们回到最简单的代码和配置。
├── dist
├── public
│ └── index.html
├── src
│ ├── App.css
│ ├── App.jsx
│ └── index.js
├── webpack.config.js
├── package.json
└── yarn.lock
├── .babelrc
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist/"),
filename: "index.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: '缓存',
template: './public/index.html'
}),
]
};
以上对于单入口的配置,会生成固定的fimename为index.js的文件,但是通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称
设置output filename
- 使用入口名称:
module.exports = {
//...
output: {
filename: '[name].bundle.js',
},
};
- 使用内部 chunk id
module.exports = {
//...
output: {
filename: '[id].bundle.js',
},
};
- 使用由生成的内容产生的 hash:
module.exports = {
//...
output: {
filename: '[contenthash].bundle.js',
},
};
- 结合多个替换组合使用:
module.exports = {
//...
output: {
filename: '[name].[contenthash].bundle.js',
},
};
- 使用函数返回 filename:
module.exports = {
//...
output: {
filename: (pathData) => {
return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
},
},
};
更复杂和更高级的用法,参见webpack的文档:outputfilename
你可以简单地对以上四种方式进行设置看看build后结果。
这里我们设置为:
module.exports={
//...
output: {
path: path.resolve(__dirname, "dist/"),
filename: "[name].[contenthash].js"
},
}
build后输出结果为:
├── index.html
├── main.2a5c2d475953a2c073fc.js
└── main.2a5c2d475953a2c073fc.js.LICENSE.txt // 不用管
可以看到,生成的文件名是根据我们配置的方式产生的
提取引导模板(extracting boilerplate)
webpack 还提供了一个优化功能,可使用 optimization.runtimeChunk 选项将 runtime 代码拆分为一个单独的 chunk。将其设置为 single 来为所有 chunk 创建一个 runtime bundle
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist/"),
filename: "[name].[contenthash].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: '管理输出',
template: './public/index.html'
}),
],
optimization: {
runtimeChunk: 'single',
},
};
build后文件为:
├── index.html
├── main.e015ebc8a50a50e241af.js
├── main.e015ebc8a50a50e241af.js.LICENSE.txt
└── runtime.fb3fdb31b8fba3a87894.js
可以看到,新生成了一个runtime.fb3fdb31b8fba3a87894.js文件。
我们继续:将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用 client 的长效缓存机制,命中缓存来消除请求,并减少向 server 获取资源,同时还能保证 client 代码和 server 代码版本一致,这可以通过使用 SplitChunksPlugin 示例 2 中演示的 SplitChunksPlugin 插件的 cacheGroups 选项来实现
// ...
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
生成的代码文件为,仔细看看main的代码大小:main中不包含任何依赖相关代码了
├── index.html
├── main.7f74a4145b9a5f89c983.js
├── runtime.fb3fdb31b8fba3a87894.js
├── vendors.60580f0863c3f8e70856.js
└── vendors.60580f0863c3f8e70856.js.LICENSE.txt
接下来,我们再src目录新增一个print.js
export function print() {
console.log('print!!!')
}
再App.jsx中引入print方法并执行
import React from "react";
import print from './print';
import "./App.css";
function App() {
print();
return (
<div className="App">
<h1> Hello, World </h1>
</div>
);
}
export default App;
build后生成的文件:
├── index.html
├── main.ecda747780e86fe47ecf.js
├── runtime.b8a0cf32c66c8e3d96c6.js
├── vendors.ed2678b03f97207cadab.js
└── vendors.ed2678b03f97207cadab.js.LICENSE.txt
我们期望的是main的filename发生修改:因为我们修改的只是打包进入main文件的代码,但是事实上发现,生成的所有文件名都发生了修改~
这是因为每个 module.id 会默认地基于解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变。因此,简要概括:
main bundle 会随着自身的新增内容的修改,而发生变化。 vendor bundle 会随着自身的 module.id 的变化,而发生变化。 manifest runtime 会因为现在包含一个新模块的引用,而发生变化。 第一个和最后一个都是符合预期的行为,vendor hash 发生变化是我们要修复的。我们将 optimization.moduleIds 设置为 'deterministic':
optimization: {
runtimeChunk: 'single',
moduleIds: 'deterministic',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
再次执行build一次、再删除print.js和print相关代码,会发现,vendor hashd都没有发生变化
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!