babel学习笔记

babel: 把符合最新标准的js代码向下编译成现在随处可用的版本,还支持语法扩展,如支持React用的JSX语法,还支持用于静态类型检查的流式语法(Flow Syntax)。

babel的一切都是简单的插件,你也可以利用babel创建自己的插件。

babel自身被分解成了数个核心模块,任何人都可以利用它们来创建下一代的js工具(围绕着babel已涌现出了大规模和多样化的生态系统)。

Babel 几乎可以编译所有时新的 JavaScript 语法,但对于 APIs 来说却并非如此。如它能编译箭头函数语法,却无法编译Array.from()这个新的api。为了解决这个问题,我们使用一种叫做 Polyfill(代码填充,也可译作兼容性补丁) 的技术。 简单地说,polyfill 即是在当前运行环境中用来复制尚不存在的原生 api 的代码。 能让你提前使用还不可用的 APIs,Array.from 就是一个例子。

js发展史:

1996年,网景浏览器,网景把javascript提交给 ECMA International(欧洲计算机制造商协会) 进行标准化,并最终确定出新的语言标准,它就是 ECMAScript。自此,ECMAScript 成为所有 JavaScript 实现的基础,不过,现实中我们只用 ECMAScript 称呼标准,平时都还是使用 JavaScript 来称呼这个语言。
标准(Standard): 用于定义与其他事物区别的一套规则。
实现(Implementation): 某个标准的具体实施/真实实践。

1996--2011年,相继发布了ECMAScript3,(ECMAScipt4由于太过激进而被抛弃),ECMAScript5,但由于现实中的很多实现和标准大相径庭,大部分开发者依然写着ECMAScript3风格的代码。 

2012年,由于开始停止对旧版浏览器的支持,用ECMAScript5(ES5)编写代码变得可行。并且新的ES6标准开始启动。

2015 年,负责制定 ECMAScript 规范草案的委员会 TC39 决定将定义新标准的制度改为一年一次(所以开始以年份来命名ECMAScript标准了),这意味着每个新特性一旦被批准就可以添加,而不像以往一样,规范只有在整个草案完成,所有特性都没问题后才能被定稿。因此,ES6在2015年6月份公布之前又被重命名为了 ECMAScript 2015(ES2015)

2016年,提议中的新的js语法ES2016,或称为ES7。

2017年,提议中的新的js语法ES2017,或称为ES8,如async, await。

js提案要被正式采纳必须经过5(0-4)个阶段,相继通过各个阶段,最终在阶段4被标准正式采纳。

 

.babelrc:

babel的配置文件,用来让babel做你要它做的事情的配置文件,存放在项目的根目录下,用来设置转码规则和插件。在 babel 6 里,执行 babel test.js,只会输出原样的文本,因为 babel 不再包含任何 transform 功能,babel 6 里把它们作为插件(plugin)分割出去,需要我们自己配置插件,.babelrc文件内容为:

{
  "presets": [],   // 转码规则
  "plugins": []    // 插件
}

比如要使用es6的箭头函数,必须配置"plugins": ["transform-es2015-arrow-functions"]。基本上 ES6/ES7 的各种功能,babel 都提供了相应的插件用于转换,但如果我们要一个一个配置 – 那就太恼人了。所以 babel 还提供了一个方法:presets。我们不妨把 presets 理解为套餐,不同套餐有不同的插件组合,比如 ES2015 preset 里打包了所有用于转换 ES2015 代码的插件,React preset 则打包了转换 react.js jsx 语法的插件。

转码规则可以根据需要按照:

# ES2015转码规则
$ npm install --save-dev babel-preset-es2015  //包含所有es2015的特性

# react转码规则
$ npm install --save-dev babel-preset-react

# ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
$ npm install --save-dev babel-preset-stage-0  //包含了async,await等
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3

然后,将这些规则加入.babelrc:

{
    "presets": [
      "es2015",
      "react",
      "stage-2"
    ],
    "plugins": []
  }

以下所有Babel工具和模块的使用,都必须先写好.babelrc。也可以把内容写进package.json文件里:

"babel": {
    "presets": [
      "react",
      "node5",
      "stage-0"
    ],
     "plugins": []
},

babel-cli,babel-node:

全局按照babel-cli,就可以在命令行下使用Babel编译文件了,如babel src -d lib (把src目录整个编译成一个新的目录)或babel example.js -o compiled.js (把example.js编译后的结果写入到compiled.js)。但是不推荐全局安装,导致项目产生了对环境的依赖,另一方面,这样做也无法支持不同项目使用不同版本的Babel。一般在项目中安装babel: npm install babel-cli --save-dev ,把命令写在npm scripts里,如"scripts": {"build": "babel src -d lib"},然后就可以在终端里运行npm run build。

babel-node不用单独安装,而是随babel-cli一起安装。babel-node命令,它近似于 node,只不过它在运行代码前会预先编译 ES2015 的代码。提供一个支持ES6的REPL环境。它支持Node的REPL环境的所有功能,而且可以直接运行ES6代码或脚本文件。

