天天看點

webpack練手項目之easySlide(二):代碼分割

Hello,大家好。

在上一篇 webpack練手項目之easySlide(一):初探webpack  中我們一起為大家介紹了webpack的基本用法,使用webpack對前端代碼進行子產品化打包。

但是乍一看webpack隻是将所有資源打包到一個JS檔案中而已,并沒有做到真正的按需加載,這當然不是我們所想要的。

不急,今天的這一章我們就來一起繼續探索webpack的另外一個功能:code split.

  1.什麼是code split

   英文不好,暫且将其翻譯為代碼分割。也就是我們根據實際業務需求将代碼進行分割,然後在合适的時候在将其加載進入文檔中。

  這裡舉一個實際應用場景:上次我們做的圖檔輪播,我們為每張圖檔都添加一個點選事件,點選以後我們彈出一個對話框,裡面介紹一些詳細内容,然後可以點選關閉按鈕進行關閉。

  在這個需求中我們發現,對話框這個元件比較特殊,他是在使用者點選圖檔以後才需要加載,如果使用者不點選,那麼他就沒有必要加載出來了。

  OK,很好。webpack通過code split方法将頁面必須加載的資源放在bundle.js中,然後對于按需加載的資源通過ajax進行異步加載。

  webpack通過 require.ensure 來判斷是否對資源進行按需加載。

  下面是官網的簡單用例:

1 require.ensure(["module-a", "module-b"], function(require) {
2     var a = require("module-a");
3     // ...
4 });      

  

    

   2.Demo與Code

    同樣的,我已經将上面所說的對話框按需加載實作,大家感興趣的話可以前往檢視:

    Demo:  http://xiaoyunchen.github.io/easySlide/

    Code:   https://github.com/xiaoyunchen/easySlide

    大家可以打開控制台網絡面闆,檢視資源的加載情況:

    頁面加載的時候隻有7個請求,這其中其實并沒有包含我們的對話框元件:

webpack練手項目之easySlide(二):代碼分割

    然後大家可以點選任意一張圖檔,這個時候網絡浏覽器發送了新的網絡請求,然後頁面上也打開了對話框:

webpack練手項目之easySlide(二):代碼分割

    這個2.chunk.js也就是webpack為我們打包的對話框元件,包括JS邏輯,HTML模闆以及CSS樣式,稍後我們将為大家作詳細介紹。

    (demo上有幾個menu的link,大家先不用管,那是我們下一章将要介紹的内容)

   3.元件引用與webpack打包

    接下來我們來看看代碼上都發生了哪些變動。

    首先是index.html與index.css,并沒有任何修改。(index.html中增加了header與footer,增加了多個圖檔輪播元件,為下一章做的準備。但是都與對話框元件沒有任何關系)

    那來看看index.js的修改,具體的源碼大家可以檢視github,這裡隻對後面新增的代碼進行分析:

1 //添加對話框事件
 2     var pageDialog=false;
 3     $('.pictureShow a').click(function(){
 4         var _id=$(this).attr('dialog-for');
 5         require.ensure(["../module/dialog.js","../module/dialogConfig.js"], function(require) {
 6             var dialogModule=require("../module/dialog.js");
 7             var dialogConfig=require("../module/dialogConfig.js");
 8             if(!pageDialog){    //判斷對話框元件是否存在,避免重複建立
 9                 pageDialog=new dialogModule();
10             }
11             pageDialog.openDialogWith(dialogConfig[_id]);
12         });
13     });      

    首先我們定義了一個對象,然後為頁面上所有的滑動元素增加了一個單擊事件。

    第4行:擷取目前事件元素的dialog-for屬性,這是我們在每個滑動元素上新增的屬性,用于指定其對應的對話框id

    第5行:使用了webpack的require.ensure異步加載了兩個元件:dialog與dialogConfig,這兩個元件分别是對話框的具體實作邏輯以及對話框内容配置資訊,詳細的代碼我們後面再分析

    第6/7行:加載完成後得到兩個元件的引用

    第8-10行:判斷pageDialog是否存在,如果不存在我們通過調用dialog元件new一個執行個體,并将指派給pageDialog。

    這裡主要是為了避免多次點選時頁面重複建立dialog Html元素,降低頁面性能

    第11行:使用pageDialog執行個體,調用openDialogWith方法來打開對話框,同時要從dialogConfig中加載指定的對話框配置内容。

    是的,哪怕是在我們沒有檢視dialog元件具體源碼的情況下,整個邏輯還是相對比較清晰的。我們不用理會dialog元件調用了什麼模闆,用了什麼css樣式,内部實作了哪些方法。

    定義元件的一大目的就是降低代碼之前的耦合性,作為元件,我隻管定義如何實作一個元件;作為元件調用者,我隻管衣來伸手飯來張口的拿來主義,

    不管你内部是如何實作的。

    接下來看webpack是如果對上面的代碼進行打包的:

    以下是webpack.config.js配置檔案部分内容:

