Babel的运用

Babel引见

Babel 把用最新范例编写的 JavaScript 代码向下编译成可以在本日到处可用的版本。 这一历程叫做“源码到源码”编译, 也被称为转换编译。

15 年 11 月,Babel 宣布了 6.0 版本。相较于前一代 Babel 5,新一代 Babel 越发模块化, 将一切的转码功用以插件的情势星散出去,默许只供应 babel-core。底本只须要装一个 babel ,如今必需依据本身的需求设置,灵活性进步的同时也进步了运用者的进修本钱。

npm i babel
已弃用,你能下载到的仅仅是一段 console.warn,通知你 babel 6 不再以大杂烩的情势供应转码功用了。

比方,Babel 可以将新的 ES2015 箭头函数语法:

let fun = () => console.log('babel')

转译为:

"use strict";
var fun = function fun() {
  return console.log('babel');
};

不过 Babel 的用处并不止于此,它支撑语法扩大,能支撑像 React 所用的 JSX 语法,更主要的是,Babel 的一切都是简朴的插件,谁都可以建立本身的插件,应用 Babel 的悉数威力去做任何事变。
再进一步,Babel 本身被剖析成了数个中心模块,任何人都可以应用它们来建立下一代的 JavaScript 东西。

运用 Babel

babel-cli

Babel 的 CLI 是一种在命令行下运用 Babel 编译文件的简朴要领。

让我们先全局装置它来进修基础知识。

$ npm install --global babel-cli

我们可以如许来编译我们的第一个文件:

$ babel my-file.js

这将把编译后的效果直接输出至终端。运用 –out-file 或着 -o 可以将效果写入到指定的文件。

$ babel example.js --out-file compiled.js
# 或
$ babel example.js -o compiled.js

假如我们想要把一个目次全部编译成一个新的目次,可以运用 –out-dir 也许 -d。.

$ babel src --out-dir lib
# 或
$ babel src -d lib

babel-core

假如你须要以编程的体式格局来运用 Babel,可以运用 babel-core 这个包。

babel-core 的作用是把 js 代码剖析成 ast ,轻易各个插件剖析语法举行响应的处置惩罚。有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默许值等,这类言语层面的不兼容只能经由过程将代码转为 ast,剖析其语法后再转为低版本 js。
起首装置 babel-core。.

$ npm install babel-core
var babel = require("babel-core");

字符串情势的 JavaScript 代码可以直接运用 babel.transform 来编译。

babel.transform("code();", options);
// => { code, map, ast }

假如是文件的话,可以运用异步 api:

babel.transformFile("filename.js", options, function(err, result) {
  result; // => { code, map, ast }
});

也许是同步 api:

babel.transformFileSync("filename.js", options);
// => { code, map, ast }

其他用法

还可以经由过程babel-registerbabel-node运用Babel,但由于这两种用法不适合临盆环境故省略。

设置 Babel

你也许已注重到了,目前为止经由过程运转 Babel 本身我们并没能“翻译”代码,而仅仅是把代码从一处拷贝到了另一处。缘由就是从Babel 6今后, 默许的插件被移除, 假如没有指定一个插件,Babel将会原样输出, 不会举行编译。

你可以经由过程装置插件(plugins)或预设(presets,也就是一组插件)来指导 Babel 去做什么事变。

插件只是单一的功用,比方

  • es2015-arrow-functions

  • es2015-classes

  • es2015-for-of

  • es2015-spread

以下是装置箭头函数的插件体式格局

npm install --save-dev babel-plugin-transform-es2015-arrow-functions

假如我们一个一个惹人功用单一的插件的话显得迥殊贫苦,平常我们用的更多的是预设。插件和预设平常写入到设置文件中。可以将设置写入package.json的‘babel’属性里,也许是一个零丁的.babelrc文件。

.babelrc

在我们通知 Babel 该做什么之前,你须要做的就是在项目标根途径下建立 .babelrc 文件。然后输入以下内容作为最先:

{
  "presets": [],
  "plugins": []
}

这个文件就是用来让 Babel 做你要它做的事变的设置文件。

babel-preset-es2015

预设 babel-preset 系列打包了一组插件,类似于餐厅的套餐。如 babel-preset-es2015 打包了 es6 的特征,babel-preset-stage-0 打包处于 strawman 阶段的语法

我们须要装置 “es2015” Babel 预设:

$ npm install --save-dev babel-preset-es2015

我们修正 .babelrc 来包含这个预设。

{
    "presets": [
+     "es2015"
    ],
    "plugins": []
  }

一样的,另有babel-preset-2016babel-preset-2017

