webpack增量打包多页应用
一,webpack打包存在的問題
webpack的打包順序:
var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].js"} }; 復(fù)制代碼1,找到入口文件
2,根據(jù)入口文件,找出具有依賴關(guān)系的文件js/css
3,最后,把css/js全部打包成一個(gè)js包
好的,打包完成,打包了整個(gè)世界,那么問題來了:
產(chǎn)品說:按鈕顏色不對,給我改成#ccc
技術(shù):好的,這就改。
然后就有了如下流程:
1,找到了entry -> js -> componet -> button.less修改了一個(gè)色值
2,執(zhí)行webpack打包
這時(shí)就暴露了問題:
1,明明只是修改了一個(gè)色值,卻要從入口開始重新打包
2,業(yè)務(wù)代碼明明沒有變化,卻也被牽連了
3,最后生成的js要全部推到線上,覆蓋掉線上原本沒問題的業(yè)務(wù)js,純粹是增加風(fēng)險(xiǎn)
二,思考解決方案
首先想到的是,既然只修改一個(gè)文件,那能不能重新打包一個(gè)文件呢?
1,單獨(dú)打包更新的文件?
這種方案,很快就被自我否定了。
因?yàn)?#xff1a;
1,從入口打包的文件,已經(jīng)通過依賴關(guān)系,把老版本button.less打入了最終輸出的js文件
2,單獨(dú)打包button.less輸出了一個(gè)獨(dú)立的button.js,這個(gè)文件需要手動(dòng)引入到html中,一旦這類文件制造的多了,根本無法維護(hù)
經(jīng)過反復(fù)思考,單獨(dú)打包每一個(gè)文件的想法,不符合webpack的設(shè)計(jì)初衷,從入口打包的流程是不能夠產(chǎn)生變化的
在這個(gè)問題上卡了真的很久.....很久
2,能否通過依賴關(guān)系,打包某一個(gè)入口?
由于我面臨的場景是多頁應(yīng)用,所以存在多個(gè)入口,那么既然如此,那么能否通過依賴關(guān)系,找到需要更新的入口呢?
這種方案,也思索了很久,后來也被否定了。
因?yàn)?#xff1a;
1,webpack沒有適合輸出模塊依賴關(guān)系的插件,遍尋無果啊
2,通過webpack的stats分析指標(biāo),能夠輸出依賴關(guān)系,但數(shù)據(jù)量太大,如果不加過濾,目前項(xiàng)目輸出12W行json信息,還需要花力氣處理一遍這個(gè)信息才能拿到關(guān)系
3,如果一個(gè)組件被多個(gè)入口引用,那么需要找到每一個(gè)引用的入口點(diǎn),再重新打包每個(gè)被波及的入口
上面尤其是第三點(diǎn),完全不符合我們想增量發(fā)布的目的,如果改了一個(gè)button組件,要重新打包二三十個(gè)入口,這完全沒有增量發(fā)布的意義
在這個(gè)問題上又糾結(jié)了很久......很久 
三,合理的解決方案
經(jīng)過前面兩個(gè)問題后,我發(fā)現(xiàn)思考的方向完全是錯(cuò)誤的,總是妄想改變webpack的打包方式,簡直就是跟它的理念對著干。
既然不能改變webpack的打包方式,那么我能否改變webpack的輸出結(jié)果呢?
其實(shí)webpack關(guān)于緩存方面的功能,提供了很多功能強(qiáng)大的插件,例如:
-  CommonsChunkPlugin可以用來在打包的時(shí)候提取公共js代碼 
-  ExtractTextPlugin可以用來從js中提出css,將其輸出到一個(gè)獨(dú)立的文件 
利用這兩個(gè)插件,我們能夠?qū)⑽覀兇虬木燃右詣澐?#xff0c;將公共引用的部分打包為一個(gè)單獨(dú)的文件
如果公共引用的部分變?yōu)榱艘粋€(gè)單獨(dú)的文件,再添加上hash進(jìn)行緩存,當(dāng)再次修改的時(shí)候只要更新hash,這樣我們不就能夠確定,究竟改動(dòng)了哪個(gè)文件了嗎
既然如此,我們一步一步進(jìn)行探索:
1,首先使用CommonsChunkPlugin,提取公共js
現(xiàn)在我們創(chuàng)建測試入口文件:
src/one.js:
import jquery from 'jquery';console.log('one'); 復(fù)制代碼src/two.js:
import jquery from 'jquery';console.log('two'); 復(fù)制代碼webpack.config.js
var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].js"} }; 復(fù)制代碼執(zhí)行webpack
輸出了2個(gè)文件,大小都是271kb,這是因?yàn)閛ne.js和two.js都引用了jquery,jquery打包了2次,分別打包到了兩個(gè)文件中
這樣顯然不是很友好,像jquery這種文件,顯然平時(shí)不會改動(dòng),還是緩存起來比較好,修改webpack.config.js
var webpack = require("webpack"); var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: "common",}),] }; 復(fù)制代碼現(xiàn)在我們添加了CommonsChunkPlugin插件,它的作用是提取公共js,再次執(zhí)行webpack
可以看到one.js和two.js的大小已經(jīng)不到1k了,而common則274k,可以看到j(luò)query已經(jīng)被打包到了common.js當(dāng)中
2,為文件添加hash
var webpack = require("webpack"); var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[hash:6].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: "common",}),] }; 復(fù)制代碼上面修改了output的輸出內(nèi)容[name].[hash].js
現(xiàn)在執(zhí)行webpack:
可以看到打包的三個(gè)文件都有了hash,但需要主意,此時(shí)每個(gè)文件的hash都是一樣的
再次執(zhí)行一遍webpack:
可以看到,兩次構(gòu)建輸出的結(jié)果一致,這很好,因?yàn)闆]有修改文件,自然不希望hash發(fā)生改變
那么接下來,修改一下文件:one.js
import jquery from 'jquery'; console.log('修改one'); 復(fù)制代碼悲劇了,所有文件全部修改了hash,查看輸出的結(jié)果:
可以發(fā)現(xiàn)只修改一個(gè)文件,卻修改了全部文件的hash,這個(gè)問題很嚴(yán)重,顯然不是我們想要的
3,使用chunkhash替代hash
webpack中關(guān)于緩存,提供了好幾種添加hash的方法,其中就有chunkhash
chunkhash簡單來說,就是根據(jù)模塊內(nèi)容來添加hash,既然這樣的話,只要文件沒有改變,就不會生成新的hash
var webpack = require("webpack"); var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: "common",}),] }; 復(fù)制代碼如上圖,修改filename:[name].[chunkhash:8]/js
執(zhí)行webpack
可以看到這一次生成的hash是4897....
但是輸出的每個(gè)文件的hash卻不是4897....
很好,接下來再執(zhí)行一次webpack:
可以看到兩次輸出之間hash并沒有發(fā)生變化
現(xiàn)在,修改one.js,再執(zhí)行webapck
import jquery from 'jquery'; console.log('使用chunkhash后修改one'); 復(fù)制代碼可以看到two.js的hash沒有改變one.js的hash改變了,但common.js的hash竟然也改了...
4,提取manifest
前面用CommonsChunkPlugin提取代碼后,公共的代碼已經(jīng)被抽離,但是他們之間肯定存在一個(gè)映射關(guān)系,例如
之所以commonjs的hash會變,是因?yàn)樾薷膐ne.js生成了新的hash,而jquery又與one.js存在映射關(guān)系,映射關(guān)系會更新,也就是說common.js它要從新的one.js中提取了jquery
而manifest就可以簡單理解為模塊映射關(guān)系的集合,而這個(gè)manifest將隨著這些被分離出來的代碼共同打包!!!
所以現(xiàn)在分離manifest
var webpack = require("webpack"); var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: "common",}),new webpack.optimize.CommonsChunkPlugin({name: 'manifest' // 用于提取manifest})] }; 復(fù)制代碼這里主要是利用CommonsChunkPlugin的一個(gè)功能,通過默認(rèn)的名字,來提取公共代碼,因?yàn)閣ebpack打包的是有有一個(gè)默認(rèn)模塊就是manifest,所以我們可以通過這個(gè)來實(shí)現(xiàn)
現(xiàn)在我們執(zhí)行webpack:
可以看到,多輸出了一個(gè)manifest.js
接下來,再修改one.js
import jquery from 'jquery'; console.log('分離manifest后修改one'); 復(fù)制代碼可以看到,現(xiàn)在只有one.js和manifest.js的hash發(fā)生了改變,common.js被成功緩存了
使用代碼對比工具,比較兩次manifest之間的區(qū)別,可以看到確實(shí)是映射的chunkid發(fā)生了改變
5,使用webpack-md5-hash插件
前面我們輸出了一個(gè)manifest.js,但這樣還需要單獨(dú)處理這個(gè)manifest.js,所以可以使用webpack的另一個(gè)插件webpack-md5-hash
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); module.exports = {entry: {one: "./src/one.js",two: "./src/two.js"},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new WebpackMd5Hash(),new webpack.optimize.CommonsChunkPlugin({name: "common",}),] };復(fù)制代碼執(zhí)行一次打包:
沒有manifest輸出,修改one.js
import jquery from 'jquery'; console.log('使用WebpackMd5Hash修改one'); 復(fù)制代碼再次打包:
這一次僅有one.js的hash發(fā)生了改變
雖然webpack-md5-hash解決了我們的問題,但這也讓打包的模塊關(guān)系變成了黑盒,存在一定的未知風(fēng)險(xiǎn),還需要仔細(xì)實(shí)踐評估是否有問題
6,打包修改頻率超級低的庫
前面已經(jīng)抽離出來了公共代碼,但是還存在問題,假如這時(shí)候又需要引入lodash,那common的hash是否會改變?
修改one.js
import jquery from 'jquery'; import lodash from 'lodash'; console.log('引入lodash修改one'); 復(fù)制代碼修改two.js
import jquery from 'jquery'; import lodash from 'lodash'; console.log('引入lodash修改two'); 復(fù)制代碼這一次,所有文件的hash都發(fā)生了改變,不僅如此,而且更顯著的是common的體積增大了
這就意味者lodash也被打進(jìn)了common當(dāng)中,但這本身是一個(gè)錯(cuò)誤的行為,lodash和jquery,平時(shí)根本不會對其進(jìn)行修改,既然如此,那還需要優(yōu)化,把他們單獨(dú)打包出去
現(xiàn)在修改webapack.config.js
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); module.exports = {entry: {two: "./src/two.js",one: "./src/one.js",common:['jquery','lodash']},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new WebpackMd5Hash(),new webpack.optimize.CommonsChunkPlugin({name: "common",}),] }; 復(fù)制代碼這一次在入口處添加了一個(gè)common,common單獨(dú)指向了jquery和lodash,這一次我們執(zhí)行打包
此時(shí),輸出的內(nèi)容沒有明顯變化,同樣是3個(gè)文件,大小也完全一致,hash也沒有問題
可以看到,common的大小是817k
如果這時(shí),再應(yīng)用了其他的包呢?例如引入react
修改one.js
import jquery from 'jquery'; import lodash from 'lodash'; import react from 'react'; console.log('引入react修改one'); 復(fù)制代碼修改two.js
import jquery from 'jquery'; import lodash from 'lodash'; import react from 'react'; console.log('引入react修改one'); 復(fù)制代碼執(zhí)行webpack
問題來了,common的大小增加了,很顯然react被打包進(jìn)去了,但如果我們此時(shí),只想永久緩存jquery和lodash呢,這該怎么辦?
修改webpack.config.js
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); module.exports = {entry: {two: "./src/two.js",one: "./src/one.js",common:['jquery','lodash']},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new WebpackMd5Hash(),new webpack.optimize.CommonsChunkPlugin({name: 'common',minChunks:Infinity})] }; 復(fù)制代碼這一次,添加了一句話minChunks:Infinity
minChunks屬性的可以設(shè)置為2,意思是引用次數(shù)為2的模塊就抽離出來,而Infinity則表示無限,無限就意味著不會有多余的被打包進(jìn)來
現(xiàn)在執(zhí)行webpack打包
可以看到現(xiàn)在common又恢復(fù)了816k,當(dāng)然react也沒有抽出來,還在兩個(gè)文件當(dāng)中,接下來繼續(xù)抽離react
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); module.exports = {entry: {two: "./src/two.js",one: "./src/one.js",common:['jquery','lodash'],react:['react','react-redux']},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: ['react','common'], // 用于提取manifestminChunks:Infinity}),new WebpackMd5Hash(),] }; 復(fù)制代碼通過上面的構(gòu)建,我們已經(jīng)將不會改動(dòng)的類庫,單獨(dú)打包并維持住了hash。
7,引入HashedModuleIdsPlugin固定模塊id
前面看似完美,但如果我們現(xiàn)在改變一下入口的順序
entry: {react:['react','react-redux'], two: "./src/two.js",one: "./src/one.js",common:['jquery','lodash'], } 復(fù)制代碼可以看到common和react公共庫的hash又變了,這是因?yàn)?#xff0c;模塊id是根據(jù)webpack的解析順序增量的,如果變換解析順序,那模塊id也會隨之改變。
所以就需要HashedModuleIdsPlugin了,它是根據(jù)模塊相對路徑生成模塊標(biāo)識,如果模塊沒有改變,那模塊標(biāo)識也不會改變
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); module.exports = {entry: {common:['jquery','lodash'], react:['react','react-redux'], two: "./src/two.js",one: "./src/one.js",},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},plugins:[new webpack.optimize.CommonsChunkPlugin({name: ['react','common'], // 用于提取manifestminChunks:Infinity}),new webpack.HashedModuleIdsPlugin(),new WebpackMd5Hash(),] }; 復(fù)制代碼現(xiàn)在打包后,模塊的標(biāo)識不再是id了,而是一個(gè)四位的編碼了,這樣就可以固定住ip地址了。
8,使用extract-text-webpack-plugin提取css文件
在src下創(chuàng)建one.css:
body{color:blue; } 復(fù)制代碼two.css
h1{font-size:24px; } 復(fù)制代碼修改one.js和two.js引入css
import jquery from 'jquery'; import lodash from 'lodash'; import react from 'react'; import './one.css' console.log('引入css修改one'); 復(fù)制代碼修改webpack.config.js
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = {entry: {common: ['jquery', 'lodash'],react: ['react', 'react-redux'],two: "./src/two.js",one: "./src/one.js",},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},module: {rules: [{test: /\.css$/,use: ExtractTextPlugin.extract({fallback: "style-loader",use: "css-loader"})}]},plugins: [new webpack.optimize.CommonsChunkPlugin({name: ['react', 'common'], // 用于提取manifestminChunks: Infinity}),new ExtractTextPlugin("[name].[chunkhash:8].css"),new webpack.HashedModuleIdsPlugin(),new WebpackMd5Hash()] }; 復(fù)制代碼執(zhí)行webpack:
可以看到,成功輸出了js和css,但是有點(diǎn)疑問的是,one.css和one.js的hash是一樣的,這樣的話,如果我們改變one.css呢?
修改one.css,再次打包:
發(fā)現(xiàn)css的hash沒有任何變化。
接著再修改one.js,再次打包:
這一次one.js和one.css的hash同時(shí)改變了。
9,使用contenthash提取固定css的hash
- When using the ExtractTextWebpackPlugin, use [contenthash] to obtain a hash of the extracted file (neither [hash] nor [chunkhash] work).
webpack output文檔種有寫,當(dāng)提取css后,用contenthash添加hash
var webpack = require("webpack"); var WebpackMd5Hash = require('webpack-md5-hash'); var path = require('path'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = {entry: {common: ['jquery', 'lodash'],react: ['react', 'react-redux'],two: "./src/two.js",one: "./src/one.js",},output: {path: path.resolve(__dirname, 'dist'),filename: "[name].[chunkhash:8].js"},module: {rules: [{test: /\.css$/,use: ExtractTextPlugin.extract({fallback: "style-loader",use: "css-loader"})}]},plugins: [new webpack.optimize.CommonsChunkPlugin({name: ['react', 'common'], // 用于提取manifestminChunks: Infinity}),new ExtractTextPlugin("[name].[contenthash:8].css"),new webpack.HashedModuleIdsPlugin(),new WebpackMd5Hash()] }; 復(fù)制代碼這一次,只是修改了輸出的hash,conenthash代表的是文本文件內(nèi)容的hash值,也就是只有style文件的hash值。
執(zhí)行webpack:
one.js和one.css的hash變的不一樣了
接下來,修改one.css
body{color:white; } 復(fù)制代碼再次執(zhí)行webpack:
至此,只有one.css發(fā)生了變化,準(zhǔn)備工作基本就到這里了
四,優(yōu)化多頁打包時(shí)間,穩(wěn)定hash
1,約束入口
因?yàn)槭嵌囗搼?yīng)用,是通過掃入口文件來進(jìn)行的打包,規(guī)則為js文件為入口文件,jsx為引用的資源不被識別為入口
通過BundleAnalyzerPlugin插件分析,發(fā)現(xiàn)有部分組件被打包為了入口,梳理一遍后,重新打包,打包時(shí)間減少了2/3,當(dāng)然這是在填以前的坑
生產(chǎn)打包時(shí)間是74578ms
此時(shí)壓縮和不壓縮的打包時(shí)間也是3倍的關(guān)系:
開發(fā)打包時(shí)間是24780ms
好的,圍繞這兩個(gè)時(shí)間,我們開始優(yōu)化
2,使用UglifyjsWebpackPlugin開啟多線程打包
首先要做的其實(shí)是穩(wěn)定hash,但因?yàn)樯a(chǎn)環(huán)境的打包速度太慢,所以我們先優(yōu)化打包速度,webpack默認(rèn)提供的打包是單線程的
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')module.exports = {plugins: [new UglifyJSPlugin({parallel: true})] } 復(fù)制代碼這個(gè)插件是webpack3提供的,至于低版本webapck的話,需要謹(jǐn)慎處理,不過效果很明顯
現(xiàn)在生產(chǎn)打包時(shí)間是51690ms,比之前提速了1/3
3,使用HappyPack多線程加速loader
var HappyPack = require('happypack'); var os = require('os'); var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });... module: {rules: [ {test: /\.js[x]?$/,exclude: /(node_modules|bower_components)/,loader: 'happypack/loader?id=happybabel',include: path.join(__dirname, 'static/assets/js')}} plugins: [new HappyPack({id: 'happybabel',loaders: ['babel-loader?cacheDirectory=true'],threadPool: happyThreadPool,cache: true,verbose: true}), 復(fù)制代碼上面module的rules屬性中l(wèi)oader原本事babel-loader,現(xiàn)在將它變成了一個(gè)任務(wù),其中有一個(gè)id,id對應(yīng)的就是plugins中的happyPack實(shí)例
此時(shí),我們開啟了babel-loader的多線程模式
現(xiàn)在生產(chǎn)打包時(shí)間是43855ms,比之前又提速了1/9,這只是babel-loader,我們還可以為其它的loader開啟
接著處理less,css,style等loader,這些結(jié)合可以一口氣搞定
module: {rules: [{test: require.resolve('zepto'),loader: 'exports-loader?window.Zepto!script-loader'}, {test: /\.js[x]?$/,exclude: /(node_modules|bower_components)/,loader: 'happypack/loader?id=happybabel',include: path.join(__dirname, 'static/assets/js')}, {test: /\.less$/,use: extractTextPlugin.extract({fallback: "style-loader",// use: ["css-loader" + (ENV ? '?minimize' : ''), "less-loader", "postcss-loader"]use: ["happypack/loader?id=postcss"]})}]} plugins: [new HappyPack({id: 'happybabel',loaders: ['babel-loader?cacheDirectory=true'],threadPool: happyThreadPool,// cache: true,verbose: true}),new HappyPack({id: 'postcss',loaders: ["css-loader" + (ENV ? '?minimize' : ''), "less-loader",'postcss-loader'],threadPool: happyThreadPool,// cache: true,verbose: true}), 復(fù)制代碼這樣,我們即處理了babel,同時(shí)也搞定了css,less,postcss這些loader
上圖happy[任務(wù)名],可以看到打包行為全都開啟了多線程,效果顯著
現(xiàn)在生產(chǎn)打包時(shí)間是35130ms,此時(shí)已經(jīng)比第一此非優(yōu)化的時(shí)候,提升了一倍的速度
4,使用dll拆分代碼
經(jīng)過前面的過程,想必已經(jīng)意識到了純靜態(tài)得庫和組件都需要與打包環(huán)節(jié)分離開,這就需要dll技術(shù)了
dll技術(shù),其實(shí)就是將修改頻率低或基本不修改且引用次數(shù)多的內(nèi)容,單獨(dú)打包
因?yàn)樵O(shè)計(jì)dll后,config文件的數(shù)量劇增,所以需要重新整理目錄結(jié)構(gòu)
例如上圖,將每一個(gè)webpack拆分出去,把所有配置文件分離開,例webpack.dev.js:
var base = require('./webpack.base.js'); var config = {entry: require('./dev/entry.js'),output: require('./dev/output.js'),plugins: require('./dev/plugins.js'),devtool: 'eval-source-map' } //把配置文件暴露出去; module.exports = Object.assign(base,config);復(fù)制代碼ok,基礎(chǔ)拆分webpack完成后,我們創(chuàng)建一個(gè)webpack.dll.libs.js用于打包類庫
module.exports = {libs: ['react','react-dom','react-motion','react-redux','redux','axios','prop-types','classnames',] } 復(fù)制代碼修改plugins插件:
var webpack = require('webpack'); var dirVars = require('../common/dir.js'); var path = require('path'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin');//多線程打包 var getDefaultPlugins = require('../common/plugins.js').getDefaultPlugins; var AssetsPlugin = require('assets-webpack-plugin');//輸出映射表var plugins =[new webpack.DllPlugin({path: dirVars.dllLibsManiFest,}),new UglifyJsPlugin({parallel: true,cache: true}),new AssetsPlugin({filename: 'static/dll/libs-rev-manifest.json'}), ] module.exports = plugins.concat(getDefaultPlugins()) 復(fù)制代碼現(xiàn)在執(zhí)行webpack
可以看到,只需要1s,就打包了所有的類庫,接下來,修改webpack.prod.js
在plugins中添加:
new webpack.DllReferencePlugin({manifest: 'static/dll/libs-rev-manifest.json' }), 復(fù)制代碼此時(shí)當(dāng)我們執(zhí)行webpack.prod.js進(jìn)行打包,當(dāng)掃描到libs中的打包的內(nèi)容時(shí),就不會重復(fù)打包
4,開始繼續(xù)約束hash
前面已經(jīng)徹底搞定了打包,但破壞性很大,所以需要系統(tǒng)的驗(yàn)證hash是否存在問題
case1:js改變
修改一個(gè)業(yè)務(wù)代碼的js,添加一句注釋,再次打包
可以看到文件hash發(fā)生了改變,但很不幸,vendor也發(fā)生了改變
解決方案:添加webpack-md5-hash插件,使用之后,再次驗(yàn)證,發(fā)現(xiàn)vendorjs的hash不再發(fā)生變化
case2:less改變
只有一個(gè)css的hash發(fā)生了變化,沒問題
case3:修改一個(gè)入口下自己封裝出去的公共方法
上面修改了一個(gè)入口內(nèi)公共使用的tools插件,最終是入口的hash發(fā)生了改變,沒問題
case4:修改公共方法組件js
主要是多個(gè)入口都會引用的組件
測試,只有單獨(dú)打包出去的components的hash修改了
case5:修改公共方法組件less
只有一個(gè)hash發(fā)生了改變
case6:添加一個(gè)公共組件
只有components的hash發(fā)生了改變
未優(yōu)化前打包時(shí)間180-200s
優(yōu)化:
1,約束入口,嚴(yán)格明確入口文件篩選條件后生產(chǎn)打包:74578ms開發(fā)打包:24780ms 2,開啟多線程壓縮后生產(chǎn)打包:51690ms 3,開啟多線程編譯生產(chǎn)打包:35130ms開發(fā)打包:15031ms 4,拆包分解了打包過程,類庫4s,組件4s,業(yè)務(wù)20s,總體30s左右 復(fù)制代碼最終,流程變得可控,打包實(shí)現(xiàn)了定制化,hash得到了保持。
總結(jié)
以上是生活随笔為你收集整理的webpack增量打包多页应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 《爆发》摘录
- 下一篇: CentOS 查看系统版本号
