webpack code splitting (chanpter 1)
webpack的简单代码分割
webpack官网把代码分割分了三个部分 => 地址
- Vendor code splitting
- CSS splitting
- On demand code-splitting
这篇写个人对Vendor code splitting部分的一些尝试。
目的
Vendor code splitting主要处理第三方插件框架打包的问题,vendor是供应商的意思,因为这部分的代码基本不会变,如果和应用代码带包到一起(应用代码是经常改动的),打包出来的chunks也会每次都不一样,这样我们就不能利用缓存去加快访问这些资源的速度,所以我们希望将这部分代码分离出来生成一个独立的文件。
使用
以jquery的打包为例,首先安装jquery1
npm install --save jquery
配置webpack.config.js,设置了入口和打包文件输出设置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let path = require("path");
let webpack = require("webpack");
modules.exports = {
entry: {
app: "./src/app.js",
main: "./src/main.js",
},
output: {
filename: assetDir+"js/[name].[chunkhash].js",
publicPath: "",
path: path.resolve(__dirname, "./dist"),
},
plugins: [
new HtmlWebpackPlugin({
template: "index.html"
}),
]
}
在main.js中编写代码:1
2
3
4
5
6
7
8
import $ from "jquery"
import image from "./image/2.jpg"
let $image = $("<img></img>");
$image.attr("src", image);
console.log($image);
$(document.body).append($image);
然后打包会发现有main.js打出来的包特别大(当然没启用代码压缩)1
2
3 Asset Size Chunks Chunk Names
static/js/main.1bfd830214e54480638a.js 281 kB 0 [emitted] [big] main
index.html 304 bytes [emitted]
为了把jquery打包成独立文件,需要使用CommonsChunkPlugin插件。
在entry配置加一项:
1 |
|
再启用CommonsChunkPlugin插件,把entry的vendor项进行分割打包1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let path = require("path");
let webpack = require("webpack");
modules.exports = {
entry: {
app: "./src/app.js",
main: "./src/main.js",
vendor: ["jquery"]
},
output: {
filename: assetDir+"js/[name].[chunkhash].js",
publicPath: "",
path: path.resolve(__dirname, "./dist"),
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ["vendor"],
}),
]
}
重新运行webpack1
2
3
4
5
6
7
8 Asset Size Chunks Chunk Names
static/js/main.2dd0efc1bc2a64606e3f.js 10.4 kB 0 [emitted] main
static/js/vendor.563278ce106e847a9d92.js 274 kB 1 [emitted] [big] vendor
index.html 391 bytes [emitted]
[0] ./~/jquery/dist/jquery.js 268 kB {1} [built]
[1] ./src/image/2.jpg 9.75 kB {0} [built]
[2] ./src/main.js 455 bytes {0} [built]
[3] multi jquery 28 bytes {1} [built]
可以看到jquery被打包到chunk 1,即vendor.[chunkhash].js中,main.js体积变小了很多。
不过改下main.js的内容,加个console.log(“hello,world”)什么的再webpack发现vendor的哈希值变了,然而我们并没有改动jquery的内容。
But, if we change application code and run webpack again, we see that the hash for the vendor file changes. Even though we achieved separate bundles for vendor and main bundles, we see that the vendor bundle changes when the application code changes. This means that we still don’t reap the benefits of browser caching because the hash for vendor file changes on every build and the browser will have to reload the file.
The issue here is that on every build, webpack generates some webpack runtime code, which helps webpack do its job. When there is a single bundle, the runtime code resides in it. But when multiple bundles are generated, the runtime code is extracted into the common module, here the vendor file.
To prevent this, we need to extract out the runtime into a separate manifest file. Even though we are creating another bundle, the overhead is offset by the long term caching benefits that we obtain on the vendor file.
把runtime code提取到manifest文件就可以了
1 |
|
再改main.js发现vendor的哈希不变,manifest的哈希变了
如果不确定哪些第三方库需要分割,可以使用minChunks属性
minChunks: number|Infinity|function(module, count) -> boolean,
// The minimum number of chunks which need to contain a module before it’s moved into the commons chunk.
// The number must be greater than or equal 2 and lower than or equal to the number of chunks.
// PassingInfinity
just creates the commons chunk, but moves no modules into it.
// By providing afunction
you can add custom logic. (Defaults to the number of chunks)
比如minChunks设为2,如果有两个模块都用到了jquery,就会自动分割打包jquery
minChunks设为函数时,接受两个参数module,count
You also have the ability to pass the minChunks property a function. This function is called by the CommonsChunkPlugin and calls the function with module and count arguments.
The module argument represents each module in the chunks you have provided via the name/names property. module has the shape of a NormalModule, which has two particularly useful properties for this use case:
module.context: The directory that stores the file. For example: ‘/my_project/node_modules/example-dependency’
module.resource: The name of the file being processed. For example: ‘/my_project/node_modules/example-dependency/index.js’
The count argument represents how many chunks the module is used in.
比如把node_modules下的都分割出来,这样vendor就不用写了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let path = require("path");
let webpack = require("webpack");
modules.exports = {
entry: {
app: "./src/app.js",
main: "./src/main.js",
// vendor: ["jquery"]
},
output: {
filename: assetDir+"js/[name].[chunkhash].js",
publicPath: "",
path: path.resolve(__dirname, "./dist"),
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ["vendor"],
minChunks: function (module) {
return module.context && module.context.indexOf('node_modules') !== -1;
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest'
}),
]
}
**更新**
这玩意变化的有点快。。一段时间就过时了,还是以文档为准吧,不写这种的了