babel-preset-latest

latest是一个特别的presets,包含了es2015,es2016,es2017的插件(目前为止,今后有es2018也会包含进去)。即老是包含最新的编译插件。

babel-preset-env

上面提到的种种preset的题目就是: 它们都太”重”了, 即包含了过多在某些情况下不须要的功用. 比方, 当代的浏览器大多支撑ES6的generator, 然则假如你运用babel-preset-es2015, 它会将generator函数编译为庞杂的ES5代码, 这是没有必要的。但运用babel-preset-env, 我们可以声明环境, 然后该preset就会只编译包含我们所声明环境缺乏的特征的代码,因而也是比较引荐的体式格局。

装置babel-preset-env

npm install babel-preset-env --save-dev

增加设置

{
  "presets": ["env"]
}

当没有增加任何的设置选项时,babel-preset-env默许行动是和babel-preset-latest是一样的。
下面我们经由过程一些例子来看babel-preset-env的设置是怎样运用的:

  • 指定支撑主流浏览器最新的两个版本以及IE 7+:

"presets": [
    [
      "env",
      {
        "targets": {
          "browsers": ["last 2 versions", "ie >= 7"]
        }
      }
    ]
  ]
}
  • 支撑凌驾市场份额5%的浏览器:

"targets": {
  "browsers": "> 5%"
}
  • 某个牢固版本的浏览器:

"targets": {
  "chrome": 56
}

更多的设置请检察官方文档

babel-preset-stage-x

官方预设(preset), 有两种,一个是按年份(babel-preset-2017),一个是按阶段(babel-preset-stage-0)。 这主如果依据TC39 委员会ECMASCRPIT 宣布流程来制订的。TC39 委员会决议,从2016年最先,每一年都邑宣布一个版本,它包含每一年期限内完成的一切功用,同时ECMAScript的版本号也按年份编制,就有了ES2016, ES2017。所以也就有了babel-present-2016, babel-preset-2017, 对每一年新增的语法举行转化。babel-preset-latest 就是把一切es2015, es2016, es2017 悉数包含在一同了。

终究在阶段 4 被范例正式采用。
以下是4 个差别阶段的(打包的)预设:

  • babel-preset-stage-0

  • babel-preset-stage-1

  • babel-preset-stage-2

  • babel-preset-stage-3

注重 stage-4 预设是不存在的由于它就是上面的 es2017 预设。

以上每种预设都依靠于紧随的后期阶段预设,数字越小,阶段越靠后,存在依靠关联。也就是说stage-0是包含stage-1的,以此类推。也就是说这些stage包含的特征是比latest更新的特征但还未被写入范例举行宣布。

运用的时刻只须要装置你想要的阶段就可以了:

$ npm install --save-dev babel-preset-stage-2

然后增加进你的 .babelrc 设置文件。然则要注重假如没有供应es2017相干的预设,preset-stage-X 这类阶段性的预设也不能用。

实行 Babel 天生的代码

Babel 险些可以编译一切时新的 JavaScript 语法,但关于 APIs 来讲却并非如此。比方: Promise、Set、Map 等新增对象,Object.assign、Object.entries等静态要领。

为了杀青运用这些新API的目标,社区又有2个完成派别:babel-polyfill和babel-runtime+babel-plugin-transform-runtime。

这两个模块功用险些雷同,就是转码新增 api,模仿 es6 环境,但完成要领完全差别。babel-polyfill 的做法是将全局对象统统污染一遍,比方想在 node 0.10 上用 Promise,挪用 babel-polyfill 就会往 global 对象挂上 Promise 对象。关于平常的营业代码没有关联,但假如用在模块上就有题目了,会把模块运用者的环境污染掉。

babel-runtime 的做法是本身手动引入 helper 函数,照样上面的例子,const Promise = require(‘babel-runtime/core-js/promise’) 就可以引入 Promise。

但 babel-runtime 也有题目,第一,很不轻易,第二,在代码中中直接引入 helper 函数,意味着不能同享,形成终究打包出来的文件里有许多反复的 helper 代码。所以,babel 又开发了 babel-plugin-transform-runtime,这个模块会将我们的代码重写,如将 Promise 重写成 _Promise(只是打比方),然后引入_Promise helper 函数。如许就防止了反复打包代码和手动引入模块的痛楚。

babel-polyfill