1 module.exports = {
 2     entry: {
 3             index:"./src/js/page/index.js",
 4             delegate:"./src/js/page/jsEvent.js"
 5         },
 6     output: {
 7         path: path.join(__dirname,'dist'),
 8         publicPath: "/easySlide/dist/",
 9         filename: "[name].js",
10         chunkFilename: "[id].chunk.js"
11     },
12     module: {
13         loaders: [    //加載器
14             {test: /\.css$/, loader: "style!css" },
15             {test: /\.html$/, loader: "html" },
16             {test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
17         ]
18     }
19     
20 };      

    改動的地方不多,主要是以下幾點:

  第10行:定義了chunk的檔案名命名規則,這裡除了id以外,還可以使用[hash]

  第8行:publicPath 這個配置很容易被疏忽。我們的chunk檔案預設是跟bundle放在一塊的,都是在dist目錄下,如果不配置正确的publicPath的話,webpack請求chunk檔案時将會預設請求根目錄

  第15行:新增了HTML加載器,主要是給dialog元件加載模闆使用的

  codeSplit作為webpack一個比較核心的功能,是以也需要額外的plugins插件配置就能支援。

  在項目根目錄下運作 webpack 打包指令以後可以看到dist目錄下就會新增一個 2.chunk.js檔案 (2是chunk的ID值)

  值得一提的是,chunk檔案完全由webpack進行管理和使用,我們無需額外的幹預

  4.dialog元件的實作

    dialog的實作原理比較簡單,我們定義了一個dialog容器,通過css控制其固定在整個頁面之上,然後在生成一個mask陰影層。

    具體的實作css樣式大家也可以前往github檢視源碼。

    dialog元件的實作方法也是與我們之前做的slideModule比較類似:

   

webpack練手項目之easySlide(二):代碼分割

    第10-11行:加載了dialog元件的HTML模闆,并将其放置在body中。嗯,之所有是要使用html模闆也是為了解耦合,友善對模闆和JS進行單獨維護。這裡webpack在打包的時候

  會自動将html模闆壓縮成字元串儲存在chunk檔案中。

    第16-44行:定義了dialog元件的幾個接口方法,其中openDialogWith 就是我們之前調用的根據配置内容更新dialog DOM資訊,然後将dialog展示出來。

    對于dialogConfig我們也簡單的來看下:

webpack練手項目之easySlide(二):代碼分割

    這裡全部都是對話框的資料配置項,單獨維護的好處也是解耦合,以外咱們可以将這些資料配置在資料庫中,通過接同樣的接口格式傳回來就行了。

    其實我這裡的元件定義還有一個問題:

    我們是将自定義的對象直接作為元件導出,開放給調用者使用。這在操作上其實存在一定的風險性,因為所有接口方法和屬性都是開放的,那就有可能被使用者

  給篡改,影響到元件的正常使用。正确的做法是:

    在元件内部定義一個私有變量,使用者存放元件所有屬性與方法,然後再将接口方法(一般不建議開放屬性給調用者直接修改)導出給調用者使用。

    小結:

      通過webpack的codeSplit方法我們可以對代碼進行按需分割以及加載,進而到達頁面性能的最優。

繼續閱讀