今天我們繼續來進行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外掛來完成相關任務。