第1篇
Babel學習系列1-Babel歷史
第2篇
Babel學習系列2-Babel設計組成
第3篇
Babel學習系列3-babel-preset,babel-plugin
這篇主要講
polyfill
和
runtime
總結下,
Babel
只是轉換
syntax
層語法,所有需要
@babel/polyfill
來處理API相容,又因為
polyfill
體積太大,所以透過
preset
的 useBuiltIns 來實現按需載入,再接著為了滿足 npm 元件開發的需要 出現了
@babel/runtime
來做隔離
下面上一段 常見程式碼
轉換前程式碼
let
array
=
[
1
,
2
,
3
,
4
,
5
,
6
];
array
。
includes
(
item
=>
item
>
2
);
new
Promise
()
Babel轉換後代碼
var
array
=
[
1
,
2
,
3
,
4
,
5
,
6
];
array
。
includes
(
function
(
item
)
{
return
item
>
2
;
});
new
Promise
()
Babel
預設只是轉換了 箭頭函式
let
,
Promise
和
includes
都沒有轉換 ,這是為什麼
Babel
把
Javascript
語法 分為
syntax
和
api
先說
api
,
api
指那些我們可以透過 函式重新覆蓋的語法 ,類似
includes,map,includes,Promise
,凡是我們能想到重寫的都可以歸屬到
api
啥子是
syntax
,像 箭頭函式,
let,const,class, 依賴注入 Decorators
,等等這些,我們在
Javascript
在執行是無法重寫的,想象下,在不支援的瀏覽器裡不管怎麼樣,你都用不了 let 這個關鍵字
千萬要get到上面這2個點,非常重要,很多人以為只要 引用了
Babel
就不會出現相容性問題了,這個是大錯特錯的
syntax
這個關鍵字
Babel
的官網只是一筆帶過,直譯又不準確,網上很多文章在說
polyfill
和
transform-runtime
的差別都沒說到點上,還互相瞎雞兒抄,這個點上小編還是很自信的,按照自己的理解,說出二者的差別(默默的給自己加個雞腿)
那
Babel
只負責 轉換
syntax
,
includes,map,includes
這些
API
層面的 怎麼辦,
Babel
把這個放在了 單獨放在了
polyfill
這個模組處理
Babel
這個設計非常好, 把
Javascript
語法抽象成2個方面的,
syntax
和
polyfill
獨立開來,分而治理,
6to5
一開始設計是把二者放在一起的,大家想想
polyfill
隨著瀏覽器的不同,差異是非常大的,2個要是在一起 程式碼的耦合性就太大了,到處都是
if else
polyfill
直譯的話是墊片的意思,那處理類似
assign,includes,map,includes
,某些瀏覽器 沒有的方法 最直接的辦法的是 根據 一份瀏覽器不相容的表格(這個
browserslist
已經完成了),把對應瀏覽器不支援的語法全部重新寫一遍,類似下面這樣
//
if
(
typeof
Object
。
assign
!=
‘function’
)
{
Object
。
defineProperty
(
Object
,
“assign”
,
·····
}
if
(
!
Array
。
prototype
。
includes
){
Object
。
defineProperty
(
Array
。
prototype
,
‘includes’
,
·····
}
if
(
!
Array
。
prototype
。
every
){
Object
。
defineProperty
(
Array
。
prototype
,
‘every’
,
·····
}
。。。。。
好多好多
這種方式可以簡單粗暴的解決相容性問題, 那問題也來了,這樣會導致
polyfill。js
這個包非常大,這個大家又受不了
怎麼辦,Babel 開發大佬們肯定是又辦法的,只要我用到了
includes
Babel 就只給我引入
includes
的對應的不就好了,按需載入,要啥給我載入啥
這個就需要用到上篇說到
@babel/preset-env
的
useBuiltIns
屬性了,不瞭解
@babel/preset-env
看下上篇
useBuiltIns
有
false
,
entry
,
usage
三個屬性
先執行下
npm i @babel/polyfill -s
useBuiltIns 設定
false
是預設值,表示啥也不幹
entry
表示就是把全部
@babel/polyfill
全部一次性引入 ``` 。babelrc { “presets”: [ [ “@babel/preset-env”, { “debug”: true, “useBuiltIns”: “entry”, “targets”:{ “browsers”:[“> 1%”] } } ] ]
} ```
然後在
sample。js
中引入 打包後生成的 檔案是這樣樣子的
這個一般沒人用,長的醜的人才會用,因為體積實在是太大了
usage
的意思是 按需載入 ,把上面 改成
“useBuiltIns”: “usage”
打包出來如下
這就是這 2 個值得差別, 使 用
entry
需要手動在
sample。js
中手動
@babel/polyfill
,並且會把所有的
polyfill
引入進來, 使用
usage
實現按需載入,一般在專案裡使用這樣方式
runtime 機制,為元件開發而生
好,
polyfill
問題是已經解決了,現在又出現了一個場景, 假設你是開發 一個 npm 元件的選手 你剛好用到了
Promise
方法, 按照上面的方法,寫完釋出到 npm 倉庫 現在隔壁印度小哥剛好搜到你這包,下載下來了,但是他的專案裡面也用到了
Promise
,但是他的
Promise
是 自定義的 一套,類似
window。Promise = function (){
this。reject = 。。
this。resolve = 。。
}
這個時候就傻眼了,小哥專案跑不起來了,跑到 github 上用蹩腳 English 罵了你一通,這個場景其實很常見,那這麼辦,那假設在開發 元件的時能報把所有的
Promise copy
到
_Promise
物件上,然後元件裡都用
_Promise
,是不是就和外界做了層隔離,互不影響,哈哈完美,這個思路我們在開發設計中也是可以學習套用的,那
Babel
裡面針對 這種場景 出現了
@babel/runtime
,
@babel/plugin-transform-runtime
首先 執行下,這2個一個都不能少,都是必須的
// 。babelrc
{
“presets”: [
[
“@babel/preset-env”,
{
“debug”: true,
“useBuiltIns”: “false”,
“targets”:{
“browsers”:[“> 1%”, “last 2 versions”, “not ie <= 8”]
}
}
]
],
“plugins”: [
[
“@babel/plugin-transform-runtime”,
{
“corejs”: 2 // 參考官方文件
}
]
],
}
npm install ——save @babel/runtime
npm install ——save-dev @babel/plugin-transform-runtime
npm install ——save @babel/runtime-corejs2 ——save // 官方文件 說這個可以不加,我試了不加,沒起作用
上面程式碼 會轉換成如下
可以看到
Promise, Array。isArray,Object。assign
,都對應的轉換了 但是 圖片裡的
Array。prototype。includes
原型方法是沒有轉換的(網上文章講到這都是一筆帶過,壓根沒講為什麼會這樣設計),為啥
Babel
的作者為什麼這樣設計,其實是因為他無能為力,要實現 這個功能 需要在 把所有陣列包裹起來,例如下面這樣
let arry = [1,2,3,4] 轉換成
let array = function(){
return new _Array(1,2,3,4) // 假設是這個樣子
}
但是
Javascript
是個弱型別語言,在
AST
層面無法解析到判斷某個變數是不是一個數組,所以很無奈,
runtime
也不是包治百病,需要配合
@babel/polyfill
配合轉換 原型鏈上的方法
OK,可算寫完了,總結下,
Babel
只是轉換
syntax
層語法,所有需要
@babel/polyfill
來處理API相容,又因為
polyfill
體積太大,所以透過
preset
的
useBuiltIns
來實現按需載入,再接著為了滿足 npm 元件開發的需要 出現了
@babel/runtime
來做隔離
基本上這篇是大部分人在開發中常遇到,希望讀者都能掌握,看到這眼睛離開手機,會議下整篇文章。
大家可以看到我寫的東西都不是按照網上的 直接上程式碼,說明某個語法是幹嘛的,那樣非常好寫,但是缺乏生命, 看了就過了,很容易忘記
站在作者的角度思考為什麼這樣實現,感覺是一種隔著螢幕和網線那端作者對話,整個知識是流動了,不用強行記憶,就能記住某個配置的具體含義。推薦大家在學習新的東西時候也可以用這種方法,開始會慢些,但是基本不會忘記。
本文原創釋出於 同名微信公眾號 chromedev,給個讚唄。