为了处理这个题目,我们运用一种叫做 Polyfill(代码添补,也可译作兼容性补丁) 的手艺。 简朴地说,polyfill等于在当前运转环境顶用来复制(意指模仿性的复制,而不是拷贝)尚不存在的原生 api 的代码。能让你提早运用还不可用的 APIs,Array.from 就是一个例子。
Babel 用了优异的 core-js 用作 polyfill,而且另有定制化的 regenerator 来让 generators(天生器)和 async functions(异步函数)平常事情。
要运用 Babel polyfill,起首用 npm 装置它:

$ npm install --save babel-polyfill

然后只须要在文件顶部导入 polyfill 就可以了:

import "babel-polyfill";

babel-runtime

与 babel-polyfill 一样,babel-runtime 的作用也是模仿 ES2015 环境。只不过,babel-polyfill 是针对全局环境的,引入它,我们的浏览器就好像具有了范例里定义的完全的特征 – 虽然原生并未完成。
babel-runtime 更像是疏散的 polyfill 模块,我们可以在本身的模块里零丁引入,比方 require(‘babel-runtime/core-js/promise’) ,它们不会在全局环境增加未完成的要领,只是,如许手动援用每一个 polyfill 会异常低效。我们借助 Runtime transform 插件来自动化处置惩罚这一切。
经由过程装置 babel-plugin-transform-runtimebabel-runtime 来最先。

$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save babel-runtime

然后更新 .babelrc

    {
    "plugins": [
      "transform-runtime",
      "transform-es2015-classes"
    ]
  }

如今,Babel 会把如许的代码:

class Foo {
  method() {}
}

编译成:

import _classCallCheck from "babel-runtime/helpers/classCallCheck";
import _createClass from "babel-runtime/helpers/createClass";

let Foo = function () {
  function Foo() {
    _classCallCheck(this, Foo);
  }

  _createClass(Foo, [{
    key: "method",
    value: function method() {}
  }]);

  return Foo;
}();

如许就不须要把 _classCallCheck_createClass 这两个助手要领放进每一个须要的文件里去了。

那什么时刻用 babel-polyfill 什么时刻用 babel-runtime 呢?假如你不介意污染全局变量(如上面提到的营业代码),放心大胆地用 babel-polyfill ;而假如你在写模块,为了防止污染运用者的环境,没的选,只能用 babel-runtime + babel-plugin-transform-runtime

options

许多预设和插件都有选项用于设置他们本身的行动。 比方,许多转换器都有“宽松”形式,经由过程摒弃一些范例中的行动来天生更简化且机能更好的代码。

要为插件增加选项,只须要做出以下变动:

{
    "plugins": [
      "transform-runtime",
-     "transform-es2015-classes",
+     ["transform-es2015-classes", { "loose": true }]
    ]
}

plugins/presets排序:

  • 详细而言,plugins优先于presets举行编译。

  • plugins依据数组的index增序(从数组第一个到末了一个)举行编译。

  • presets依据数组的index倒序(从数组末了一个到第一个)举行编译。由于作者以为大部分会把presets写成[“es2015”, “stage-0”]。详细细节可以看这个。

webpack 中定义 babel-loader

很少有大型项目仅仅须要 babel,平常都是 babel 配合著 webpack 或 glup 等编译东西一同上的。
为了显出 babel 的本事,我们离别配个用 babel-polyfillbabel-runtime 、支撑 react 的webpack.config.js
先来配运用 babel-runtime 的:
起首装置:

npm install babel-loader babel-core babel-preset-es2015 babel-plugin-transform-runtime webpack --save-dev
npm install babel-runtime --save

然后设置

module: {
  loaders: [{
    loader: 'babel',
    test: /\.jsx?$/,
    include: path.join(__dirname, 'src'),
    query: {
      plugins: ['transform-runtime'],
      presets: [
        ["env", {
          "targets": {
            "chrome": 52
          },
          "modules": false,
          "loose": true
        }],
        'stage-2',
        'react'
      ],
    }
  }]
}

须要注重的是,babel-runtime 虽然没有出如今设置里,但仍然须要装置,由于 transform-runtime 依靠它。
再来个 babel-polyfill 的:

entry: [
  'babel-polyfill',
  'src/index.jsx',
],

module: {
  loaders: [{
    loader: 'babel',
    test: /\.jsx?$/,
    include: path.join(__dirname, 'src'),
    query: {
      presets: [
        ["env", {
          "targets": {
            "chrome": 52
          },
          "modules": false,
          "loose": true
        }],
        'stage-2',
        'react',
      ],
    }
  }]
}

参考文档:
http://babeljs.io/
https://github.com/thejamesky…
https://excaliburhan.com/post…
https://icyfish.me/2017/05/18…

    原文作者:ziison
    原文地址: https://segmentfault.com/a/1190000008159877
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