如果你喜歡我的文章,希望點贊👍 收藏 📁 評論 💬 三連支持一下,謝謝你,這對我真的很重要!
對於大部分開發者來説,版本兼容是一件存在感很低的事情,因為它在絕大部分情況下都是一行配置,在一些前端工具鏈(例如 Babel、CoreJS,Autoprefixer 等工具)的幫助下適配到目標瀏覽器,只會在一些大的 break change 事件(例如 Vue3 必須在支持 Proxy 的現代瀏覽器下才能運行)下才會關注這件不起眼的事情。
但當你稍微研究一下的時候,才會發現這塊兒內容知識非常雜,因為版本兼容的相關知識沒有那麼多內在邏輯性,很多細碎的知識點散落在在各個商業公司的博弈和版本變更中。前段時間因工作需要對部分語言/瀏覽器特性重點關注了一下,以此文做一下記錄。
本文主要記錄了移動端的版本適配問題,未對桌面端做更多的研究,後面有可能補充相關內容。
1.iOS & Safari
iOS 和 Android 雖然都是一年更新一個大版本,但受益於生態的封閉性,iOS 的更新率極高,基本上最近的兩個版本就能覆蓋 95% 以上的人羣。
例如 Apple 官方統計,截止到 2022-05-31,Apple 四年內推出的新機型中,iOS 15 已經有 89% 的裝機率,iOS 14 也有 10% 的裝機率;而在所有歷史機型裏,iOS 15 和 iOS 14 加起來也有 96% 的裝機率,隔壁 Android 都羨慕哭了:
為什麼如此關注 iOS 的版本號?因為 iOS 版本基本上和 Safari 版本一一對應的,例如 iOS 15.6 上安裝着 Safari 15.6,iOS 14.5 上安裝着 Safari 14.1,具體的映射關係可見 MDN 的映射表,或者可以看 core-js: SafariToIOS,所以我們基本上只要比對 iOS 版本號即可。
另外一個問題是,有一定 C 端開發經驗的開發者可能還會關注 iOS 上運行的是 UIWebView 還是 WKWebView,在 2022 年這個時間點其實已經不需要關注了,因為 Apple Store 已經發過公告,2020 12 月之後已經禁止含 UIWebView 的 APP 上架了,所以 iOS 平台只有 WKWebView 這一個 WebView 了,而且它兼容性也不錯,最低支持到 iOS 8。
2.Android & Chrome
説完 iOS 我們再談談 Android。因為兩個操作系統的發展策略不同,再加上國內各大廠商的魔改,Android 從一開始就深陷碎片化的深淵,有 Android 開發經歷的同學一定都深有感觸。
Android 系統本身碎片化,Android 系統自帶的瀏覽器更碎片化。在 Android 早期,Android 版本和 Chrome 瀏覽器版本是有綁定關係的,那這個早期是有多早?那就是 Android 4,2014 年發佈,綁定了 Chrome 早期幾個版本,因為數據不多,我這裏就直接列出來:
// https://github.com/zloirock/core-js/blob/master/packages/core-js-compat/src/mapping.mjs
ChromeToAndroid: [
[9, '3.0'],
[12, '4.0'],
[30, '4.4'],
[33, '4.4.3'],
]
事情的轉機出現在 Android 5,這個版本里 WebView 被移植為一個獨立的 APK,可以獨立更新,不再和 Android 系統深度綁定。
Google 的想法初衷是好的,藉助於 Google 商店,解耦更利於瀏覽器的版本迭代。但是在國內多廠商魔改和一些網絡問題上,極有可能發生這樣的事情:對於一台 Android 5 手機,理論上用户可以安裝 Chrome 36 - Chrome 95 任意一個版本!
所以和 iOS 對比起來,Android 因為他的開放性帶來嚴重的碎片化問題:Android 版本多樣,Chrome 版本多樣,還有各種魔改內核,對於開發者來説適配起來真的苦不堪言。
3.Web Browser
瞭解完操作系統的版本歷史,我們再看看瀏覽器上最關鍵的 JavaScript 語法兼容度。
JavaScript
最近十年內,JS 這門語言的的最大變革就是 ES6(ES2015)的發佈了,帶來了非常多的新特性。下面我搞了一個表格,列出幾個大家常用的 JS 語法是從哪個版本開始支持的:
| 語法/API | iOS | Chrome |
|---|---|---|
Class |
9 | 49 |
=> |
10 | 45 |
const |
11 | 49 |
let |
11 | 49 |
Proxy |
10 | 49 |
generators |
10 | 39 |
Promise |
8 | 33 |
async await |
11 | 55 |
import export |
10.3 | 61 |
| ... | ... | ... |
我們可以看到,這些語法的最低支持版本集中在 iOS 10、iOS 11,Chrome 49,Chrome 61 這幾個版本上,我們把它們的版本發佈時間列出來:
| 事件 | 發佈時間 |
|---|---|
ES5 標準發佈時間 |
2009.12 |
ES6 標準發佈時間 |
2015.06 |
iOS 10 發佈時間 |
2016.06 |
iOS 11 發佈時間 |
2017.06 |
Chrome 49 發佈時間 |
2016.03 |
Chrome 61 發佈時間 |
2017.09 |
時間列出來後結論基本上是呼之欲出了:ES6 標準發佈後的未來一年時間內,各大瀏覽器語法就支持的差不多了,兩年後基本上就全部支持了,這個時間點就是 2017 年,對應着 iOS 11 和 Chrome 61。
legacy vs modern
看完 ES6 的支持情況,我們再來了解兩個概念,「經典瀏覽器」和「現代瀏覽器」。
這兩個詞在英文裏對應着「legacy browser」和「modern browser」。如果大家比較關注一些相對前沿的前端項目,比如説 Vue3,Solidjs,Vite,它們的官網裏其實經常提到這兩個詞。
那麼問題來了,既然有兩個稱呼,那在工程裏必然存在一個分界線去區分 legacy 和 modern,這個分界線就是 iOS10.3 和 Chrome 61,既瀏覽器支持 ES Modules 的版本(支持 <script type="module"> & import & export)。
這樣一看是不是就和上面的內容對上了?Babel 官網也做了相關的解釋,core-js 也專門做了區分,更詳細的介紹可以看 MDN 的文章:JavaScript modules,我就不做多餘介紹了。
modern feature
經過上面的探索,我們再回過來看看一些比較 modern 的 browser feature 的支持程度:
| browser fature | iOS | Chrome |
|---|---|---|
| Web Worker | 5 | 4 |
| SubtleCrypto | 7 | 37 |
| Service Worker | 11.3 | 45 |
| WebAssembly | 11 | 57 |
| CSS Grid Layout | 10.3 | 58 |
| WebGPU | not support | not support |
| ... | ... | ... |
看看各個 API 的兼容度,再結合上文的內容,就可以發現很多「兼容性不好」人云亦云的説法不攻自破,其實大部分情況下不是兼容度不好從而不用,是項目還沒有複雜到那個程度需要用這些高級功能。
4.Open Source Project
日常開發中肯定不能寫一行代碼查一下兼容度,這些都是由社區工具做抹平的。
兼容度數據源頭可以追述到 MDN 的 browser-compat-data,記錄了各種 API 的兼容,MDN 網站的兼容度直接是從這個 repo 裏讀的。我們常用的 caniuse 網站,一部分數據也是依賴於它的。
接下來是工程上依賴最多的 browserslist,babel、eslint、autoprefixer、postcss,webpack 等構建工具都依賴於它,browserslist 的數據又依賴於 caniuse-lite,其實也是依賴於 caniuse,lite 只保留了核心數據,對一些説明文案做了裁剪處理。
綜合以上分析,我們可以看出,在項目工程裏依賴的 browserslist,數據準確性還是可以得到保證的,所以兼容性還是無需擔心的。
5.Adaptation Suggestions
説了這麼多,那麼有什麼配置建議呢?我個人認為主要有 3 點建議提供參考。
第一個是參考國民級 APP 的最低支持度配置。
在國內,在日活上能稱為國民級 APP 的就是微信抖音了,這兩個 APP 因為日活巨大,基本上已經覆蓋到全部中國人,所以他們的配置一定有所考量,可以反應出國內的整體手機版本水平。
從 App Store/Android 應用商店/瀏覽器 UA 上看,我們可以得處以下結論(截止到 2022-8-8):
- 微信:最低支持到
iOS 12、Android 5、內置瀏覽器版本為Chrome 86 - 抖音:最低支持到
iOS 10、Android 5、內置瀏覽器版本為Chrome 75
當然你也可以參考其他 APP,由於精力有限我就不做過多展開了。
根據項目的迭代速度來看,iOS 基本上可以做到一年一升級,比如説今年 iOS 16 出來後,明年最低適配版本基本上可以升到 iOS 11 了,Android 因為長尾效應和版本不綁定的問題,應該還會支持到 Android 5。
第二個建議是直接看當前業務的版本數據。
不同的公司不同的項目都有不同的用户場景,比如説面向三四線 C 端用户的場景,一般低端機就會多一些;面向門店的場景,説不定還得適配 IE 瀏覽器;面向企業內的開發者項目,直接適配到最新幾個瀏覽器即可。
場景如此之多就要依賴於用户版本數據統計了。一般中大廠都有比較完善的數據監控中台,直接拉一份數據就能獲取大致情況,基建不完善的小公司也可以單獨開個接口記錄數據,收集一個月做個去重統計也能得到相關數據。拿到數據後再結合業務場景做些取捨,基本上就可以拿到最低適配了。
第三個建議結合前端框架和 Chrome 版本做兼容。
結合前端框架其實很好理解,比如説你用了 Vue3,底層依賴於 Proxy,那麼最低依賴已經鎖死到 iOS 10 和 Chrome 49 了,那你的最低配置只能比以上版本高,假如你無腦設置為 iOS 9 或 Android 4,除了在最低版本上跑不起來,還要平白無故的多了許多語法轉換和 polyfill,在 構建速度/運行時性能/產物體積 上都會產生不必要的劣化。
結合 Chrome 版本做兼容其實就是本文第二大節的內容。因為 Android 5 之後不再和 Chrome 做深度綁定,版本兼容設置 Android 版本其實是無意義的行為,應該根據統計結果直接設置 Chrome 版本,做更細粒度的配置。
Refs: Version History
以上的版本歷史和發佈時間主要參考官方更新日誌/文檔 和 維基百科,相關鏈接如下所示:
- iOS 版本歷史:https://en.wikipedia.org/wiki/IOS_version_history
- Android 版本歷史:https://en.wikipedia.org/wiki/Android_version_history
- Chrome 版本歷史:https://en.wikipedia.org/wiki/Google_Chrome_version_history
- WKWebView API 兼容度:https://developer.apple.com/documentation/webkit/wkwebview
- Android Verison 和 APILevel 的對應關係:https://developer.android.com/guide/topics/manifest/uses-sdk-element#ApiLevels
如果你喜歡我的文章,希望點贊👍 收藏 📁 評論 💬 三連支持一下,謝謝你,這對我真的很重要!
歡迎大家關注我的微信公眾號:滷蛋實驗室,目前專注前端技術,對圖形學也有一些微小研究。
原文鏈接 👉 🔬 對前端版本兼容問題的研究:更新更及時,閲讀體驗更佳。