1. 程式人生 > >基於CommonsChunkPlugin,webpack打包優化

基於CommonsChunkPlugin,webpack打包優化

affect emp epc ace extract 前端 創建 ring 關聯關系

前段時間一直在基於webpack進行前端資源包的瘦身。在項目中基於路由進行代碼分離,http://www.cnblogs.com/legu/p/7251562.html。但是打包的文件還是很大,特別是通過CommonsChunkPlugin的async:true打包的chunk的公共包不可控。今天就通過CommonsChunkPlugin插件的理解,來優化這個問題

  問題描述詳細些,我們的打包是基於router進行的chunk分割,比如router有10個,router1,router2用到了echart,所以echart打包到了公共文件async中。但是如果用戶通過鏈接,

  第一次直接訪問的router3,這樣就會先加載公共文件async,可是echart代碼其實是多余的,影響到了router3的展現。

  一開始遇到這個問題,沒想到太好的方法,讓echart基於chunk進行按需打包~~實在沒辦法,最後只能從CommonsChunkPlugin插件的源代碼入手,看看有什麽啟發。

  

 1     apply(compiler) {
 2         compiler.plugin("this-compilation", (compilation) => {
 3             compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
 4                 /*
* 5 * 根據chunkNames[options.name, options.names],從chunks中篩選出targetChunks, 沒有則使用compilation.addChunk新增 6 * 如果children || async,返回targetChunks = chunks 7 */ 8 const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this
.children, this.async); 9 targetChunks.forEach((targetChunk, idx) => { 10 /** 11 * 根據selectedChunks【options.chunks】,從chunks篩選出affectedChunks 12 * async || children,返回 affectedChunks = targetChunk.chunks, 如果children = true,進行深度遍歷 13 */ 14 const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children, this.deepChildren); 15 let asyncChunk; 16 if(this.async) { 17 //如果async==string,進行name篩選 18 asyncChunk = affectedChunks.filter(c => c.name === this.async)[0]; 19 if(!asyncChunk) { 20 /** 21 * 根據async創建一個新的chunk,和targetChunk綁定關系 22 * asyncChunk.addParent(targetChunk); targetChunk.addChunk(asyncChunk); 23 */ 24 asyncChunk = this.createAsyncChunk( 25 compilation, 26 targetChunks.length <= 1 || typeof this.async !== "string" ? this.async : 27 targetChunk.name ? `${this.async}-${targetChunk.name}` : 28 true, 29 targetChunk 30 ); 31 } 32 targetChunk = asyncChunk; 33 } 34 // 根據minChunks的設置,遍歷affectedChunks的modules,返回符合條件的公共modules集合 35 const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk); 36 if(this.minSize) {// minSize限制邏輯 37 const modulesSize = this.calculateModulesSize(extractableModules); 38 if(modulesSize < this.minSize) 39 return; 40 } 41 // affectedChunks中移除extractableModules中modules的關系,只返回存在公共modules的Chunks集合(removeChunk返回true) 42 const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks); 43 // 公共的modules 和 targetChunk 綁定關聯關系 44 // chunk.addModule(module); module.addChunk(chunk); 45 this.addExtractedModulesToTargetChunk(targetChunk, extractableModules); 46 if(this.filenameTemplate) 47 targetChunk.filenameTemplate = this.filenameTemplate; 48 if(this.async) { 49 //被移除modules的Chunk,設置和targetChunk的關系,需要第一個加載targetChunk才能加載chunksWithExtractedModules 50 this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk); 51 asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules); 52 return; 53 } 54 //設置affectedChunks和targetChunk的parent關系 55 this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk); 56 }); 57 return true; 58 }); 59 }); 60 }

  代碼邏輯不是很復雜,主要是chunks之間的關系和chunks與modules之間的關系該怎麽去維護,對於不清楚webpack打包機制的人,很難一時間了解。其實我也不很了解。

  根據上面我的中文註釋,對大家的了解有一些幫助。我們會發現,對我們的問題沒有什麽直接關系。

  回到我們的問題,異步的模塊中,共用模塊怎麽能再進行拆分,把大模塊echarts,ace編輯器等進行分開打包,並且能自己處理關系,需要的時候才異步加載進來?

  其實最後問題的答案很簡單,需要實現自動異步加載,那肯定還是要借助CommonsChunkPlugin的async,我們可以根據實際情況,通過minChunks,把echarts,ace這種大庫先進行一次async打包,這樣再進行根據router的async打包的時候,自然不會再有echarts,ace了,看下現在的配置

 1         new webpack.optimize.CommonsChunkPlugin({
 2             names: [‘vendor‘, ‘libs‘, ‘manifest‘]
 3         }),
 4         new webpack.optimize.CommonsChunkPlugin({
 5             async: ‘brace‘,
 6             minChunks: function(module, count) {
 7                 var path = `/public/node_modules`;
 8                 var resource = module.resource;
 9                 if ( resource && 
10                         (
11                             resource.indexOf(`${path}/_brace`) !== -1 ||
12                             resource.indexOf(`${path}/brace`) !== -1
13                         )
14                 ) {
15                     return true
16                 }
17                 return false;
18             }
19         }),
20         new webpack.optimize.CommonsChunkPlugin({
21             async: ‘echarts‘,
22             minChunks: function(module, count) {
23                 var path = `/public/node_modules`;
24                 var resource = module.resource;
25                 if ( resource && 
26                         (
27                             module.resource.indexOf(`${path}/_echarts`) !== -1 ||
28                             module.resource.indexOf(`${path}/echarts`) !== -1 ||
29                             module.resource.indexOf(`${path}/zrender`) !== -1 ||
30                             module.resource.indexOf(`${path}/_zrender`) !== -1 
31                         )
32                 ) {
33                     return true
34                 }
35                 return false;
36             }
37         }),
38         new webpack.optimize.CommonsChunkPlugin({
39             async: ‘async‘,
40             minChunks: 2
41         }),

  

基於CommonsChunkPlugin,webpack打包優化