把npm scripts改写成"scripts": {"build": "babel-node scripts.js"},这样script.js本身就不用做任何转码处理。

babel-register:

运行babel的另一个方法,只需要引入文件就可以运行 Babel,或许能更好地融入你的项目设置。babel-register模块改写require命令,为它加上一个钩子。此后,每当使用require加载.js、.jsx、.es和.es6后缀名的文件,就会先用Babel进行转码。如创建一个register.js文件:

require("babel-register")
require("./index.js")

这样做就可以把 Babel注册到 Node 的模块系统中并开始编译其中 require 的所有文件。这样执行命令node register.js就可以运行的就是编译后的index.js文件了。需要注意的是,babel-register只会对require命令加载的文件转码,而不会对当前文件转码。另外,由于它是实时转码,所以只适合在开发环境使用。

babel-core:

以编程的方式来使用 Babel,如果某些代码需要调用Babel的API进行转码,就要使用babel-core模块。

var babel = require('babel-core');
// 字符串转码
babel.transform('code();', options);
// => { code, map, ast }
// 文件转码(异步)
babel.transformFile('filename.js', options, function(err, result) {
  result; // => { code, map, ast }
});
// 文件转码(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }

babel-polyfill:

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。如果想让这些方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。

要使用 Babel polyfill,首先用 npm 安装它:npm install --save babel-polyfill,然后只需要在文件顶部导入 polyfill 就可以了:import 'babel-polyfill'或是在webpack.config.js中加入babel-polyfill到你的入口数组:entry:["babel-polyfill","./app/js"]

babel-runtime:

与 babel-polyfill 一样,babel-runtime 的作用也是模拟 ES2015 环境。只不过,babel-polyfill 是针对全局环境的引入它的,babel-runtime 更像是分散的 polyfill 模块,我们可以在自己的模块里单独引入,比如 require(‘babel-runtime/core-js/promise’) ,它们不会在全局环境添加未实现的方法,只是,这样手动引用每个 polyfill 会非常低效。我们借助 Runtime transform 插件来自动化处理这一切。安装:npm install --save-dev babel-plugin-transform-runtime    npm install --save babel-runtime; 配置.babelrc: "plugins":["transform-runtime"],这样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;
}();

至于要用 babel-polyfill 还是 babel-runtime,则需要根据具体需求。举个例子,如果一个库里引用了 babel-polyfill,别人的库也引用了 babel-polyfill,我们很可能会跑两个 babel-polyfill 实例,这里,使用 babel-runtime 会更合适。

手动指定插件:

你可以安装一些别的插件,配置.babelrc的plugins,这样能让你对正在使用的转换器进行更细致的控制。如babel-plugin-transform-es2015-classes插件。插件列表可参考babel官方网址

插件选项:很多插件也有选项用于配置他们自身的行为。 例如,很多转换器都有“宽松”模式,通过放弃一些标准中的行为来生成更简化且性能更好的代码。如"plugins":[ ["transform-es2015-classed", {"loose":true}] ]。

基于环境自定义babel:

Babel 插件解决许多不同的问题。 其中大多数是开发工具,可以帮助你调试代码或是与工具集成。 也有大量的插件用于在生产环境中优化你的代码。因此,想要基于环境来配置 Babel 是很常见的。你可以轻松的使用 .babelrc 文件来达成目的。

{
    "presets": [...],
    "plugins": [...],
    "env": {
      "development": {
        "plugins": [...]
      },
       "production": {
        "plugins": [...]
      }
    }
 }

Babel 将根据当前环境来开启 env 下的配置。当前环境可以使用 process.env.BABEL_ENV 来获得。 如果 BABEL_ENV 不可用,将会替换成 NODE_ENV,并且如果后者也没有设置,那么缺省值是"development"

手动指定插件?插件选项?环境特定设置?所有这些配置都会在你的项目里产生大量的重复工作。为此可以创建自己的预设并发布,使用时直接安装就可以了,比如 babel-preset-airbnb

Babel和其他工具:

以eslint为例,eslint是最流行的语法检查工具之一。首先安装 eslint 和 babel-eslint,然后创建或使用项目现有的 .eslintrc 文件并设置 parser 为 babel-eslint,现在添加一个 lint 任务到 npm 的 package.json 脚本中就可以了,"scripts": {"lint": "eslint my-files.js"}。

webpack中定义babel-loader:

webpack.config.js中的loaders配置参考:

loaders: [     
  {
      test: /\.jsx?$/,
      loader: 'babel-loader',
      include: [
          path.resolve(__dirname, '../src'),
      ],
      query: {
          babelrc: false,
          presets: [
              'react',
              'es2015',
              'stage-0',
          ],
          plugins: [
              'transform-runtime'
           ]
      }
  }
]

 

posted @ 2017-06-07 15:12  荔枝龙眼  阅读(2261)  评论(0编辑  收藏  举报

这里是页脚Html代码