10月07, 2016

babel的一些笔记

最近写的申报框架,主要让我有三个启发:

  • 错误的异常捕获
  • 模块化的重要性
  • 学会写测试用例

其实第二点和第三点,可以放在一起来说。大家都知道jQuery一个文件有好几千行,像我上面的申报框架也差不多有2000多行。但其实这些代码是可以做拆分的。jQuery2已经开始做拆分了,更不要说jQuery3了。

拆分的好处有很多,比如:

  • 职责更加清晰,我这个类就做这个事,不处理其他
  • 方便写测试

拆分的思想就是模块化。这里有一篇文章:js模块化历程,讲述了模块化的发展历程。

那么提到模块化,不得不提的就是ES6。但是目前并不是所有的浏览器能支持ES6语法,所以就有了babel。

babel是什么

Babel 是一个通用的多用途 JavaScript 编译器(Babel is a JavaScript compiler.)。通过 Babel 你可以使用(并创建)下一代的 JavaScript,以及下一代的 JavaScript 工具。

作为一种语言,JavaScript 在不断发展,新的标准/提案和新的特性层出不穷。 在得到广泛普及之前,Babel 能够让你提前(甚至数年)使用它们。

Babel 把用最新标准编写的 JavaScript 代码向下编译成可以在今天随处可用的版本。 这一过程叫做“源码到源码”编译, 也被称为转换编译(transpiling,是一个自造合成词,即转换+编译。以下也简称为转译)。

例如,Babel 能够将新的 ES2015 箭头函数语法:

const square = n => n * n;

转译为:

const square = function square(n) {
  return n * n;
};

不过 Babel 的用途并不止于此,它支持语法扩展,能支持像 React 所用的 JSX 语法,同时还支持用于静态类型检查的流式语法(Flow Syntax)。

更重要的是,Babel 的一切都是简单的插件,谁都可以创建自己的插件,利用 Babel 的全部威力去做任何事情。

再进一步,Babel 自身被分解成了数个核心模块,任何人都可以利用它们来创建下一代的 JavaScript 工具。

安装babel

npm install -g babel-cli

随后我们就可以编译一个文件了:

babel my-file.js

或者一个目录整个编译成一个新的目录

babel src -d lib

结合package.json

{
    "name": "my-project",
    "version": "1.0.0",
    "scripts": {
      "build": "babel src -d lib"
    }
}

然后通过npm run build的方式来编译目录,当然在命令中还可以加上'-w'来时时监听文件变化,时时编译文件。

然而在测试时,却发现有问题了。

上面的结果仅仅是把代码从一处拷贝到了另一处。

这是因为我们还没告诉 Babel 要做什么。

由于 Babel 是一个可以用各种花样去使用的通用编译器,因此默认情况下它反而什么都不做。你必须明确地告诉 Babel 应该要做什么。

你可以通过安装插件(plugins)或预设(presets,也就是一组插件)来指示 Babel 去做什么事情。(所谓的 presets 其实就是一些同类plugin打包的结果,方便进行添加)

.babelrc

在我们告诉 Babel 该做什么之前,我们需要创建一个配置文件。你需要做的就是在项目的根路径下创建 .babelrc 文件。然后输入以下内容作为开始:

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

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

比如常见的.babelrc案例是这样的:

{
  "presets":["react","es2015","stage-0"],
  "plugins": ["transform-object-assign"]
}

上面的transform-object-assign插件主要是用来编译Object.assgin方法的。

不得不提的stage-0

一开始我也不知道为什么有些时候要使用stage-0啊,stage-1啊这些东西,后来搞明白了。这个还得从es这门语言的规范制定说起。es作为一门语音,它的规范制定是由某个委员会来统筹的。就像法律一样,一个标准的诞生是要经过很多次的讨论的:一开始是一些不成熟的想法(stage-0:Strawman),通过之后变成提议(stage-1:Proposal),再通过进入草案(stage-2: Draft),再通过进入候选(stage-3: Candidate),最后才能进入标准(stage-4:finished)。标准里面的每一条都得经过层层的筛选,并不是所有都能在最后进入标准的,所以使用stage-x里面的新特性是有一定风险的,比如我们用得很多的async和await,它就是属于stage3,还差一点就进入标准了。所以,如果你想使用还没有进入标准的一些新特性,你就需要包含相应的stage-x-preset或者plugins。

这个流程分为 5(0-4)个阶段。 随着提案得到越多的关注就越有可能被标准采纳,于是他们就继续通过各个阶段,最终在阶段 4 被标准正式采纳。

以下是4 个不同阶段的(打包的)预设:

  • babel-preset-stage-0
  • babel-preset-stage-1
  • babel-preset-stage-2
  • babel-preset-stage-3

注意 stage-4 预设是不存在的因为它就是上面的 es2015 预设。

以上每种预设都依赖于紧随的后期阶段预设。例如,babel-preset-stage-1 依赖 babel-preset-stage-2,后者又依赖 babel-preset-stage-3。

Stage 0:

  • Function Bind Syntax:函数的绑定运算符
  • String.prototype.at:字符串的静态方法at

Stage 1:

  • Class and Property Decorators:Class的修饰器
  • Class Property Declarations:Class的属性声明
  • Additional export-from Statements:export的写法改进
  • String.prototype.{trimLeft,trimRight}:字符串删除头尾空格的方法

Stage 2:

  • Rest/Spread Properties:对象的Rest参数和扩展运算符

Stage 3:

  • SIMD API:“单指令,多数据”命令集
  • Async Functions:async函数
  • Object.values/Object.entries:Object的静态方法values()和entries()
  • String padding:字符串长度补全
  • Trailing commas in function parameter lists and calls:函数参数的尾逗号
  • Object.getOwnPropertyDescriptors:Object的静态方法getOwnPropertyDescriptors

Stage 4:

  • Array.prototype.includes:数组实例的includes方法
  • Exponentiation Operator:指数运算符

babel-polyfill

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。Babel默认不转码的API非常多,详细清单可以查看definitions.js文件。

开发环境与生产环境

babel是可以区分开发环境和生产环境的,就像webpack那样,具体可以参考这里

最后,这里有个很不错的babel中文手册,可供参考。

本文链接:www.my-fe.pub/post/some-about-babel.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。