今天我們繼續來進行webpack工程化開發的探索!
首先來驗證上一篇文章 基於webpack的前端工程化開發解決方案探索(一):動態生成HTML 中的遺留問題:webpack將如何處理按需加載的資源,還能繼續通過AJAX進行異步加載嗎?
1. require.ensure
在上一章我們已經知道通過require引入的資源,可以通過插件讓webpack將其獨立成為單獨的文件,然后向HTML中自動寫入路徑。那對於require.ensure情況又會是怎樣的情況呢?
我們都知道webpack通過require.ensure來對我們的代碼進行分割,將按需加載的代碼單獨放在的塊文件chunk中,然后在合適的時候異步加載進入文檔中。
在webpack中引入的提取文件插件,是否影響這一功能呢?
同樣的,這次我們對上次的項目進行了改動,具體代碼可以查看: https://github.com/xiaoyunchen/webpack
首先,我們在JS下新增了一個components文件夾,用於存放自定義的組件,然后定義了一個dialog組件(dialog的實現請參考之前的文章,本章將對本部分進行簡化處理)。
在dialog組件中我們定義了dialog所需的HTML模板,CSS樣式文件,以及入口文件Index.js(如果模塊邏輯層次很復雜的話,這里還可以再新建兩個關於模板和樣式的子目錄)
我們稍微看下index.js的內容:
1 (function(){ 2 //加載模塊CSS 3 require('./dialog.css'); 4 //加載模板 5 var html=require('./dialog.html'); 6 7 module.exports=function(text){ 8 $('body').append(html); 9 $('.dialog:last-child').html(text); 10 }; 11 12 })();
這里只是出於演示使用,所以實現的功能與邏輯比較簡單。就是引入了所需的模板和樣式文件,然后導出一個方法,改方法將會向body插入一個元素。
OK,我們再來看下page目錄下index.js這個入口文件的變動:
1 //引入CSS 2 require("../../css/lib/reset.css"); 3 require("../../css/common/global.css"); 4 require("../../css/page/index.css"); 5 6 //增加事件 7 $('#btn').click(function(){ 8 require.ensure(['../components/dialog/index.js'],function(require){ 9 var Dialog=require('../components/dialog/index.js'); 10 new Dialog(new Date()-0); 11 }); 12 });
第7行,為頁面的一個按鈕添加了點擊事件,點擊后加載dialog組件,然后生成一個dialog實例。
再來看看webpack配置中添加了什么內容:
可以看出配置文件並沒有太大的變化,這里主要是:
18行:增加了HTML加載器,用於加載HTML模板
22行:引入全局jq,方便其他JS調用
在項目根目錄下運行 webpack 打包命令后,可以看到dist/js下多了1.chunk.js文件。其實看到這里大家也就放心了,webpack的確正確處理了這種按需加載的關系。
然后運行dist/view/index.html,打開控制台觀察資源加載。
一開始並沒有加載dialog組件,點擊按鈕后,瀏覽器開始異步加載dialog組件,然后生成對應的HTML.
這里有個問題需要單獨說明下,require.ensure 被webpack編譯后在執行的時候會自動判斷該模塊已經下載,如果已經下載就不會再重復請求。
2. 圖片加載
借助於url-loader這個加載器,在webpack中我們可以比較優雅的處理圖片加載的問題。所謂的比較優雅,是指:
1. webpack可以將所用到的圖片自動拷貝到輸出目錄下,同樣可以為其添加hash版本號
2. 對於比較文件比較小的圖片,webpack可以將其自動轉換了BASE64字符串進行存儲,減少一次HTTP請求
接下來我們來做下演示:
我們在dialog組件目錄下增加一張圖片(圖片大小15k左右),然后修改了dialog組件的模板,在其中引入了該張圖片。這樣每次我們點擊按鈕的時候,瀏覽器都會顯示這張圖。
另外我們在 global.css進行修改,為body添加一張背景圖片,由於這個圖很小(1KB),所以我們將背景圖設置為重復。
1 body{
2 font: "微軟雅黑";
3 background: url(../../img/mask.png) repeat scroll 0 0;
4 }
最后,我們在webpack配置文件中,為圖片引入url-loader加載器,同時為其指定存放路徑和文件名:
1 module: { 2 loaders: [ //加載器
3 {test: /\.css$/, loader:ExtractTextPlugin.extract("style", "css") }, 4 {test: /\.html$/, loader: "html" }, 5 {test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=./img/[hash].[ext]'} 6 ] 7 }
生成的圖片存放在dist/img下,然后為了混淆,我們將圖片文件名設置為其hash值。
同時我們配置了limit參數,當圖片大小小於這個值的時候,webpack都將會轉換為base64字符串進行存儲。
然后在項目根目錄下運行 webpack 命令進行打包,然后運行生成index.html文件:
點擊ADD按鈕后瀏覽器才發起異步請求,加載了dialog組件以及我們所引入的圖片資源,同時圖片名稱已經被設置為hash值。
再來看看樣式中引入的圖片:
可以看到這個背景圖已經轉換成BASE64字符串寫入css文件中,所以這里就減少了一次圖片請求。這是一種比較常用的優化頁面性能的方式。
上面說到webpack的這種處理方式是一種比較優雅的處理方式,那又有哪些地方不夠完善呢?
1. 上面寫入模板中的圖片webpack可以幫我們處理,但是src/view目錄下的用於生成最終HTML的模板,webpack並不會對其中所引入的圖片進行提取處理,導致圖片路徑不對。
2. 這里只是對圖片進行了提取,其實並未對圖片進行任何優化處理,比如合並小圖標,限制圖片質量避免圖片過大等。
當然了,這些都是屬於額外需求,已經有些超出了webpack所承載的功能范疇。實際項目中如果出現上述需求的話,個人建議是單獨安裝grunt,然后調用grunt插件來完成相關任務。