Babel:下一代Javascript語法編譯器

定義

Babel是一個Javascript的編譯器,經過它你能夠將一些新版本的ECMAScript語法轉換成低版本的語法。以便可以在低版本的瀏覽器或者其它環境平穩運行。html

截至目前筆者寫這篇文章的時候,babel的版本是7.10.0node

實踐

第一步:建立項目

mkdir babel-study && cd babel-studylinux

第二步:初始化項目,並安裝相關依賴包

npm init -yios

npm i @babel/cli @babel/core @babel/preset-env --save-devgit

相關依賴包說明:es6

@babel/cli: hello,你好,我是腳手架工具,我能夠經過一些命令將源文件編譯成目標代碼。github

@babel/core: hello,你好,我是一個代碼分析選手,我負責將代碼分析稱ast,方便其餘插件進行相關處理。chrome

@babel/preset-env: hello,你好,我是一個語法轉義器,我負責的內容是將JS的相關語法進行編譯,關於轉義新增的API和全局對象這個我不負責的。npm

第三步:配置.babelrc

樓下這幾位就是經常使用的babel配置參數了,這裏作簡要介紹數組

presets(預設)

早期的版本實際上是引入相似babel-preset-x,這種形式的包,如今官方推薦統一用@babel/preset-env,這個包來作語法轉義器這部分的工做。

plugins(插件)

彌補babel自己上的功能不足,好比轉義新增的API和全局對象可能就須要用到一些新的插件來作這部分工做,咱們稱之爲補丁轉義器。

ignore(忽略)

把不須要babel編譯的文件寫配置到這個參數裏面,是一個數組的形式。

minified(壓縮)

Boolean類型的,將其設置爲true後,編譯後的文件會被壓縮。

comments(註釋)

Boolean類型的,將其設置爲true後,編譯後的文件會有註釋(你項目開發中寫的註釋)。

env(環境變量)

babel運行的環境變量,若是設置了BABEL_ENV則使用它,若是沒有設置,它會去找有沒有NODE_ENV,若是仍是沒有,那就是走默認development

這裏附上一份我調研後的配置文件

{
  "presets": [[
    "@babel/preset-env", {
      // "modules": false,
      "corejs": "3", 
      "useBuiltIns": "usage",
      "targets": {
        "node": "4"
        // "browsers": ["last 2 versions"]
      }
    }
  ]],
  "plugins": ["@babel/plugin-transform-runtime"],
  "env": {
    "test": {
      "presets": [[
        "@babel/preset-env", {
          "modules": false,
          "targets": {
            "node": "current",
            // "chrome": "83",
            // "edge": "17",
            // "firefox": "68",
            // "ie": "11",
            // "ios": "11.3",
            // "safari": "5.1",
            // "samsung": "9.2",
            "browsers": ["last 2 versions"]
          }
        }
      ]],
      "minified": true,  
      "comments": true,
      "ignore": ["./src/test.js"]
    },
    "development": {
      "presets": [[
        "@babel/preset-env", {
          "targets": {
            "browsers": ["last 2 versions", "safari 7"]
          }
        }
      ]]
    },
    "production": {
      "presets": [[
        "@babel/preset-env", {
          "targets": {
            "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
          }
        }
      ]],
      "plugins": ["@babel/runtime"],
      "minified": true,  
      "comments": true
    }
  }
}

這裏簡要說明下,modules默認爲true的,在node的環境下(支持COMMONJS),若是使用ES Module的語法(import、export),而後將其設置爲false,你會發現入口文件沒有被編譯,全部這裏把它去掉了。而後targets下面你能夠單獨設置相關環境的支持版本,browsers的優先級高於其餘的。babel7.4.0之後,廢棄了polyfill,須要單獨安裝core-js

第四步:編寫相關測試代碼

這裏咱們測試下ES Module寫法,而後一些新的API的轉義狀況,好比數組的include,箭頭函數、模板字符串、Promise等,這裏咱們不考慮相關的寫法是否是冗餘,單純地就是爲了測試下編譯效果。

animal.js

class Animal {
  constructor(name) {
    this.name = name;
  }

  eat() {
    console.log(`${this.name} is eating!`);
  }
}

export default Animal;

person.js

import Animal from './animal';

class Person extends Animal {
  constructor(name, sex) {
    super(name);
    this.name = name;
    this.sex = sex;
    this.sexMap = new Map([[1, '男'], [0, '女']]);
  }

  sing() {
    console.log(`${this.name} is singing!`);
  }

  getSex() {
    if (![0, 1].includes(this.sex)) {
      return false;
    } else {
      return this.sexMap.get(this.sex);
    }
  }

  testArr(arr) {
    return arr.map(item => item * 2);
  }

  testPromise() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(2020);
      }, 2000);
    });
  }
}

export default Person;

index.js

import Person from './person';
// 我就是試試
let ataola = new Person('ataola', 1);
ataola.eat();
ataola.sing();
const sex = ataola.getSex();
console.log(sex);
let testArr = ataola.testArr([0, 1, 2]);
console.log(testArr);
ataola.testPromise().then(res => {
  console.log(res);
});

第五步:babel-cli的使用

編譯項目文件

