您好,登錄后才能下訂單哦!
這篇文章主要介紹“為什么要用Babel編譯Typescript”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“為什么要用Babel編譯Typescript”文章能幫助大家解決問題。
typescript 給 javascript 擴展了類型的語法和語義,讓 js 代碼達到了靜態類型語言級別的類型安全,之前只能在運行時發現的類型不安全的問題,現在能在編譯期間發現了,所以大項目越來越多的選擇用 typescript 來寫。除此之外,typescript 還能夠配合 ide 做更好的智能提示,這也是用 typescript 的一個理由。
類型安全:如果一個類型的變量賦值給它不兼容類型的值,這就是類型不安全,如果一個類型的對象,調用了它沒有的方法,這也是類型不安全。反之,就是類型安全。類型安全就是變量的賦值、對象的函數調用都是在類型支持的范圍內。
最開始 typescript 代碼只有自帶的 tyepscript compiler(tsc)能編譯,編譯不同版本的 typescript 代碼需要用不同版本的 tsc,通過配置 tsconfig.json 來指定如何編譯。
但是 tsc 編譯 ts 代碼為 js 是有問題的:
tsc 不支持很多還在草案階段的語法,這些語法都是通過 babel 插件來支持的,所以很多項目的工具鏈是用 tsc 編譯一遍 ts 代碼,之后再由 babel 編譯一遍。這樣編譯鏈路長,而且生成的代碼也不夠精簡。
所以,typescript 找 babel 團隊合作,在 babel7 中支持了 typescript 的編譯,可以通過插件來指定 ts 語法的編譯。比如 api 中是這樣用:
const parser = require('@babel/parser'); parser.parse(sourceCode, { plugins: ['typescript'] });
這個插件是 typescript 團隊與 babel 團隊合作了一年的成果。
但是,這個插件真的能支持所有 typescript 代碼么?答案是否定的。
我們來看一下 babel 不支持哪些 ts 語法,為什么不支持。
babel 的編譯流程是這樣的:
parser: 把源碼 parse 成 ast
traverse:遍歷 ast,生成作用域信息和 path,調用各種插件來對 ast 進行轉換
generator:把轉換以后的 ast 打印成目標代碼,并生成 sourcemap
而 typescript compiler 的編譯流程是這樣的:
scanner + parser:分詞和組裝 ast,從源碼到 ast 的過程
binder + checker:生成作用域信息,進行類型推導和檢查
transform:對經過類型檢查之后的 ast 進行轉換
emitter:打印 ast 成目標代碼,生成 sourcemap 和類型聲明文件(根據配置)
其實 babel 的編譯階段和 tsc 的編譯階段是類似的,只是 tsc 多了一個 checker,其余的部分沒什么區別。
babel 的 parser 對應 tsc 的 scanner + parser
babel 的 traverse 階段 對應 tsc 的 binder + transform
babel 的 generator 對應 tsc 的 emitter
那么能不能基于 babel 的插件在 traverse 的時候實現 checker 呢?
答案是不可以。
因為 tsc 的類型檢查是需要拿到整個工程的類型信息,需要做類型的引入、多個文件的 namespace、enum、interface 等的合并,而 babel 是單個文件編譯的,不會解析其他文件的信息。所以做不到和 tsc 一樣的類型檢查。
一個是在編譯過程中解析多個文件,一個是編譯過程只針對單個文件,流程上的不同,導致 babel 無法做 tsc 的類型檢查。
那么 babel 是怎么編譯 typescript 的呢?
其實 babel 只是能夠 parse ts 代碼成 ast,不會做類型檢查,會直接把類型信息去掉,然后打印成目標代碼。
這導致了有一些 ts 語法是 babel 所不支持的:
const enum 不支持。const enum 是在編譯期間把 enum 的引用替換成具體的值,需要解析類型信息,而 babel 并不會解析,所以不支持。可以用相應的插件把 const enum 轉成 enum。
namespace 部分支持。不支持 namespace 的跨文件合并,不支持導出非 const 的值。這也是因為 babel 不會解析類型信息且是單文件編譯。
上面兩種兩個是因為編譯方式的不同導致的不支持。
export = import = 這種 ts 特有語法不支持,可以通過插件轉為 esm
如果開啟了 jsx 編譯,那么
這四種就是 babel 不支持的 ts 語法,其實影響并不大,這幾個特性不用就好了。
結論:babel 不能編譯所有 typescript 代碼,但是除了 namespace 的兩個特性外,其余的都可以做編譯。
babel 是可以編譯 typescript 代碼,那么為什么要用 babel 編譯呢?
babel 編譯 typescript 代碼有 3 個主要的優點:
產物體積更小
tsc
tsc 如何配置編譯目標呢?
在 compilerOptions 里面配置 target,target 設置目標語言版本
{ compilerOptions: { target: "es5" // es3、es2015 } }
typescript 如何引入 polyfill 呢?
在入口文件里面引入 core-js.
import 'core-js';
babel7
babel7 是如何配置編譯目標呢?
在 preset-env 里面指定 targets,直接指定目標運行環境(瀏覽器、node)版本,或者指定 query 字符串,由 browserslist 查出具體的版本。
{ presets: [ [ "@babel/preset-env", { targets: { chrome: 45 } } ] ] }
{ presets: [ [ "@babel/preset-env", { targets: "last 1 version,> 1%,not dead" } ] ] }
babel7 如何引入 polyfill 呢?
也是在 @babel/preset-env 里面配置,除了指定 targets 之外,還要指定 polyfill 用哪個(corejs2 還是 corejs3),如何引入(entry 在入口引入 ,usage 每個模塊單獨引入用到的)。
{ presets: [ [ "@babel/preset-env", { targets: "last 1 version,> 1%,not dead", corejs: 3, useBuiltIns: 'usage' } ] ] }
這樣可以根據 @babel/compat-data 的數據來針對的做語法轉換和 api 的 polyfill:
先根據 targets 查出支持的目標環境的版本,再根據目標環境的版本來從所有特性中過濾支持的,剩下的就是不支持的特性。只對這些特性做轉換和 polyfill 即可。
而且 babel 還可以通過 @babel/plugin-transform-runtime 來把全局的 corejs 的 import 轉成模塊化引入的方式。
顯然,用 babel 編譯 typescript 從產物上看有兩個優點:
能夠做更精準的按需編譯和 polyfill,產物體積更小
能夠通過插件來把 polyfill 變成模塊化的引入,不污染全局環境
從產物來看,babel 勝。
typescript 默認支持很多 es 的特性,但是不支持還在草案階段的特性,babel 的 preset-env 支持所有標準特性,還可以通過 proposal 來支持更多還未進入標準的特性。
{ plugins: ['@babel/proposal-xxx'], presets: ['@babel/presets-env', {...}] }
從支持的語言特性來看,babel 勝。
tsc 會在編譯過程中進行類型檢查,類型檢查需要綜合多個文件的類型信息,要對 AST 做類型推導,比較耗時,而 babel 不做類型檢查,所以編譯速度會快很多。
從編譯速度來看, babel 勝。
總之,從編譯產物大小(主要)、支持的語言特性、編譯速度來看,babel 完勝。
但是,babel 不做類型檢查,那怎么類型檢查呢?
babel 可以編譯生成更小的產物,有更快的編譯速度和更多的特性支持,所以我們選擇用 babel 編譯 typescript 代碼。但是類型檢查也是需要的,可以在 npm scripts 中配一個命令:
{ "scripts": { "typeCheck": "tsc --noEmit" } }
這樣在需要進行類型檢查的時候單獨執行一下 npm run typeCheck 就行了,但最好在 git commit 的 hook 里(通過 husky 配置)再執行一次強制的類型檢查。
關于“為什么要用Babel編譯Typescript”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。