﻿# 如何讓 Angular CLI v8+ 建置專案時可以不要輸出 ES5 版本 (browserslist)

Angular CLI 從 v8 版本開始，就支援一個「差異化載入」(Differential Loading) 功能，此功能會自動判斷當今世上所有主流瀏覽器中，是否支援 ES5 或 ES2015 (ES6) 語法。如果這些瀏覽器還有不支援 ES2015 的版本尚在市場上流通的話，Angular CLI 在執行 `ng build --prod` 的時候，就會建置出分別為 ES5 與 ES2015 兩個版本，並透過 `nomodule` 屬性達成差異化載入。想當然爾，如果一次建置兩個版本，總體建置時間也會倍增。本篇文章我將解釋這部分技術細節，如果你只想建置出 ES2015 的版本，也請繼續看下去。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/f9965eb1ba2f6792c116-68238919-fc5dc000-0044-11ea-9ab7-9152a1a1f01b.png)

### 關於 browserslist 設定檔

在 Angular CLI v7 以前，在 `angular.json` 中有個設定參數為 `es5BrowserSupport`，這個設定可以告訴 Angular CLI 在建置專案時，其輸出的 JS 語法是否要支援 ES5 版本，但是這個設定到了 Angular CLI v8 就不再適用，建議未來也不要再用這條設定。

從 Angular CLI v8 開始，關於建置輸出的 JS 版本，統一由 `browserslist` 設定檔負責，該檔案的詳細說明可以參考 [Browserslist](https://github.com/browserslist/browserslist) 專案。

這個 `browserslist` 設定檔，主要用來定義**當前應用程式**應該支援的**瀏覽器種類**與**版本**，他有一套相當便利的**查詢語法**，可以幫助你用比較**通用**的方式定義瀏覽器。

### 解說 browserslist 設定檔預設內容

我們先來看看 Angular CLI v8 內建的 `browserslist` 設定檔內容：

```bash
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
```

這些設定大致上的意思是這樣的：

1.  `> 0.5%`: 依據瀏覽器全球統計數據，支援大於 `0.5%` 市佔率的瀏覽器。
2.  `last 2 versions`: 支援**每個瀏覽器**的**最新兩個版本**
3.  `Firefox ESR`: 支援 [Firefox ESR](https://support.mozilla.org/kb/firefox-esr-release-cycle) 版本
4.  `dead` 是指已經不被官方所支援的瀏覽器版本 (例如: IE10, IE Mobile 10, BlackBerry 10, ...)，或是距離上次更新已經超過 24 個月的版本。而 `not dead` 就是指這些**舊版瀏覽器**皆**不支援**。
5.  `not IE 9-11`: 代表**不支援** `IE 9-11` 版本！

> 請注意：越下方的設定，會覆寫越上面所寫的瀏覽器查詢規則。

其實 `browserslist` 設定檔內容還算淺顯易懂，但要知道確切支援了哪些瀏覽器，則可以透過以下命令進行查詢：

```bash
npx browserslist
```

Angular CLI v8 預設 `browserslist` 的執行結果為：

```
and_chr 75
and_ff 67
and_qq 1.2
and_uc 12.12
android 67
baidu 7.12
chrome 75
chrome 74
chrome 73
edge 18
edge 17
firefox 68
firefox 67
firefox 60
ie_mob 11
ios_saf 12.2-12.3
ios_saf 12.0-12.1
ios_saf 11.3-11.4
kaios 2.5
op_mini all
op_mob 46
opera 62
opera 60
safari 12.1
safari 12
samsung 9.2
samsung 8.2
```

你可以從上述清單中發現幾個亮點：

1.  完全不支援 IE，連 IE11 都沒有在裡面。
2.  他竟然支援 Opera Mini 所有版本，這個版本完全不支援 ES2015 語法。至於這個瀏覽器還支援的原因也很神奇，因為他的全球市佔率至今還有 1.3%，即便連台灣也還有 0.68% 的市佔率。瀏覽器市占比例可以參考 ["Can I use" usage table](https://caniuse.com/usage-table) 資料，台灣這邊的市佔率也可以參考 [Can I use - JavaScript modules via script tag](https://caniuse.com/#feat=es6-module) 上面的資訊！
3.  還有 `and_uc 12.12` (UC Browser for Android)、`baidu 7.12` (Baidu Browser) 與 `and_qq 1.2` (QQ Browser) 都是不支援 ES2015 的瀏覽器。說實在的，我並不清楚為何這些瀏覽器還會出現在支援清單上，可能是某地區的市佔率還挺高吧。

也因為要支援這些瀏覽器的關係，因此 Angular CLI v8 在對專案進行 `ng build --prod` 的時候，便會同時輸出 ES5 與 ES2015 版本。

### 調整 browserslist 讓 Angular CLI 輸出只有 ES2015 的版本

如果想要達成只建置輸出 ES2015 版本，你可以明確指定你想支援的瀏覽器版本，如下範例：

```bash
Chrome >= 61
Firefox >= 60
Safari >= 11
Opera >= 48
Edge >= 16
Samsung >= 8
Android >= 67
ChromeAndroid >= 74
FirefoxAndroid >= 66
```

> 你可以參考 [Can I use](https://caniuse.com/#feat=es6-module) 網站的資訊進行調整。當然，如果有真的有使用者使用了不支援 ES2015 的瀏覽器，其風險你就要自行承擔了。

### 我想要支援 IE9-11 怎麼辦

由於 IE11 並不支援大部分 ES2015 語法，如果想要調整瀏覽器支援度，請務必將 `browserslist` 設定檔中的 `not IE 9-11` 修改為 `IE 9-11` 即可！如下範例：

```bash
> 0.5%
last 2 versions
Firefox ESR
not dead
IE 9-11
```

此時執行 `npx browserslist` 的結果就會變成：

```bash
and_chr 75
and_ff 67
and_qq 1.2
and_uc 12.12
android 67
baidu 7.12
chrome 75
chrome 74
chrome 73
edge 18
edge 17
firefox 68
firefox 67
firefox 60
ie 11
ie 10
ie 9
ie_mob 11
ios_saf 12.2-12.3
ios_saf 12.0-12.1
ios_saf 11.3-11.4
kaios 2.5
op_mini all
op_mob 46
opera 62
opera 60
safari 12.1
safari 12
samsung 9.2
samsung 8.2
```

當然，除了調整 `browserslist` 設定檔外，若要支援 IE9+ 版本，還要適時的調整一下 `src\polyfills.ts` 設定檔才行喔！

### 相關連結

-   [Can I use...JavaScript modules via script tag](https://caniuse.com/#feat=es6-module)
-   [Choose ES target level · Issue #14639 · angular/angular-cli](https://github.com/angular/angular-cli/issues/14639#issuecomment-500458409)
-   [browserslist/browserslist](https://github.com/browserslist/browserslist): Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env
-   [Browserslist (@Browserslist) / Twitter](https://twitter.com/browserslist)
-   ["Differential Loading" - A New Feature of Angular CLI v8 - DEV Community](https://dev.to/lacolaco/differential-loading-a-new-feature-of-angular-cli-v8-4jl)
