webpack多頁應用架構專題系列 3
第三章:整合第三方工具
教練我要寫ES6!webpack怎麼整合Babel?
前言
一直以來,我對ES6都不甚感興趣,一是因為在生產環境中使用ES5已是處處碰壁,其次則是隻當這ES6是語法糖不曾重視。只是最近學習react生態,用起babel來轉換jsx之餘,也不免碰到諸多用上ES6的教程、案例,因此便稍作學習。這一學習,便覺得這語法糖實在是甜,忍不住嚐鮮,於是記錄部分自覺對自己有用的方法在此。
這是我數月前的一篇文章《ES6部分方法點評(一)》中的一段,如今再看我自己的程式碼,觸目皆是ES6的語法。在當前的瀏覽器市場下,想在生產環境用上ES6,Babel是必不可少的。
由於我本身只用了ES6的語法而未使用ES6的其它特性,因此本文只介紹如何利用webpack整合Babel來編譯ES6的語法,而實際上若要使用ES6的其它屬性甚至是ES7(ES2016),其實只需要引入Babel其它的preset/plugin即可,在用法上並無多大變化。
用到哪些npm包?
首先要說到的是babel-loader
,這是webpack整合Babel的關鍵,我們需要配置好babel-loader來載入那些使用了ES6語法的js檔案;換句話說,那些本來就是ES5語法的檔案,其實是不需要用babel-loader來載入的,用了也只會浪費我們編譯的時間。
然後就是babel相關的npm包,其中包括:
babel-core
,babel的核心,沒啥好說的。babel-preset-es2015-loose
,babel的preset(相當於是一整套plugin)。babel是有許多preset的,看自己需要來選用,比如說我只管ES6(ES2016)語法的就可以用babel-preset-es2015
babel-preset-es2015-loose
。這倆preset其實用法一樣,差別就在於:許多Babel的外掛有兩種模式:
儘可能符合ECMAScript6語義的normal模式和提供更簡單ES5程式碼的loose模式。
優點:生成的程式碼可能更快,對老的引擎有更好的相容性,程式碼通常更簡潔,更加的“ES5化”。
缺點:你是在冒險——隨後從轉譯的ES6到原生的ES6時你會遇到問題。
我自己的考慮是,肯定要更好的相容性和更好的效能啦這還用想的嗎?(敲黑板)
babel-plugin-transform-runtime
和babel-runtime
,這屬於優化項,不用也沒啥問題,下文會細說。
如何配置babel-loader
babel-loader的配置並不複雜,與其它loader並無二致:
{
test: /\.js$/,
exclude: /node_modules|vendor|bootstrap/,
loader: 'babel-loader?presets[]=es2015-loose&cacheDirectory&plugins[]=transform-runtime',
},
下面來詳細解釋此配置:
test: /\.js$/
表明我只用babel-loader來載入js檔案,如果你只是小部分js檔案應用了ES6,那麼也可以給這些檔案換個.es6
的字尾名並把此處改為test: /\.es6$/
。exclude: /node_modules|vendor|bootstrap/
,上文已經說到了,不需要用babel來載入的檔案還是剔除掉,否則會大量增加編譯的時間,一般我們只用babel編譯我們自己寫的應用程式碼。loader: 'babel-loader?presets[]=es2015-loose&cacheDirectory&plugins[]=transform-runtime'
,這一行是指定使用babel-loader並傳入所需引數,這些引數其實也是可以通過babel配置檔案.babelrc,不過我還是推薦在這裡以引數的方式傳入。下面來介紹這些引數:
preset引數:babel-preset-es2015-loose
上文已經解釋過preset是什麼以及為啥要使用babel-preset-es2015-loose
了,這裡不再累述。
cacheDirectory引數
cacheDirectory引數預設為false,若你設定為一個檔案目錄路徑(表示把cache存到哪),或是保留為空(表示作業系統預設的快取目錄),則相當於開啟cache。這裡的cache指的是babel在編譯過程中某些可以快取的步驟,具體是什麼我也不太清楚,反正是隻要開啟了cache就可以加快webpack整體編譯速度。我測試了一下,未開啟cache的時候我的腳手架專案(Array-Huang/webpack-seed)需要15秒半來編譯;而開啟cache後的第一次編譯時間並沒有減少,第二次編譯則變為14秒了,足足減少了1秒半了棒棒噠。
plugins引數
雖說一個preset已經包括N個plugin了,但總有一些漏網之魚是要專門載入的。這裡我只用到了transform-runtime
,這個plugin的效果是:不用這plugin的話,babel會為每一個轉換後的檔案(在webpack這就是每一個chunk了)都新增一些輔助的方法(僅在需要的情況下);而如果用了這個plugin,babel會把這些輔助的方法都集中到一個檔案裡統一載入統一管理,算是一個減少冗餘,增強效能的優化項吧,用不用也看自己需要了;如果不用的話,前面也不需要安裝babel-plugin-transform-runtime
和babel-runtime
了。
總有刁民想害朕!ESLint為你阻擊垃圾程式碼
前言
刁民,還不退下?啊……來人啊快救駕!
你所在的團隊裡有沒有“老鼠屎”?就是專門寫各種看起來溜得飛起但實際上晦澀難懂的程式碼?又或是縮排換行亂成一團?
你寫程式碼是不是特粗心?經常落下些語法錯誤,debug起來想死?
如果你有以上問題,ESLint幫到你![手動滑稽]
ESLint的用途是?
從上面兩個應用場景,你大概已經猜到ESLint是用來幹什麼的了:
- 審查程式碼是否符合編碼規範和統一的程式碼風格;
- 審查程式碼是否存在語法錯誤;
語法錯誤好說,編碼規範和程式碼風格如何審查呢?ESLint定義好了一大堆規則作為可配置項;同時,一些大公司會開源出來他們使用的配置(比如說airbnb
),你可以在某套現成配置的基礎上進行修改,修改成適合你們團隊使用的編碼規範和程式碼風格。
本文主要講什麼?
本文著重介紹如何在webpack裡整合進ESLint,而並不介紹ESLint本身,因此,對於沒有使用過ESLint的小夥伴,請先去自己入門一下啦。
webpack如何整合ESLint?
這次我們需要使用到eslint-loader
,先放出配置的程式碼:
/* 這是webpack配置檔案的內容,省略無關部分 */
{
module: {
preLoaders: [{
test: /\.js$/, // 只針對js檔案
loader: 'eslint', // 指定啟用eslint-loader
include: dirVars.srcRootDir, // 指定審查範圍僅為自己團隊寫的業務程式碼
exclude: [/bootstrap/], // 剔除掉不需要利用eslint審查的檔案
}],
},
eslint: {
configFile: path.resolve(dirVars.staticRootDir, './.eslintrc'), // 指定eslint的配置檔案在哪裡
failOnWarning: true, // eslint報warning了就終止webpack編譯
failOnError: true, // eslint報error了就終止webpack編譯
cache: true, // 開啟eslint的cache,cache存在node_modules/.cache目錄裡
}
}
接下來解釋一下這份eslint-loader的配置。
為嘛把eslint-loader放在preLoaders
而不是loaders
裡?
理論上來說放loaders裡也無傷大雅,但放preLoaders裡有以下好處:
- 放在preLoader是先於loader的,因此當ESLint審查到問題報了warning/error的時候就會停掉,可以稍微省那麼一點點時間吧大概[手動滑稽]。
- 如果你使用了babel,或類似的loader,那麼,通過webpack編譯前後的程式碼相差就很大了,這會造成兩個問題(以babel為例):
- babel把你的程式碼轉成什麼樣你自己是無法控制的,這往往導致無法通過ESLint的審查。
- 我們實際上並不關心編譯後生成的程式碼,我們只需要管好我們自己手寫的程式碼即可,反正誰也不會沒事去讀讀編譯後的程式碼吧?
如何傳參給eslint-loader?
從eslint-loader官方文件可以看出,eslint-loader的配置還是比較多也比較複雜的,因此採用了獨立的一個配置項eslint
(跟module
同級哈)。
總結
只要你能在自己團隊裡成功推行ESLint,那麼最起碼,你可以放心不用再看到那些奇奇怪怪的程式碼了,因為,它們都編譯不通過吶哈哈哈哈哈……
後話
通過webpack整合ESLint,我們可以保證編譯生成的程式碼都是沒有語法錯誤且符合編碼規範的;但在開發過程中,等到編譯的時候才察覺到問題可能也是太慢了點兒。
因此我建議可以把ESLint整合進編輯器或IDE裡,像我本人在用Sublime Text 3
的,就可以使用一個名為SublimeLinter
的外掛,一寫了有問題的程式碼,就馬上會標識出來,如下圖所示: