gulp webpack整合
為什么需要前端工程化?
前端工程化的意義在于讓前端這個行業由野蠻時代進化為正規軍時代,近年來很多相關的工具和概念誕生。好奇心日報在進行前端工程化的過程中,主要的挑戰在于解決如下問題:
? 如何管理多個項目的前端代碼?
? 如何同步修改復用代碼?
? 如何讓開發體驗更爽?
項目實在太多
之前寫過一篇博文?如何管理被多個項目引用的通用項目?,文中提到過好奇心日報的項目偏多(PC/Mobile/App/Pad),要為這么多項目開發前端組件并維護是一個繁瑣的工作,并且會有很多冗余的工作。
更好的管理前端代碼
前端代碼要適配后臺目錄的規范,本來可以很美好的前端目錄結構被拆得四分五裂,前端代碼分散不便于管理,并且開發體驗很不友好。
而有了前端工程化的概念,前端項目和后臺項目可以徹底分離,前端按自己想要的目錄結構組織代碼, 然后按照一定的方式構建輸出到后臺項目中,簡直完美(是不是有種后宮佳麗三千的感覺)。
技術選型
調研了市場主流的構建工具,其中包括gulp、webpack、fis,最后決定圍繞gulp打造前端工程化方案,同時引入webpack來管理模塊化代碼,大致分工如下:
webpack:管理模塊化,構建js/css。
至于為什么選擇gulp & webpack,主要原因在于gulp相對來說更靈活,可以做更多的定制化任務,而webpack在模塊化方案實在太優秀(情不自禁的贊美)。
怎么設計前端項目目錄結構?
抽離出來的前端項目目錄結構如下
前端項目結構 appfe目錄:appfe就是前面提到的前端項目,這個項目主要包含兩部分:前端代碼、構建任務
appfe > gulp目錄:包含了所有的gulp子任務,每個子任務包含相關任務的所有邏輯。
appfe > src目錄:包含了所有前端代碼,比如頁面、組件、圖片、字體文件等等。
appfe > package.json:這個不用說了吧。
appfe > gulpfile.js:gulp入口文件,引入了所有的gulp子任務。
理想很豐滿,現實卻很骨感,這么美好的愿望,在具體實踐過程中,注定要花不少心思,要踩不少坑。
好奇心日報這次升級改造即將上線,終于也有時間把之前零零碎碎的博文整合在一起,并且結合自己的體會分享給大家,當然未來可能還會有較大的調整,這兒拋磚引玉,大家可以參考思路。
gulp 是什么?
gulp是一個基于流的構建工具,相對其他構件工具來說,更簡潔更高效。
Tip:之前寫過一篇gulp 入門,可以參考下,如果對gulp已經有一定的了解請直接跳過。
webpack 是什么?
webpack是模塊化管理的工具,使用webpack可實現模塊按需加載,模塊預處理,模塊打包等功能。
Tip:之前寫過一篇webpack 入門,可以參考下,如果對webpack已經有一定的了解請直接跳過。
如何整合gulp & webpack
webpack是眾多gulp子任務中比較復雜的部分,主要對JS/CSS進行相關處理。
包括:模塊分析、按需加載、JS代碼壓縮合并、抽離公共模塊、SourceMap、PostCSS、CSS代碼壓縮等等...
webpack-stream方案[不推薦]
使用webpack-stream雖然可以很方便的將webpack整合到gulp中,但是有致命的問題存在:
如果關閉webpack的監聽模式,那么每次文件變動就會全量編譯JS/CSS文件,非常耗時。
如果打開webpack的監聽模式,那么會阻塞其他gulp任務,導致其他gulp任務的監聽失效。
所以這種方案幾乎不可用!
webpack原生方案
直接使用webpack原生方案,相對來說更靈活。
Tip:代碼較復雜,里面涉及的知識點也很多,建議看看形狀就好,如果真有興趣,可以好好研究研究,畢竟花了很長時間去思考這些方案。
實踐中遇到那些坑?
如何組織gulp任務?
由于gulp任務較多,并且每個核心任務都有關聯任務,比如webpack的關聯任務就有
webpack/ watch:webpack/ build:webpack/ clean:webpack,如何組織這些子任務是一個需要很小心的事情,出于一直以來的習慣:把關聯的邏輯放在一起,所以我的方案是webpack相關的任務放到一個文件,然后定義了 default/ clean/ watch/ build四個入口任務來引用對應的子任務。webpack任務結構
gulp怎么實現錯誤自啟動
使用watch模式可以更高效的開發,監聽到改動就自動執行任務,但是如果過程中遇到錯誤,gulp就會報錯并終止watch模式,必須重新啟動gulp,簡直神煩!
利用gulp-plumber可以實現錯誤自啟動,這樣就能開心的在watch模式下開發且不用擔心報錯了。
進一步結合gulp-notify,在報錯時可以得到通知,便于發現問題。
gulp怎么處理同步任務和異步任務
同步任務:gulp通過 return stream的方式來結束當前任務并且把 stream傳遞到下一個任務,大多數gulp任務都是同步模式。異步任務:實際項目中,有些任務的邏輯是異步函數執行的,這種任務的return時機并不能準確把控,通常需要在異步函數中調用 callback()來告知gulp該任務結束,而這個 callback什么都不是,就是傳到該任務中的一個參數,沒有實際意義。 // 同步任務 gulp.task('views', function() { return gulp.src(config.src) .pipe(plumber(handleErrors)) .pipe(gulp.dest(config.dest)); }); // 異步任務 gulp.task('webpack', function(callback) { webpack(config, function(err, stats) { compileLogger(err, stats); callback(); //異步任務的關鍵之處,如果沒有這行,任務會一直阻塞 }); });
webpack怎么抽出獨立的css文件
webpack默認是將css直接注入到html中,這種方法并不具有通用性,不推薦使用。
結合使用
webpack怎么抽出通用邏輯和樣式
沒有webpack之前,想要抽離出公共模塊完全需要手動維護,因為js是動態語言,所有依賴都是運行時才能確定,webpack可以做靜態解析,分析文件之間的依賴關系,使用
CommonsChunkPlugin就可以自動抽離出公共模塊。 // webpack.config.js var webpack = require('webpack'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: { 'homes/index': 'pages/homes/index.js' }, output: { filename: "[name].js" }, module: { loaders: [{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }] }, plugins: [ //抽離公共模塊,包含js和css new webpack.optimize.CommonsChunkPlugin("commons", "commons.js"), new ExtractTextPlugin("[name].css") ] }webpack的watch模式
webpack相對來說比較耗時,尤其是項目較復雜時,需要解析的文件較多。好奇心日報web項目首次全量執行webpack任務大概需要10s,所以必須引入增量構建。增量構建只需要簡單的給webpack配置添加watch參數即可。
webpack任務輸出日志
但是問題在于,如果給webpack-stream添加watch參數,webpack-stream的任務會阻塞其他的watch任務,最后導致其他任務的增量構建失效。
所以如果要使用webpack的增量構建,需要使用原生的webpack方案!
靈活的webpack入口文件
webpack入口文件接收三種格式:字符串,數組,對象,對于多頁應用場景,只有對象能夠滿足條件,所以我們把所有的入口文件全部列出來即可。
但這種方案極不靈活,借鑒gulp的方案,是否可以讀取某個文件下的所有入口文件呢?為了解決這個問題,自定義了一個函數來實現該功能。
webpack的development/production配置合并
webpack任務的development配置和production配置差異巨大,并且各自擁有專屬的配置。
由于
webpack怎么線上模式異步加載js文件
webpack可以將js代碼分片,把入口文件依賴的所有模塊打包成一個文件,但是有些場景下的js代碼并不需要打包到入口文件中,更適合異步延遲加載,這樣能最大程度的提升首屏加載速度。
比如好奇心日報的登錄浮層,這里面包含了復雜的圖片上傳,圖片裁剪,彈框的邏輯,但是它沒必要打包在入口文件中,反倒很適合異步延遲加載,只有當需要登錄/注冊的時候才去請求。
圖片上傳裁剪
我們可以通過webpack提供的
require及 require.ensure來實現異步加載,值得一提的是,除了指定的異步加載文件列表,webpack還會自動解析回調函數的依賴及指定列表的深層次依賴,并打包成一個文件。但是實際項目中還得解決瀏覽器緩存的問題,因為這些異步JS文件的時間戳是rails生產的,對于webpack是不可知的,也就是說請求這個異步JS文件并不會命中。
為了解決這個問題,我們在rails4中自定義了一個rake任務:生產沒有時間戳版本的異步JS文件。
rake任務
上圖中還有一個小細節就是,這些異步JS文件有兩個時間戳,前者為webpack時間戳,后者為rails時間戳,之所以有兩個時間戳,是為了解決瀏覽器緩存的問題。
簡而言之就是:
通過
通過自定義rake任務,來生成沒有rails時間戳的異步JS文件,解決webpack不識別rails時間戳的問題。
通過webpack的chunkFileName配置,給異步JS文件加上webpack時間戳,解決瀏覽器緩存的問題。
?
學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入學習交流群
343599877,我們一起學前端!
總結
以上是生活随笔為你收集整理的gulp webpack整合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在 React Native 中写一
- 下一篇: Html5 填表 表单(二) input