# 單純執行, 它會在控制檯打出編譯後的信息
babel index.js

# 完整寫法
babel index.js --out-file bundle.js
# 簡寫形式
babel index.js -o bundle.js

編譯項目文件夾

# 完整寫法
babel src -out-dir dist
# 簡寫形式
babel src -d dist
# 生成sourc map文件
babel src -d dist -s

babel-node

babel-cli自然自帶了一個babel-node的命令,拆分一下也就是babel + node,提供了一個支持ES6的REPL環境,你能夠這麼玩。

# 直接進到這個環境
babel-node

# 直接執行這個文件的代碼
babel-node index.js

最後附上個人測試腳本

...
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build:dir": "babel src -d dist",
    "build:dir:prod": "cross-env BABEL_ENV=production babel src -d dist",
    "build:dir:dev": "cross-env BABEL_ENV=development babel src -d dist",
    "build:dir:test": "cross-env BABEL_ENV=test babel src -d dist",
    "build:dir:s": "babel src -d dist -s",
    "build:file": "babel ./test/babel_core.test.js -o bundle.js"
  },
  ...

項目地址: https://github.com/ataola/JavaScript-Tsukuki/tree/master/code/babel-study

問題思考

在項目中使用Babel,它的做用是什麼?或者這麼說它的意義何在?

將高版本的JS語法轉換成低版本的JS語法,可兼容不一樣版本的瀏覽器或者運行環境,劃重點,解決了代碼在不一樣版本的瀏覽器的兼容性問題。人的腦容量都是有限的,兼容的事情就愉快地交給它吧。

使用Babel後,把源代碼編譯成更復雜更難懂一坨坨的東西,我爲何要去用它?

首先,這絕對不是爲了裝逼,也不是爲了混淆代碼。咱們先思考下使用高版本的語法它有什麼用?有一些實際上是低版本的語法糖,使用了這些咱們能夠減小代碼量,而後減輕維護成本。可是ECMAScript它是一個語法標準,不一樣的JS引擎以及瀏覽器對它的實現和支持又不大同樣,全部咱們不可以保證使用高版本的語法它可以完美在各平臺運行,這也就是babel的做用體現。

ES的語法有那麼多版本,Babel的配置有那麼多個版本,我該怎麼去選擇呢?

早期地預設有babel-preset-es201五、babel-preset-stage-x之類的啥的,如今官方推薦統一@babel/preset-env,腳手架統一@babel/cli,對,不成文地規定就是@babel打頭基本是對的,polyfill除外。

@babel/xxx和 babel-xxx的,爲何會有兩種,該用哪一個?

先說結論,用前者@babel/xxx, @xxx就至關於註冊了一個命名空間,特指這個是xxx下的某包,它是一個範圍,是一種組織的體現形式,例如@ataola/zjt,

.babelrc文件我不寫行不行,能運行嗎?

若是隻是建立一個.babelrc裏面什麼都不寫,會報錯,由於babel會讀取裏面的格式,加個{},這個是能夠運行的,裏面什麼都不寫。這裏思考下babel的默認行爲是什麼?只是轉換了Javascript的語法,而不對新的API進行轉換,新的仍是要用插件的。

什麼是語法轉義器,什麼是補丁轉義器?

在presets裏的形如@babel/preset-env就是語法轉義器,在plugins下的插件包就是補丁轉義器,它們的分工不一樣,前者是將相關語法進行編譯,後者彌補了前者的一些不足,故稱之爲補丁。

targets裏設置browsers的優先級高,仍是直接設置瀏覽器的優先級高?

設置browsers的優先級高於直接設置瀏覽器的,會覆蓋後者。

爲何將modules設置成false,是否還有其餘設置方案?

說明其默認爲true,默認都是支持commonjs規範的。還能夠設置成amd、umd之類的。

transform-runtime解決了一個什麼問題?

解決了es6語法中全局對象或者全局對象方法編譯不足的狀況。

既然transform-runtime只是解決es6,那我要是用es七、es八、es9甚至更高怎麼辦呢?

babel-polyfill , core-js、regenerator-runtime

爲何不推薦全局安裝腳手架?

版本更新迭代太快了,安裝在項目本地易升級。

BABEL_ENV或者NODE_ENV的設置方式

# osx|linux
export NODE_ENV=production

#window
SET NODE_ENV=production

Babel的默認行爲是什麼?

轉換了形如let、箭頭函數之類的語法, 若是要徹底的ES6語法支持須要安裝plugin-transform-runtime插件,若是須要更高版本的話,那就須要安裝polyfill插件。

參考文獻

babel官網:https://babeljs.io/

@babel/preset-env文檔:https://babeljs.io/docs/en/babel-preset-env/

@babel/plugin-transform-runtime:https://babeljs.io/docs/en/next/babel-plugin-transform-runtime.html

@babel/cli文檔:https://babeljs.io/docs/en/babel-cli

babel配置文件:https://babeljs.io/docs/en/config-files#file-relative-configuration

babel環境變量配置:https://babeljs.io/docs/en/options#envname

@xxx npm包的解釋 About Scope: https://docs.npmjs.com/about-scopes

知識共享許可協議
本做品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

相關文章
相關標籤/搜索