對 babel polyfill 的一些理解

前言

爲了支持業務中少許的es6+的高級特性,最近在研究了一下babel的墊片,現將此整理爲文字,以下。node

babel 和 babel ployfill 的關係

一、先來理解下 babel 究竟是作什麼的?react

簡單來說, babel解決 語法層面的問題。用於將ES6+的高級語法轉爲ES5。

二、babel polyfill 又是作什麼的?webpack

若是要解決 API層面的問題,須要使用墊片。好比常見的有 babel-polyfillbabel-runtimebabel-plugin-transform-runtime

理清了他們之間的關係,那麼再正式來說講有關polyfill的二三事。git

polyfill 種類

babel polyfill 有三種es6

* babel-polyfill
* babel-runtime
* babel-plugin-transform-runtime

babel-polyfill

babel-polyfill經過向全局對象和內置對象的prototype上添加方法來實現的。因此這會形成全局空間污染github

babel-polyfill使用的兩種方式

一、webpack.config.js 中:
配置webpack.config.js裏的entry設置爲entry: ['babel-polyfill',path.join(__dirname, 'index.js')]web

二、業務 js 中:
webpack.config.js配置的主入口index.js文件的最頂層鍵入promise

import 'babel-polyfill'

二者打印出來的大小都是同樣的,打包後大小是280KB,若是沒有使用babel-polyfill,大小是3.43kb。兩則相差大概81.6倍。緣由是webpackbabel-polyfill總體所有都打包進去了。而babel-polyfill確定也實現了全部ES6新API的墊片,文件必定不會小。瀏覽器

那麼有沒有一種辦法,根據實際代碼中用到的ES6新增API ,來使用對應的墊片,而不是所有加載進去呢?
是的,有的。那就是 babel-runtime & babel-plugin-transform-runtime,他們能夠實現按需加載。babel

babel-runtime

簡單說 babel-runtime 更像是一種按需加載的實現,好比你哪裏須要使用 Promise,只要在這個文件頭部

import Promise from 'babel-runtime/core-js/promise'

就好了。

不過若是你許多文件都要使用 Promise,難道每一個文件都要 import 一下嗎?固然不是,Babel 官方已考慮這種狀況,只須要使用 babel-plugin-transform-runtime 就能夠解決手動 import 的苦惱了。

babel-plugin-transform-runtime

babel-plugin-transform-runtime 裝了就不須要裝 babel-runtime了,由於前者依賴後者。
總的來講,babel-plugin-transform-runtime 就是能夠在咱們使用新 API 時 自動 import babel-runtime 裏面的 polyfill,具體插件作了如下三件事情:

  • 當咱們使用 async/await 時,自動引入 babel-runtime/regenerator
  • 當咱們使用 ES6 的靜態事件或內置對象時,自動引入 babel-runtime/core-js
  • 移除內聯 babel helpers 並替換使用 babel-runtime/helpers 來替換

babel-plugin-transform-runtime 優勢:

  • 不會污染全局變量
  • 屢次使用只會打包一次
  • 依賴統一按需引入,無重複引入,無多餘引入
  • 避免 babel 編譯的工具函數在每一個模塊裏重複出現,減少庫和工具包的體積

使用方式

在 .babelrc 中配置:

plugins:\["tranform-runtime"\]

打包後大小爲 17.4kb,比以前的280kb要小不少。

Plugin 插件

一、官方 Presets

若是不想本身設置一堆插件的話,官方有envreactflow三個 Presets。即預安裝了 plugins 的配置。

presets 屬性告訴 Babel 要轉換的源碼使用了哪些新的語法特性, presets 是一組 Plugins 的集合。如:
babel-preset-es2015: 能夠將es6的代碼編譯成es5
babel-preset-es2016: 能夠將es7的代碼編譯爲es6
babel-preset-es2017: 能夠將es8的代碼編譯爲es7
babel-preset-latest: 支持現有全部ECMAScript版本的新特性

當咱們須要轉換es6語法時,能夠在 .babelrc 的 plugins 中按需引入一下插件,好比:check-es2015-constantses2015-arrow-functionses2015-block-scoped-functions等等幾十個不一樣做用的 plugin。.babelrc 中配置項多是以下方式:

{
  "plugins": \[
    "check-es2015-constants",
    "es2015-arrow-functions",
    "es2015-block-scoped-functions",
    // ...
  \]
}

但 Babel 團隊爲了方便,將同屬 ES2015 的幾十個 Transform Plugins 集合到 babel-preset-es2015 一個 Preset 中,這樣咱們只須要在 .babelrc 的 presets 加入 ES2015 一個配置就能夠完成所有 ES2015 語法的支持了。.babelrc 中配置以下:

{
  "presets": \[
    "es2015"
  \]
}

二、Stage-X(試驗性 Presets)

這個比較好理解,就是爲了支持 TC39 對於草案階段的 ES 最新特性而開發的 presets。

  • Stage 0 - 草稿:只是一個設想多是一個 Babel 插件
  • Stage 1 - 提案:值得去推動的東西
  • Stage 2 - 草案:初始化規範
  • Stage 3 - 候選:完整規範和初始化瀏覽器實現
  • Stage 4 - 完成:會加入到下一版中

三、轉換插件

官方和民間提供了不少的轉換插件,用於指定對某一項 ES 高級特性進行轉換。
官方見:https://babeljs.io/docs/en/pl...

四、語法插件

這種插件可讓Babel來解析特殊類型的語法。

{
  "parserOpts": {
    "plugins": \["jsx", "flow"\]
  }
}

五、插件開發

見文檔:https://github.com/jamiebuild...

開發採用了 AST 抽象語法樹,相似於 Eslint 插件開發。

export default function () {
  return {
    visitor: {
      Identifier(path) {
        const name = path.node.name;
        // reverse the name: JavaScript -> tpircSavaJ
        path.node.name = name.split("").reverse().join("");
      }
    }
  };
}

webpack 中使用 babel 二三事

babel 用途是語法轉換,因此webpack 中須要用到 babel-loader。而 babel-core 是 Babel 編譯器的核心,所以也就意味着若是咱們須要使用 babel-loader 進行 es6 轉碼的話,咱們首先須要安裝 babel-core

總結

使用場景建議:

  • 開發應用建議使用 babel-polyfill 會在全局新增對應方法
  • 開發框架建議 babel-plugin-transform-runtime 局部變量 不會污染全局,局部使用es6的函數或方法

以上,若有寫的不正確或者有疑問的地方請留言。未完待續,本文會持續更新babel相關知識。

相關文章
相關標籤/搜索