webpack 背後靈魂 (4) - 相容工具
上回文章:背後靈魂 webpack (3) — html-webpack-plugin & devServer
這次要來看看相容性,大家知道瀏覽器有很多種,但往往不是使用者都會使用最新的瀏覽器,也因此當我們在寫 code 時可能就要考慮到這語法到底 IE 有沒有支持。對啦就是在說 IE!
這次要談的是 webpack 常用的相容工具,雖然不是專屬於 webpack 的一塊,但在開發上這些工具可以說是不可缺少。
回顧一下目前專案內的檔案:
webpack-demo
|- /src
|- index.js
|- utils.js
|- /css
|- index.css
|- /assets
|- demo.png
|- index.html
目錄
- CSS 相容
- Autoprefixer - JavaScript 相容
- BABEL - 瀏覽器版本設定
- Browserslist
CSS 相容
先來談談 PostCSS,他是以 JavaScript 打造用來編譯 CSS 的方便工具。點開官網可以看到大致上分為幾個方向:
- Autoprefixer:幫 CSS 補上前綴,不用再擔心一堆瀏覽器的前綴。
- PostCSS Preset Env:編譯最新的 CSS 給舊瀏覽器相容。
- CSS Modules:主要是解決 CSS 全域污染問題,像是 Vue 的
Scoped
。 - stylelint:CSS 的 ESLint。
- LostGrid:把格線系統
grid
編譯成calc()
給舊瀏覽器支援。
PostCSS 的分類算是後處理器(Postprocessors),跟預處理器(Preprocessors)的 Sass、Less、Stylus 差別在,前者是寫 CSS 再來做編譯,後者則是寫很像 CSS 的語法編譯成 CSS,兩者沒有衝突可以自由搭配。
而這次要看的是 Autoprefixer。
Autoprefixer
這其實是因為當初 CSS 3 草案出來時,各大瀏覽器先自幹了一部分的標準,等到正式的標準出來時才慢慢跟上,因此為了讓自己的與正式做區分,會再前面加上前綴詞,像是:
-webkit-transition: all 4s ease;
-moz-transition: all 4s ease;
-ms-transition: all 4s ease;
-o-transition: all 4s ease;
transition: all 4s ease;
各個前綴詞為:
-webkit-
:Google、Safari、新版 Opera …等等-moz-
:Firefox-o-
:舊版 Opera-ms-
:IE & Edge
當然現在工具這麼好用,我們不需要再去記哪些 CSS 需要加前綴詞。在安裝上我們需要裝上 postcss-loader
與他的 plugin autoprefixer
。
$ npm install autoprefixer postcss-loader --save-dev
配置:
這邊不要忘了 loader 的順序是由後面往前,雖然寫在
css-loader
的後面,但編譯順序是在css-loader
之前的!mini-css-extract-plugin 與 css-loader 可以參考 第二篇
另外 options
的地方為專案要使用的 postcss plugins,如果使用很多的話看起來會很雜,因此可以在專案根目錄創一個檔案為 postcss.config.js
:
module.exports = {
plugins: [
require('autoprefixer')
]
}
配置好了之後,我們在專案的 index.css
內寫些較少被支援的語法:
input[type="checkbox"] {
appearance: none;
}
編譯後可以看到 CSS 自動加上了前綴(拍手):
JavaScript 相容
CSS 都需要相容了,怎麼能沒有 JavaScript 呢,光一個 ES6 就能搞死大家了啊啊 XD
BABEL
BABEL 在 JavaScript 上一直支持著我們寫新的語法,並且幫助我們編譯成相容舊瀏覽器的語法。
看官網的話,會發現他是可以單用就直接編譯出來,但我們今天要朝向和 webpack 一起做搭配使用,要進入 webpack,當然就必須安裝 babel-loader。
@babel/core
為核心,@babel/preset-env
可以讓我們直接寫 JS 最新語法都沒問題。
$ npm install -D babel-loader @babel/core @babel/preset-env
一樣需要在 webpack.config.js
裡配置:
同樣的,如果
options
配置太雜的話可以拉到根目錄創一支babel.config.js
。
在 JS 檔裡面隨便寫些 ES6 的語法:
const arr = [1,2,3,4,5]const arrDouble = arr.map(item => item * item)
這時候再跑一次,可以看到原本的 const
和 arrow function
都被編譯了。
在沒有指定瀏覽器的狀況下,BABEL 會把所有 ES6 以上的語法都編譯過。
瀏覽器版本設定
上面兩個只要貼上基本設定,就會自動編譯好。我們可以透過統計顧客的瀏覽器版本,來個別設定 target
指定要編譯的瀏覽器版本。但…工具越來越多,假如今天編譯版本要從 IE10 升級到 Edge 15 的話,不就要每個都設定一遍嗎?
也因為這樣,我們需要有個像是變數的功能,可以統整瀏覽器版本的工具。
Browserslist
在根目錄創一支設定檔為 .browserslistrc
,根據官網推薦最佳寫法為:
defaults
或是可以選擇寫在 package.json
裡:
"browserslist": [
"defaults"
]
default
又等於:
> 0.5%
last 2 versions
Firefox ESR
not dead
一般情況下默認設定 = 最佳設定,但不是每一個產品都適用。如果想更改配置的話,官方建議改為:
last 2 versions
not dead
> 0.2%
意思為:
last 2 versions
:編譯成瀏覽器的最新兩個版本,以目前的 Chrome 78 來說,就是編譯成 77~78 都相容。not dead
:一年內有官方消息或更新的瀏覽器。> 0.2%
:這點很重要,如果光是設定以上兩個的話,一些受歡迎的舊瀏覽器就會被擋下,可以看下面兩圖比較。
如果不確定自己寫的版本 webpack 是否讀得懂的話,可以使用 browserl.ist 這個網站測試,或是在終端機打上
npx browserslist
做除錯。
延伸閱讀
在設定 browserslist 瀏覽器版本後,可以透過一些插件來檢查目前的 JS 或 CSS 有哪些不支援,需要另外安裝 polyfill。