webpack 分批打包、按需下載

來源:互聯網
上載者:User

標籤:

  之前一直維護的一段廣告js,我都是用webpack作為模組管理的,由於這種CommonJS的先行編譯打包模式,我把所有的模組都封裝到一個js裡面了,請求少了、檔案大了。好在大部分的功能模組都是我手動寫的,引用的三方庫並不多,檔案大小還是可控的。但是隨著業務發展的需要,廣告的展示效果越來越豐富,單純的靠“造輪子”,很難高效率、高品質的完成需求。我開始考慮使用一些三方js外掛程式完成一些特定的功能,一來對於很多的特效,它們的方案很成熟、穩定、複用性高。另一個方面,省去了自己開發的成本,可以更快速的完成開發。

  使用三方js外掛程式本就是一件很正常的事,可是我又在糾結什麼呢?這不得不和我的自身架構有關,我用webpack把所有的模組打包在一起,但是三方js外掛程式對應的需求並不是每次開啟頁面都要展示,而是依賴著資料請求的返回結果,換句話說我的js並不是經常依賴這個外掛程式,並且外掛程式是一類需求(並非一個)的解決方案,體積不會太小,以我使用的三方外掛程式為例就有77kb而My Code本身在壓縮前也才127kb。將外掛程式混入必然造成檔案大小的增大、載入時間變長、廣告渲染延遲等一些列問題。何況隨著業務的發展,我將來要引用的三方外掛程式不止一個。遇事我想到了曾經偶爾看到webpack中的解決方案——Code Splitting。

  簡單來說就是按需載入(下載),如果是requireJS對應的AMD的方案中這本是在正常不過了。但是在webpack中All in one的思想就會顯得很怪,但webpack並不死板(就像某著名AMD和CMD模組管理器中都有對方陣營的實現方案)。我查閱了不少的文檔和論壇,終於找到了webpack中對於按需下載的支援方案(此處想吐槽webpack官方文檔),好多的論壇文章都提到了使用require.ensure 但是卻寫得很簡略,直接使用發現行不通、感覺少了點啥,比如下面的寫法:

1 require.ensure([‘需要動態載入的module‘], function(require) {2     require(‘需要動態載入的module‘);3 });4 //webpack會自動產生動態載入代碼,結果和ensure產生的是一樣的

  我這裡就詳細整理一下,這種用法到底怎麼用。對應的配置、發布流程是什麼樣的。

  webpack的整體風格是All in one 就是將從入口檔案開始的所有引用到的模組都打包到一個js檔案(包括css 、圖片,這裡只說js)。在打包的過程中會有一系列的名稱替換,細心的朋友會發現我們的模組被命名為更加簡單,節省空間的數字了。不同於requireJS可以直接require線上檔案的方式。webpack推薦將所有可能用到的檔案(模組)都打包。但是這樣做僅適合使用率較高的小體積模組。對於體積大有不常用的模組,反而顯得不適合。如果你嘗試過在webpack工程中直接require線上url。啟動並執行時候會拋出一個異常——不能找到模組,那是因為對於打包後的js中預設是在這個包內尋找模組,或者說webpack工程中的require函數預設是在包(檔案)內找,壓根兒就沒打算髮起http請求。所以就不要想直接require線上的url了。

  拿到webpack工程就只能打包在一起,搞出一個超大的檔案,把頁面卡住?webpack官方給出瞭解決方案——Code Splitting。這種方式並不代表webpack有意投靠AMD,而是另闢蹊徑彌補了自身的短板。簡單來說,還是All in one 還是打包成一個包,還是在包內部找模組,只是這一個包不一定只有一個檔案。我們直譯Code Splitting為“代碼拆分”,也就是說我們可以理解為將all in one的包在拆成多個包,當需要引用的時候再引用下載、載入,只是這種載入是通過webpack內部機制發起http請求實現的。我們將摸個不常用的大體積模組從包中分離出來,當包內的語句引用到了這個模組後,webpack會判斷這個模組是被分離出去的,應當發起http請求拉取。不是不能拉向上模組,只是只拉和自己有淵源的模組。

  那麼webpack怎麼知道這個模組被分離了?這就降到了上面提到的 require.ensure ,通過不同的API就相當於一種標記,在打包時分出去、引用時發請求動態載入。其實大家最關心的是怎麼用?舉個例子:我要引用A、B、C、D 四個外掛程式,A、C可能往往一起用,B、D可能往往一起用。我就需要在webpack打包後產生3個檔案:包含主檔案的js(大量常用模組)、包含A和C的分離包、包含B和D的分離包。

 1 /*別的事XXXX*/ 2 if(bIsAC === true ){ 3     require.ensure(["A","C"], function(require){ 4     var A = require(‘A‘); 5         var C = require("C"); 6         var ac = A+C; 7     /*一大堆商務邏輯*/ 8     });  9 10 }else{11      require.ensure(["B","D"], function(require){12     var B = require(‘B‘);13         var D = require("D");14         var bd = B+D;15     /*一大堆商務邏輯*/16     });     17 }18 /*別的事XXXX*/

 這時候編譯webpack,會產生3個檔案。如果你在webpack.config.js檔案中定義輸出是bundle.js,同時還會產生兩個檔案1.bundle.js和2.bundle.js,把他倆放在我們實驗的頁面的同一級目錄下載會發現頁面先載入bundle.js。然後根據條件載入1.bundle.js或2.bundle.js。為了更直觀的看到現象我去掉了if判斷載入3個檔案()。

 問題來了:兩個分離的模組檔案一定要放在頁面同一級嗎?當然是可以自訂的。有一個細節,我們並沒有設定過引用1.bundle.js和2.bundle.js的線上url的語句,看來它必然是有預設設定的。如果對webpack有瞭解的朋友一定會想到webpack.config.js檔案。就是兩個分離檔案的根路徑:

它會直接影響編譯後的    __webpack_require__.p = "http://yoururl.com/";進而影響下面的路徑:

  這樣就利用Code Splitting實現了webpack的分批打包、按需下載

  

  

 

webpack 分批打包、按需下載

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.