Code Splitting - Libraries
文檔地址
應(yīng)用程序一般會使用第三方的類庫峭范,這些類庫一般不會經(jīng)常變動。
而我們的業(yè)務(wù)代碼需要隨著業(yè)務(wù)改變經(jīng)常更新瘪贱。
webapp為了提升效率纱控,會根據(jù)cache header中的參數(shù)對文件進(jìn)行緩存辆毡,
文件緩存之后就不需要再從cdn上從新拉去資源了。
為了使用緩存特性甜害,我們需要將vendor文件進(jìn)行緩存舶掖,無論我們的業(yè)務(wù)代碼如何改變,
都不希望重新下載不變的vendor文件尔店。
我們可以通過將代碼分離成vendor bundle和application bundle來使用該特性眨攘。
單入口配置
不拆分的配置方法,比如我們在應(yīng)用中使用(momentjs)[https://www.npmjs.com/package/moment],用來格式化時(shí)間的js類嚣州。
安裝moment
,https://www.npmjs.com/package/moment
.
在index.js中引入moment
鲫售,并使用其打印當(dāng)前時(shí)間。
//index.js
var moment = require('moment');
console.log(moment().format());
使用如下配置進(jìn)行打包
var path = require('path');
module.exports = function(env) {
return {
entry: './index.js',
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
}
}
}
在運(yùn)行webpack
進(jìn)行打包之后该肴,分析resulting bundle情竹,會發(fā)現(xiàn)moment
和index.js
被打包到了同一個(gè)文件中(bundle.js)。
上面的方案沙庐,對于應(yīng)用來講鲤妥,是不完美的,如果index.js代碼變了拱雏,那涉及到的bundle,都會進(jìn)行重新編譯底扳。瀏覽器會重新加載所有的bundle铸抑,雖然很多bundle沒有改變。
多入口配置(Multiple Entries)
將moment
同vendor
分離衷模,實(shí)現(xiàn)更改index.js不影響vendor鹊汛。
var path = require('path');
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
}
}
}
按照上面的配置,運(yùn)行webpack
后阱冶,將會生成兩個(gè)bundle刁憋。
查看這兩個(gè)bundle文件,將會看到兩個(gè)文件中都包含moment
文件木蹬。
這是因?yàn)?code>moment是主程序(index.js)的依賴.所以兩個(gè)entry point中都會出現(xiàn)moment
.
這樣配置沒有實(shí)現(xiàn)我們的預(yù)期至耻。為了解決這個(gè)問題,需要使用CommonsChunkPlugin
CommonsChunkPlugin
該plugin有些復(fù)雜镊叁,使用該plugin可以將不同bundle中的公共模塊抽出來放在公用的bundle中尘颓。
如果該公用的bundle不存在,會創(chuàng)建一個(gè)新的bundle晦譬。
使用下面的配置啟用CommonsChunkPlugin
.
var webpack = require('webpack');
var path = require('path');
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor' // Specify the common bundle's name.
})
]
}
}
經(jīng)過上面的配置疤苹,執(zhí)行webpack
,查看打包的bundle,moment
代碼只會存在于vendor bundle敛腌。
這樣對index.js
的修改卧土,就不會導(dǎo)致全部文件進(jìn)行重新打包了惫皱。
Implicit Common Vendor Chunk
可以配置CommonsChunkPlugin
僅僅對vendor lib起作用。
var webpack = require('webpack');
var path = require('path');
module.exports = function() {
return {
entry: {
main: './index.js'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// this assumes your vendor imports exist in the node_modules directory
return module.context && module.context.indexOf('node_modules') !== -1;
}
})
]
};
}
Manifest File
如果再次運(yùn)行webpack
命令尤莺,會看到vendor文件的hash值被改變了逸吵。雖然通過配置將vendor
同main
bundle進(jìn)行了拆分。
但是我們觀察到缝裁,當(dāng)業(yè)務(wù)代碼改變后扫皱,vendor
bundle也會進(jìn)行改變。這樣我們就仍然無法使用瀏覽器的緩存功能捷绑。
產(chǎn)生這種情況是因?yàn)槊看螛?gòu)建韩脑,webpack都會生成一些webpack的運(yùn)行時(shí)代碼(runtime code),
webpack需要依賴runtime code才能真正的向用戶提供訪問的內(nèi)容粹污。
當(dāng)僅有一個(gè)單獨(dú)bundle時(shí)段多,runtime code會包含與該bundle中。
但是當(dāng)生成多個(gè)bundles時(shí)壮吩,runtime code會唄抽取到公用的module(此處位vendor
文件)
由于是抽取到了vendor中进苍,所以業(yè)務(wù)代碼改變,仍然會影響vendor鸭叙。
為了避免這個(gè)問題觉啊,需要將runtime代碼拆分到一個(gè)單獨(dú)的manifest文件,
雖然這樣做會導(dǎo)致多生成一個(gè)bundle文件沈贝,但是這樣就能使用瀏覽器的緩存機(jī)制了杠人。
具體配置如下
var webpack = require('webpack');
var path = require('path');
module.exports = function(env) {
return {
entry: {
main: './index.js',
vendor: 'moment'
},
output: {
filename: '[chunkhash].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest'] // Specify the common bundle's name.
})
]
}
};
使用上面的配置,將會生成三個(gè)bundles宋下,vendor
,main
,manifest
三個(gè)bundles嗡善。