本文首發(fā)于Array_Huang的技術(shù)博客——
實(shí)用至上
,非經(jīng)作者同意婆翔,請勿轉(zhuǎn)載。
原文地址:https://segmentfault.com/a/1190000007104372
如果您對本系列文章感興趣掏婶,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang
前言
書承上文《webpack多頁應(yīng)用架構(gòu)系列(十):如何打造一個(gè)自定義的bootstrap》啃奴。
上文說到我們利用webpack來打包一個(gè)可配置的bootstrap,但文末留下一個(gè)問題:由于bootstrap十分龐大雄妥,因此每次編譯都要耗費(fèi)大部分的時(shí)間在打包bootstrap這一塊最蕾,而換來的僅僅是配置的便利,十分不劃算老厌。
我也并非是故意賣關(guān)子瘟则,這的確是我自己開發(fā)中碰到的問題,而在撰寫完該文后枝秤,我立即著手探索解決之道醋拧。終于,發(fā)現(xiàn)了webpack這一大殺器:DllPlugin
&DllReferencePlugin
淀弹,打包時(shí)間過長的問題得到完美解決丹壕。
解決方案的機(jī)制和原理
DllPlugin
&DllReferencePlugin
這一方案,實(shí)際上也是屬于代碼分割的范疇薇溃,但與CommonsChunkPlugin不一樣的是菌赖,它不僅僅是把公用代碼提取出來放到一個(gè)獨(dú)立的文件供不同的頁面來使用,它更重要的一點(diǎn)是:把公用代碼和它的使用者(業(yè)務(wù)代碼)從編譯這一步就分離出來沐序,換句話說琉用,我們可以分別來編譯公用代碼和業(yè)務(wù)代碼了忿峻。這有什么好處呢?很簡單辕羽,業(yè)務(wù)代碼常改逛尚,而公用代碼不常改,那么刁愿,我們在日常修改業(yè)務(wù)代碼的過程中绰寞,就可以省出編譯公用代碼那一部分所耗費(fèi)的時(shí)間了(是不是馬上就聯(lián)想到坑爹的bootstrap了呢)。
整個(gè)過程大概是這樣的:
- 利用
DllPlugin
把公用代碼打包成一個(gè)“Dll文件”(其實(shí)本質(zhì)上還是js铣口,只是套用概念而已)滤钱;除了Dll文件外,DllPlugin
還會生成一個(gè)manifest.json文件作為公用代碼的索引供DllReferencePlugin
使用脑题。 - 在業(yè)務(wù)代碼的webpack配置文件中配置好
DllReferencePlugin
并進(jìn)行編譯件缸,達(dá)到利用DllReferencePlugin
讓業(yè)務(wù)代碼和Dll文件實(shí)現(xiàn)關(guān)聯(lián)的目的。 - 在各個(gè)頁面<head>中叔遂,先加載Dll文件他炊,再加載業(yè)務(wù)代碼文件。
適用范圍
Dll文件里只適合放置不常改動的代碼已艰,比如說第三方庫(誰也不會有事無事就升級一下第三方庫吧)痊末,尤其是本身就龐大或者依賴眾多的庫。如果你自己整理了一套成熟的框架哩掺,開發(fā)項(xiàng)目時(shí)只需要在上面添磚加瓦的凿叠,那么也可以把這套框架也打包進(jìn)Dll文件里,甚至可以做到多個(gè)項(xiàng)目共用這一份Dll文件嚼吞。
如何配置哪些代碼需要打包進(jìn)Dll文件盒件?
我們需要專門為Dll文件建一份webpack配置文件,不能與業(yè)務(wù)代碼共用同一份配置:
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const dirVars = require('./webpack-config/base/dir-vars.config.js'); // 與業(yè)務(wù)代碼共用同一份路徑的配置表
module.exports = {
output: {
path: dirVars.dllDir,
filename: '[name].js',
library: '[name]', // 當(dāng)前Dll的所有內(nèi)容都會存放在這個(gè)參數(shù)指定變量名的一個(gè)全局變量下舱禽,注意與DllPlugin的name參數(shù)保持一致
},
entry: {
/*
指定需要打包的js模塊
或是css/less/圖片/字體文件等資源炒刁,但注意要在module參數(shù)配置好相應(yīng)的loader
*/
dll: [
'jquery', '!!bootstrap-webpack!bootstrapConfig',
'metisMenu/metisMenu.min', 'metisMenu/metisMenu.min.css',
],
},
plugins: [
new webpack.DllPlugin({
path: 'manifest.json', // 本Dll文件中各模塊的索引,供DllReferencePlugin讀取使用
name: '[name]', // 當(dāng)前Dll的所有內(nèi)容都會存放在這個(gè)參數(shù)指定變量名的一個(gè)全局變量下呢蔫,注意與參數(shù)output.library保持一致
context: dirVars.staticRootDir, // 指定一個(gè)路徑作為上下文環(huán)境切心,需要與DllReferencePlugin的context參數(shù)保持一致飒筑,建議統(tǒng)一設(shè)置為項(xiàng)目根目錄
}),
/* 跟業(yè)務(wù)代碼一樣片吊,該兼容的還是得兼容 */
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
}),
new ExtractTextPlugin('[name].css'), // 打包c(diǎn)ss/less的時(shí)候會用到ExtractTextPlugin
],
module: require('./webpack-config/module.config.js'), // 沿用業(yè)務(wù)代碼的module配置
resolve: require('./webpack-config/resolve.config.js'), // 沿用業(yè)務(wù)代碼的resolve配置
};
如何編譯Dll文件?
編譯Dll文件的代碼實(shí)際上跟編譯業(yè)務(wù)代碼是一樣的协屡,記得利用--config
指定上述專供Dll使用的webpack配置文件就好了:
$ webpack --progress --colors --config ./webpack-dll.config.js
另外俏脊,建議可以把該語句寫到npm scripts
里,好記一點(diǎn)哈肤晓。
如何讓業(yè)務(wù)代碼關(guān)聯(lián)Dll文件爷贫?
我們需要在供編譯業(yè)務(wù)代碼的webpack配置文件里設(shè)好DllReferencePlugin
的配置項(xiàng):
new webpack.DllReferencePlugin({
context: dirVars.staticRootDir, // 指定一個(gè)路徑作為上下文環(huán)境认然,需要與DllPlugin的context參數(shù)保持一致,建議統(tǒng)一設(shè)置為項(xiàng)目根目錄
manifest: require('../../manifest.json'), // 指定manifest.json
name: 'dll', // 當(dāng)前Dll的所有內(nèi)容都會存放在這個(gè)參數(shù)指定變量名的一個(gè)全局變量下漫萄,注意與DllPlugin的name參數(shù)保持一致
});
配置好DllReferencePlugin
了以后卷员,正常編譯業(yè)務(wù)代碼即可。不過要注意腾务,必須要先編譯Dll并生成manifest.json后再編譯業(yè)務(wù)代碼毕骡;而以后每次修改Dll并重新編譯后,也要重新編譯一下業(yè)務(wù)代碼岩瘦。
如何在業(yè)務(wù)代碼里使用Dll文件打包的module/資源未巫?
不需要刻意做些什么,該怎么require就怎么require启昧,webpack都會幫你處理好的了叙凡。
如何整合Dll?
在每個(gè)頁面里密末,都要按這個(gè)順序來加載js文件:Dll文件 => CommonsChunkPlugin
生成的公用chunk文件(如果沒用CommonsChunkPlugin
那就忽略啦) => 頁面本身的入口文件握爷。
有兩個(gè)注意事項(xiàng):
- 如果你是像我一樣利用
HtmlWebpackPlugin
來生成HTML并自動加載chunk的話,請務(wù)必在<head>里手寫<script>來加載Dll文件严里。 - 為了完全分離源文件和編譯后生成的文件饼拍,也為了方便在編譯前可以清空build目錄,不應(yīng)直接把Dll文件編譯生成到build目錄里田炭,我建議可以先生成到源文件src目錄里师抄,再用
file-loader
給原封不動搬運(yùn)過去。
光說不練假把式教硫,來個(gè)跑分啊大兄弟叨吮!
下面以我的腳手架項(xiàng)目Array-Huang/webpack-seed為例,測試一下(使用開發(fā)環(huán)境的webpack配置文件webpack.dev.config.js
)使用這套Dll方案前后的webpack編譯時(shí)間:
- 使用Dll方案前的編譯時(shí)間為:10秒17
- 使用Dll方案后的編譯時(shí)間為:4秒29
由于該項(xiàng)目只是一個(gè)腳手架瞬矩,涉及到的第三方庫并不多茶鉴,我只把jQuery、bootstrap景用、metisMenu給打包進(jìn)Dll文件里了涵叮,盡管如此,還是差了將近6秒了伞插,相信在實(shí)際項(xiàng)目中割粮,這套DllPlugin
&DllReferencePlugin
的方案能為你省下更多的時(shí)間來找女朋友(大誤)。
示例代碼
諸位看本系列文章媚污,搭配我在Github上的腳手架項(xiàng)目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed
)舀瓢。
附系列文章目錄(同步更新)
- webpack多頁應(yīng)用架構(gòu)系列(一):一步一步解決架構(gòu)痛點(diǎn)
- webpack多頁應(yīng)用架構(gòu)系列(二):webpack配置常用部分有哪些?
- webpack多頁應(yīng)用架構(gòu)系列(三):怎么打包公共代碼才能避免重復(fù)耗美?
- webpack多頁應(yīng)用架構(gòu)系列(四):老式j(luò)Query插件還不能丟京髓,怎么兼容航缀?
- webpack多頁應(yīng)用架構(gòu)系列(五):聽說webpack連less/css也能打包?
- webpack多頁應(yīng)用架構(gòu)系列(六):聽說webpack連圖片和字體也能打包堰怨?
- webpack多頁應(yīng)用架構(gòu)系列(七):開發(fā)環(huán)境芥玉、生產(chǎn)環(huán)境傻傻分不清楚?
- webpack多頁應(yīng)用架構(gòu)系列(八):教練我要寫ES6备图!webpack怎么整合Babel飞傀?
- webpack多頁應(yīng)用架構(gòu)系列(九):總有刁民想害朕!ESLint為你阻擊垃圾代碼
- webpack多頁應(yīng)用架構(gòu)系列(十):如何打造一個(gè)自定義的bootstrap
- webpack多頁應(yīng)用架構(gòu)系列(十一):預(yù)打包Dll诬烹,實(shí)現(xiàn)webpack音速編譯
- webpack多頁應(yīng)用架構(gòu)系列(十二):利用webpack生成HTML普通網(wǎng)頁&頁面模板
- webpack多頁應(yīng)用架構(gòu)系列(十三):構(gòu)建一個(gè)簡單的模板布局系統(tǒng)
- webpack多頁應(yīng)用架構(gòu)系列(十四):No復(fù)制粘貼砸烦!多項(xiàng)目共用基礎(chǔ)設(shè)施
- webpack多頁應(yīng)用架構(gòu)系列(十五):論前端如何在后端渲染開發(fā)模式下夾縫生存
本文首發(fā)于Array_Huang的技術(shù)博客——
實(shí)用至上
,非經(jīng)作者同意绞吁,請勿轉(zhuǎn)載幢痘。
原文地址:https://segmentfault.com/a/1190000007104372
如果您對本系列文章感興趣,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang