第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

中引入 打包後生成的 檔案是這樣樣子的

Babel學習系列4-polyfill和runtime差別(必看)

這個一般沒人用,長的醜的人才會用,因為體積實在是太大了

usage

的意思是 按需載入 ,把上面 改成

“useBuiltIns”: “usage”

打包出來如下

Babel學習系列4-polyfill和runtime差別(必看)

這就是這 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 // 官方文件 說這個可以不加,我試了不加,沒起作用

上面程式碼 會轉換成如下

Babel學習系列4-polyfill和runtime差別(必看)

可以看到

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,給個讚唄。

Babel學習系列4-polyfill和runtime差別(必看)