babel相關總結

對babel一直沒具體總結過,趁週末看了下文檔,記錄一下

babel做爲一個compiler,主要用在轉換新的es標準實現來使全部瀏覽器都支持,這包含兩方面react

  1. 新的es標準語法,箭頭函數、擴展運算符、塊級做用域等
  2. 轉化新的es標準方法或正被提議還未歸入標準的方法,,Array.from、Map、Promise、String.includes等

babel編譯過程

babel的編譯過程分爲三個階段,解析、轉換、生成瀏覽器支持的代碼。官網推薦了一個the-super-tiny-compiler,描述了相似babel這樣的compiler大致是如何工做的。webpack

  • 解析 解析源代碼,構造抽象語法樹
  • 轉換 使用各類plugin處理AST,轉換成一個新的AST
  • 生成代碼 根據新的AST,生成代碼字符串

具體細節參見the-super-tiny-compilergit

處理新的語法

對es新增語法的處理是藉助babel的各類plugin,各類plugin做用在babel編譯的第二個階段,轉化階段es6

presetsgithub

presets能夠看作是一部分plugin的集合,目前官方提供的presets有env、react、flowweb

在babel還不支持env以前,咱們通常在.babelrc中指定api

{
    presets:['es2015','es2016','stage-2']
}

像es2015表示babel會使用以下這些plugin處理咱們代碼中使用的新語法瀏覽器

如今咱們能夠這樣寫babel

{
    presets:['env']
}

等價於babel-preset-latest,能夠轉換已經在標準中的es6,es7等的新語法,須要注意的是env並不會處理被提議的stage-x中的新語法,要使用那些語法要本身在presets中執行stage-xapp

而且只是指定env,而不指定相關的targets信息的話,babel只會轉換新語法,對新方法不會作處理

處理新的方法

babel-polyfill

爲了支持es新增api的轉化,咱們可使用babel-polyfill,這個庫內部使用core-js(那個做者打廣告說正在找工做的庫)和regenerator來模擬實現新增api.

使用polyfill的缺點

  1. polyfill須要首先被引入,在文件首部或者webpack中entry: ["babel-polyfill", "./app/js"],整個文件會和咱們src下的代碼打包在一塊兒,增大文件大小
  2. polyfill會在js內置對象的原型上增長方法,例如String.prototpe.includes,污染全局做用域

一個減少使用polyfill後打包代碼過大問題的方法 useBuiltIns=true

useBuiltIns默認不開啓,開啓後,咱們import "babel-polyfill"會根據當前targets指定的環境引入必須的文件

import "babel-polyfill";

輸出:根據環境

import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
import "core-js/modules/web.timers";
import "core-js/modules/web.immediate";
import "core-js/modules/web.dom.iterable";

必定程度上減少打包文件大小

transform-runtime

使用babel-polyfill會有使打包文件過大和污染全局做用域的問題,因此babel提供了babel-plugin-transform-runtime來解決一些問題

  1. 優化幫助函數引用

babel內部提供了不少幫助函數來處理語法轉化的須要,transform-runtime會把對幫助函數的調用替換爲對模塊的引用

class Person {
}

輸出:

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Person = function Person() {
  _classCallCheck(this, Person);
};

_classCallCheck是一個幫助函數,若是咱們多個js文件中都有定義class類,_classCallCheck就會在多個文件中都存在,形成幫助函數重複,增大打包文件大小。而transform-runtime會將幫助函數以引用的方式調用(引用babel-runtime/helpers/xxx下面的),避免重複

  1. 對於新增api的轉化,transform-runtime使用babel-runtime/core-js下對應的同名方法,而不須要引用babel-polyfill,只會須要哪一個,就require哪一個core-js下對應的實現.避免污染全局做用域

transform-runtime的缺點

由於不會在js原生對象原型上添加方法,因此transform-runtime不會轉化新增的實例方法,例如不能處理"foobar".includes("foo")

對於新增api如何處理

若是項目中使用了大量新增api,並使用大量新增的實例方法,應該使用polyfill,爲了必定程度上減少打包文件的體積,應該啓用useBuiltIns=true,並指定代碼的最低運行環境,儘可能減小沒必要要的polyfill,同時加入transform-runtime,設置polyfill=false

{
    "presets":[
        ['env',{
            "targets":{
                "browsers": [
                    "last 2 versions",//各個瀏覽器的最新兩個版本
                    "safari >= 7"
                ]
            },
            "debug": true,
            "useBuiltIns": true
        }]
    ],
    "plugins":[
        ["transform-runtime", { //不處理新的方法,只處理幫助函數
            "helpers": true,
            "polyfill": false,
            "regenerator": false,
            "moduleName": "babel-runtime"
        }]
    ]
}

若是項目並不使用新增實例方法(不多這樣的狀況),並不想污染全局做用域,應該使用transform-runtime

{
    "presets":['env'],//處理新的語法,但新的方法由transform-runtime插件處理
    "plugins":[
        ["transform-runtime", {
            "helpers": true,
            "polyfill": true,
            "regenerator": true,
            "moduleName": "babel-runtime"
        }]
    ]
}

原文地址

相關文章
相關標籤/搜索