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個請求,這其中其實並沒有包含我們的對話框組件:

    

 

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

    

    這個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比較類似:

   

    第10-11行:加載了dialog組件的HTML模板,並將其放置在body中。嗯,之所有是要使用html模板也是為了解耦合,方便對模板和JS進行單獨維護。這里webpack在打包的時候

  會自動將html模板壓縮成字符串保存在chunk文件中。

    第16-44行:定義了dialog組件的幾個接口方法,其中openDialogWith 就是我們之前調用的根據配置內容更新dialog DOM信息,然后將dialog展示出來。

  

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

    

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

    其實我這里的組件定義還有一個問題:

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

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

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

  

  

    小結:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM