webpack 背後靈魂 (4) - 相容工具

集點送紅利 / Hiro
UNNO Technology
Published in
8 min readJul 2, 2020

上回文章:背後靈魂 webpack (3) — html-webpack-plugin & devServer

這次要來看看相容性,大家知道瀏覽器有很多種,但往往不是使用者都會使用最新的瀏覽器,也因此當我們在寫 code 時可能就要考慮到這語法到底 IE 有沒有支持。對啦就是在說 IE!

IE 娘有夠香 - Merryweather

這次要談的是 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-plugincss-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)

這時候再跑一次,可以看到原本的 constarrow function 都被編譯了。

Before & After

在沒有指定瀏覽器的狀況下,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%:這點很重要,如果光是設定以上兩個的話,一些受歡迎的舊瀏覽器就會被擋下,可以看下面兩圖比較。
可以看到 Safari 5.1 在左邊就沒出現

--

--