2022 年,Babel vs TypeScript,誰更適合代碼編譯
在現(xiàn)代 Web 應(yīng)用中,為了讓代碼能在生產(chǎn)環(huán)境高性能的運營,源代碼往往需要被編譯打包,進(jìn)行死碼刪除,代碼轉(zhuǎn)換等處理。
Babel 和 Typescript 是目前最常用的兩個編譯器,本文主要討論兩者的區(qū)別,幫助你為項目選擇最佳工具。
介紹
Babel
Babel 是一個 JS 編譯器,能將現(xiàn)代 ES6+ 語法和特性轉(zhuǎn)換為向后兼容語法,以便能夠運行在當(dāng)前和舊版本的瀏覽器或其他環(huán)境中。擁有語法轉(zhuǎn)換,Polyfill,源碼轉(zhuǎn)換等能力,
TypeScript
TS 是目前最常用的編程語言之一,是加了類型系統(tǒng)的 JS,能夠幫助在開發(fā)時規(guī)避一些錯誤。
TS 有自己的編譯器,可將 ??.ts?
? 文件轉(zhuǎn)換為 ??.js?
? 文件,然后運行在瀏覽器、Node.js 等任何能運行 JS 的環(huán)境中。
兩者對比?
雖然同為編譯器,但也有一些區(qū)別。
Babel 無法做到類型檢查
TS 在編譯時可以對代碼進(jìn)行類型檢查,而 Babel 不支持類型檢查。
可以使用 ?
?tsc -- noEmit?
? 單獨進(jìn)行 TS 類型檢查
TS 無法自動 polyfill
Babel 和 TS 兩者都只是編譯器,真正完成 API polyfill 的是 ??core-js?
?。
?
?core-js?
? 是一套模塊化的 JS 標(biāo)準(zhǔn)庫,提供了 ??polyfill?
? 的核心實現(xiàn)。
Babel 的 ??@babel/polyfill?
? 模塊包含了 ??core-js?
? 和 ??regenerator-runtime?
? 來模擬完整的 ES2015+ 環(huán)境。因此可以說 Babel 自帶了 polyfill。
?
?regenerator-runtime?
? 是 ??generator?
? 以及 ??async/await?
? 的運行時依賴。
而 TS 只能通過 ??tsconfig?
? 的 ??target?
?
控制編譯為對應(yīng) ECMAScript 版本的語法。比如 const/let 變 var,箭頭函數(shù)變 function,async+await 變
Promise.then 這些,不會引入內(nèi)置對象的擴(kuò)展,比如你要運行的瀏覽器不支持 Promise,編譯后也不會帶一個完整的 Promise
polyfill,想 polyfill 還是得配合 ??core-js?
?。
Babel 擴(kuò)展性更強(qiáng)
Babel 是自定義代碼轉(zhuǎn)換的不二之選,而且社區(qū)生態(tài)豐富,有各種各樣的插件可以優(yōu)化你的代碼。
而 TS 只支持自己的 ??Transformer API?
?,生態(tài)遠(yuǎn)遠(yuǎn)比不上 Babel 插件,知道的人也比較少,能力也更少。
裝飾器(Decorator)差異
隨著 TS 和 ES6 里引入了類,裝飾器提案 proposal-decorators[1] 誕生了,是我們最熟悉的老朋友。但是此裝飾器非彼裝飾器,歷時多年來該提案已經(jīng)走到了第三版,仍然卡在 stage-2。
首先我們需要知道,JS 與 TS 中的裝飾器不是一回事,JS 中的裝飾器目前依然停留在 stage-2 階段,并且目前版本的草案與 TS 中的實現(xiàn)差異相當(dāng)之大(TS 是基于第一版,JS 目前已經(jīng)第三版了),所以二者最終的裝飾器實現(xiàn)必然有非常大的差異。
其次,裝飾器不是
TS 所提供的特性(如類型、接口),而是 TS 實現(xiàn)的 ECMAScript 提案(就像類的私有成員一樣)。TS 實際上只會對 stage-3
以上的語言特性提供支持,但因為一些原因,當(dāng) TS 引入裝飾器時,JS 中的裝飾器依然處于 stage-1 階段。TS 的裝飾器其實是 JS 裝飾器提案的第一版。
Babel 編譯裝飾器需要使用 ??@babel/plugin-proposal-decorators?
? 插件,通過 ??version?
? 字段分別支持三版提案:
- "2021-12"
- "2018-09"(默認(rèn))
- "legacy"
Babel 默認(rèn)按第二版進(jìn)行編譯,如果要與 TS 編譯行為一致(也就是第一版),需要傳入 ??"version": "legacy"?
?。
Babel 支持更多語言特性
從上面裝飾器的例子還可以看出,TS 只會對 stage-3 以上的語言特性提供支持,不支持還在草案階段的特性。
而 Babel 的 ??preset-env?
? 支持所有標(biāo)準(zhǔn)特性,還能通過各種 ??@babel/plugin-proposal-<語言特性>?
? 插件來支持更多還未進(jìn)入標(biāo)準(zhǔn)的特性。
兩者編譯速度相當(dāng)
在性能上,兩者差別不大。這里大家可能會有疑問:“Babel 少了類型檢查的步驟,編譯速度應(yīng)該會比 TS 快才對啊”。
根據(jù) swc-node[2] 文檔的 benchmark 我們可以看到,在關(guān)閉類型檢查的情況下,TS 的編譯速度是比 Babel 快的。
esbuild x 510 ops/sec ±1.28% (88 runs sampled)
@swc-node/core x 438 ops/sec ±1.00% (88 runs sampled)
typescript x 28.83 ops/sec ±10.20% (52 runs sampled)
babel x 24.21 ops/sec ±10.66% (46 runs sampled)
Transform rxjs/AjaxObservable.ts benchmark bench suite: Fastest is esbuild
而且還可以借助第三方插件 fork-ts-checker-webpack-plugin[3] 來提速類型檢查過程(放到單獨的進(jìn)程中),所以兩者的整體性能其實相差不大。
Babel 產(chǎn)物體積更小
因為 TS 無法自動 polyfill,借助了 ??core-js?
? 也無法做到按需 polyfill。
而配置 Babel 的 ??@babel/preset-env?
? 插件:
- ?
?useBuiltIns: "usage"?
? - 添加目標(biāo)瀏覽器?
?targets: <需要兼容的瀏覽器>?
?
可以根據(jù)編譯目標(biāo)和項目的 API 使用情況來精準(zhǔn)添加 polyfill,這會大大降低包的體積。
使用 ?
?useBuiltIns: "usage"?
? 會在全局添加 polyfill,這會污染全局環(huán)境。可以使用 ??@babel/plugin-transform-runtime?
? 插件為庫的代碼提供一個沙盒環(huán)境,把 polyfill 變成模塊化的引入,代碼重用的同時避免全局污染。
總結(jié)?
綜上,兩者都有各自的編譯處理方式,整體看下來,Babel 唯一的缺點就是沒有類型檢查,但可以使用 ??tsc --noEmit?
? 單獨檢查類型。
因此,如果項目中:
- 已有 Babel 和 TypeScript,最好使用 Babel 編譯代碼,使用 TS 進(jìn)行類型檢查和生成 ??
?.d.ts?
? 文件。
TS 文檔[4]中也更推薦這種方式,但如果構(gòu)建輸出文件和源碼差別不大的話,可直接使用 TS 編譯。
- 只有 TypeScript,可以保持現(xiàn)狀,將來如果需要 Babel 提供的能力,可以將 TS 編譯輸出的 JS 再使用 Babel 編譯,或者直接使用 Babel 編譯 TS 文件。
- 只有 Babel,推薦使用 TypeScript對項目進(jìn)行漸進(jìn)式改造,保證項目前端質(zhì)量。
參考?
- https://blog.bitsrc.io/babel-vs-typescript-in-2022-b8e859a9fefc
- https://ts.xcatliu.com/
- https://jishuin.proginn.com/p/763bfbd3ba87
- https://jishuin.proginn.com/p/763bfbd5eecf
- https://juejin.cn/post/6968636129239105549
- https://blog.logrocket.com/babel-vs-typescript/
- https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html#babel-vs-tsc-for-typescript
- https://www.zhihu.com/question/322722786?
參考資料
[1]proposal-decorators: https://github.com/tc39/proposal-decorators
[2]swc-node: https://github.com/Brooooooklyn/swc-node#benchmark
[3]fork-ts-checker-webpack-plugin: https://github.com/TypeStrong/fork-ts-checker-webpack-plugin
[4]TS 文檔: https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html