Hello,大家好。
在之前兩篇文章中:
webpack練手項目之easySlide(一):初探webpack
與大家分享了webpack的基本使用方法,以及使用webpack對代碼進行分割,根據需求進行異步加載。
今天我們繼續為大家介紹webpack的其他應用方法,主要包括common chunks以及web-dev-server。
1.Demo與Code
在實際的項目開發過程中,我們的項目中會有很多公共的部分,比如一些第三方的組件,CSS樣式等。通過添加一些配置,webpack在打包過程中自動的提取出這些公共元素,並將其打包到一個獨立的文件中。在頁面上我們只需要引入這個公共的腳本以及頁面單獨的腳本即可。
如果大家注意的話,在上一章中我們使用的Demo就已經使用了common chunks:
Demo:http://xiaoyunchen.github.io/easySlide/
Code:https://github.com/xiaoyunchen/easySlide
為了演示效果,我們新增了一個頁面入口,叫做jsEvent.html,現實的功能也就是之前在 http://www.cnblogs.com/souvenir/p/4988367.html 已經實現的功能,演示JS事件流的傳播。只是這次稍微將代碼改成模塊化的形式。
OK。同一個項目下有兩個頁面(實際項目中會更多入口或者頁面),這兩個頁面都需要引用一些公共的組件,比如頭部導航菜單,footer腳部信息等,這些組件一般都是全站通用的,然后每個頁面進行單獨調用即可。
我們在項目下增加了一個jsEvent的模塊,引入了jsEvent的頁面和調用JS:
關於jsEvent模塊的實現我們稍后再看,先來看看jsEvent入口JS文件的內容:
1 (function(){ 2 //引入公共CSS與頁面CSS
3 require('../../css/vendor/reset.css'); 4 require('../../css/page/jsEvent.css'); 5 require('../../css/module/footer.css'); 6
7 //引入header
8 require("../module/header.js"); 9
10 //引入jsEvent模塊
11 var Delegate=require("../module/jsEvent.js"); 12 var delegate=new Delegate(); 13 delegate.addBodyListener(); 14 delegate.addListElement($('#list1'),$('#btn1')); 15 delegate.addListElement($('#list2'),$('#btn2')); 16
17 })();
同樣的,前三行代碼我們先引入了公共CSS和本頁面所需的CSS。
第8行:引入了header模塊。因為header模塊除了樣式以外只有一個頁面滾動式固定的功能,所以這里也需要調用其任何方法,只需引入該模塊即可。
第11-15行:引入jsEvent模塊,並配置相關事件監聽。關於jsEvent這個模塊的實現大家可以查看之前的文章或者源碼,這里不再作贅述。
同樣的大家可以再來回顧一下Index.js的源碼:
是的,前面引入公共CSS以及引入header部分是完全一致的,這也就是我們所說的common chunks公共部分。
接下來我們再來看webpack.config.js中的配置內容:
在配置文件中先定義了這兩個入口文件:Index與delegate,然后這里新引入了一個新的插件:CommonsChunkPlugin (官方文檔)
new webpack.optimize.CommonsChunkPlugin("commons.js", ["index", "delegate"])
通過這句代碼我們將Index與delegate中的公共部分提取出來並放置在commons.js這個單獨的文件中,所以我們在頁面中除了需要引入index/jsevent以外,還需要引入這個commons。
再來看看CommonsChunkPlugin 的其他配置選項:
minChunks :公共模塊被使用的最小次數。比如配置為3,也就是同一個模塊只有被3個以外的頁面同時引用時才會被提取出來作為common chunks。
minSize:作用類似於minChunks,只不過這里控制的文件大小。
children:這個參數比較有意思,他可以將common chunks不單獨存放,而是將其加入到所引用的頁面JS中進行合並。關於這個參數我也定義了一個webpack.config2.js以及index2.html用於測試,大家使用 webpack --config webpack.config2.js 就能單獨打一次包,然后發現這次並沒有生成commons.js,因為已經被加入到index.js中,所以在index2.html我們只需要引入bundle.js即可。(咦,怎么感覺又回去了呢)
2.header組件
這是一個單獨的組件,功能比較簡單,作為頁面的一個導航,同時在頁面滾動的時候固定在最頂部。
我們來看看具體的實現代碼:
1 (function(){ 2 require('../../css/module/header.css'); 3 4 var headerModule={ 5 config:{ //配置信息,頭部class/多少高度觸發fixed,fixed class名 6 headerDom:$('.headerWrapper'), 7 fixedTop:80, 8 fixedCls:'header-fixed' 9 }, 10 headerFixed:function(){ //切換class 11 if ($(window).scrollTop()>headerModule.config.fixedTop){ 12 headerModule.config.headerDom.addClass(headerModule.config.fixedCls); 13 }else{ 14 headerModule.config.headerDom.removeClass(headerModule.config.fixedCls); 15 } 16 }, 17 init:function(){ //為window綁定scroll事件 18 $(window).bind('scroll',function(){ 19 headerModule.headerFixed(); 20 }); 21 } 22 }; 23 headerModule.init(); 24 module.exports=null; 25 })();
第2行,不多說,引入header模塊所需要的css樣式。
第4行,定義了header組件的實現變量;
第5行,定義了一些配置信息,具體信息大家看注釋。
第10行,headerFixed:判斷當前滾動的高度是否大於咱們的配置,如果是的話就添加一個class。
第17行,init行數:初始化函數,為window綁定了這個scroll滾動事件。
第23-24行,主動調用了init行數,所以這里我們的exports為null,沒有任何需要導出的內容。
這里需要一下兩個問題:
1.關於header的html模板,這里沒有加載器來做異步加載,而是直接寫在每個頁面中的,其實有些增加了維護工作量。實際項目的做法應該是將這個header.html的模板文件獨立出來,然后通過后端的語法(比如PHP或者Java)來進行引入。這個工作如果由前端來完成的話,需要單獨一個HTTP請求同時需要重新渲染DOM,比較消耗瀏覽器的性能,所以不推薦。
2.關於header模塊的配置信息。根據一般組件的做法,這個參數應該是需要是暴露接口,讓調用者可以修改的,但是我們考略到header的特殊性,作為全站的導航菜單,一般都是樣式與功能統一的,所以這里並沒有開放修改接口。
好的,我們來看下最后的頁面效果:
當我們滾動向下滾動頁面后,header上增加了一個class,將header固定在了頁面頂部。
3.web-dev-server
這里再單獨介紹一個webpack的小功能:web-dev-server.
這個功能的作用在於每次修改保存后,webpack將會自動重新對資源進行打包,並且自動刷新頁面。(使用的是socket.io進行通信)
首先通過npm安裝web-dev-server
npm install web-dev-server --save--dev
安裝完成后再通過 web-dev-server 即可啟動server,啟動成功后命令行會出現如下的提示:
webpack:bundle is now VALID.
然后我們只需要訪問 http://localhost:8080/ 就可以訪問到我們的項目頁面。
可以嘗試修改一下任何一個資源文件,然后會發現控制台上webpack重新進行了編譯,而且瀏覽器也自動進行了刷新,無需我們手動干預。(雙屏開發的同學可以開始鼓掌了...)
小結:
截止到這里為止,我們對webpack的學習就暫時告一個段落。
webpack是一款非常優秀的前端模塊化打包工具,他還有很多實用的功能,因為目前我的項目中還沒有涉及到,所以還沒來得及做深入研究。比如對react/angularjs這樣的前端框架,LESS/JADE等這些模板或者css工具的編譯與支持,同時還兼容了AMD/CommonJS/ES6語法,功能十分強大,值得我們好好研究。