资讯专栏INFORMATION COLUMN

你真的会用 Babel 吗?

mochixuan / 1034人阅读

摘要:安装然后在的配置文件加入入口文件引入这样就可以啦,还是可以减少很多代码量的。是参数,等同于执行正常。这个包很简单,就是引用了和,然后生产环境把它们编译到目录下,做了映射,供使用。

引入

这个问题是对自己的发问,但我相信会有很多跟我一样的同学。
对于 babel 的使用,近半年来一直停留在与 webpack 结合使用,以及在浏览器开发环境下。导致很多 babel 的包,我都不清楚他们是干嘛的。比如 babel-register,还有 babel-runtime,各种 presets 的区别,transform-runtime 和 babel-polyfill 的区别,helpers 是干嘛的。尽管网上的 babel 的教程很多了,但是解答自己的一些疑问,还是要花费一些功夫。所以抽出时间来总结一下。如果你对于以上概念已经比较清楚了,就不需要往下看了。

本次的 example 代码都在 github 上,而且每个文件夹都有详细的 README,说明我的使用方式。可以去参照一下用例的使用,并 clone 下来自己研究一下。

版本变化

说实话,从我做前端的时候,接触 babel 的时候,就已经是 babel 6 了,但是这不妨碍了解一下它的重大版本变化。
上一个版本 babel 5 是全家桶,包括各种package, plugins,尽可能的想通过你的一次安装,达到全能的效果。不过你现在安装npm install babel,会得到一个 warning。babel 6 是 2015年10月30号发布,主要做了以下更新:

拆分成几个核心包,babel-core,babel-node,babel-cli...

没有了默认的转换,现在你需要手动的添加 plugin。也就是插件化

添加了 preset,也就是预置条件。

增加了 .babelrc 文件,方便自定义的配置。

差不多了,我感觉其他的也不需要了解了。

babel 里面有好多的包,所以必须搞清楚他们都是干嘛的,才能让我们更好的使用这个工具。

babel-core

可以看做 babel 的编译器。babel 的核心 api 都在这里面,比如 transform,主要都是处理转码的。它会把我们的 js 代码,抽象成 ast,即 abstract syntax tree 的缩写,是源代码的抽象语法结构的树状表现形式。我们可以理解为,它定义的一种分析 js 语法的树状结构。也就是说 es6 的新语法,跟老语法是不一样的,那我们怎么去定义这个语法呢。所以必须要先转成 ast,去发现这个语法的 kind,分别做对应的处理,才能转化成 es5.

主要 api:

var babel = require("babel-core");
var transform = babel.transform;

babel.transform(code: string, options?: Object)

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

babel.transformFile(filename: string, options?: Object, callback: Function)

var path = require("path");
var result = babel.transformFileSync(path.resolve(__dirname) + "/test.js", {
  presets: ["env"],
  plugins: ["transform-runtime"],
}, function(err, result) {// { code, map, ast }
    console.log(result);
});

babel.transformFileSync(filename: string, options?: Object)

var result = babel.transformFileSync(path.resolve(__dirname) + "/test.js", {
  presets: ["env"],
  plugins: ["transform-runtime"],
});
console.log(result, "res");

babel.transformFromAst(ast: Object, code?: string, options?: Object)

反转,你把 ast 传入,解析为 code 代码。

options

babel-cli

提供命令行运行 babel。也就是你可以 babel filename 去对文件转码。
安装的话

npm install --save-dev babel-cli

npm isntall babel-cli -g

使用对应就是

node_module/.bin/babel script.js --out-file script-compiled.js

babel script.js --out-file script-compiled.js

具体使用还是看官方文档吧,我就不搬文档了。

babel-external-helpers

babel-cli 中的一个command,用来生成一段代码,包含 babel 所有的 helper 函数。

首先我们需要了解什么是 helpers。babel 有很多帮助函数,例如 toArray函数, jsx转化函数。这些函数是 babel transform 的时候用的,都放在 babel-helpers这个包中。如果 babe 编译的时候检测到某个文件需要这些 helpers,在编译成模块的时候,会放到模块的顶部。
像这样

(function(module, exports, __webpack_require__) {

function _asyncToGenerator(fn) { return function () {  }; } // 模块顶部定义 helper

// some code 
// async 语法已经被 transform-async-to-generator 转化,再利用 helper 函数包装,消费 generator。
const func = (() => {
  var _ref = _asyncToGenerator(function* () {
    console.log("begin");
    yield new Promise(function (resolve) {
      setTimeout(function () {
        resolve();
      }, 1000);
    });
    console.log("done");
  });
})

})

但是如果多个文件都需要提供,会重复引用这些 helpers,会导致每一个模块都定义一份,代码冗余。所以 babel 提供了这个命令,用于生成一个包含了所有 helpers 的 js 文件,用于直接引用。然后再通过一个 plugin,去检测全局下是否存在这个模块,存在就不需要重新定义了。

使用:

执行 babel-external-helpers 生成 helpers.js 文件,

 node_modules/.bin/babel-external-helpers > helpers.js

注意:示例代码的包都是装到项目中的,也就是本地。同样你可以全局安装直接执行。

安装 plugin

npm install --save-dev babel-plugin-external-helpers

然后在 babel 的配置文件加入

{
  "plugins": ["external-helpers"]
}

入口文件引入 helpers.js

require("./helpers.js");

这样就可以啦,还是可以减少很多代码量的。另外如果使用了 transform-runtime,就不需要生成 helpers.js 文件了,这个在后面的 babel-runtime 再说。

babel-node

也是 babel-cli 下面的一个 command,主要是实现了 node 执行脚本和命令行写代码的能力。举两个栗子就清楚了。

执行脚本

node 环境肯定是不支持 jsx 的

// test.js
const React = require("react");
const elements = [1, 2, 3].map((item) => {
  return (
    
{item}
) }); console.log(elements);

执行 test.js,会报错,不认识这个语法。

node test.js //报错

但是使用 babel-node 就可以。

 node_modules/.bin/babel-node --presets react test.js

--presets react 是参数,等同于

{
  "presets": ["react"]
}

执行正常。

node 命令行写代码

注意: 本文所有代码示例,均在 node 版本 4.8.4 下执行。

写个解构赋值的,直接运行 node,不支持。

运行 node_modules/.bin/babel-node --presets env

得到 a 的 value 是 1。

通过栗子基本已经介绍了 babel-node 的用法了,就是方便我们平常开发时候,写一些脚本的。所以它不适用于生产环境。另外,babel-node 已经内置了 polyfill,并依赖 babel-register 来编译脚本。好,那 babel-register 是什么呢

babel-register
npm install babel-register --save-dev

babel-node 可以通过它编译代码,可以了解到,它其实就是一个编译器。我们同样可以在代码中引入它 require("babel-register"),并通过 node 执行我们的代码。

它的原理是通过改写 node 本身的 require,添加钩子,然后在 require 其他模块的时候,就会触发 babel 编译。也就是你引入require("babel-register")的文件代码,是不会被编译的。只有通过 require 引入的其他代码才会。我们是不是可以理解,babel-node 就是在内存中写入一个临时文件,在顶部引入 babel-register,然后再引入我们的脚本或者代码?

举个栗子,还是 node 中执行 jsx,要通过 babel 编译。我们可以把 jsx 的代码 a.js 编译完输出到一个 b.js,然后 node b.js 也是可以执行的。但是太麻烦,不利于开发。让我们看一下通过 register 怎么用:

// register.js 引入 babel-register,并配置。然后引入要执行代码的入口文件
require("babel-register")({ presets: ["react"] });
require("./test")
// test.js 这个文件是 jsx...
const React = require("react");
const elements = [1, 2, 3].map((item) => {
  return (
    
{item}
) }); console.log(elements);
// 执行
$ node register.js

它的特点就是实时编译,不需要输出文件,执行的时候再去编译。所以它很适用于开发。总结一下就是,多用在 node 跑程序,做实时编译用的,通常会结合其他插件作编译器使用,比如 mocha 做测试的时候。

值得一提的是,babel-register 这个包之前是在 babel-core 下面的,所以也可以 require("babel-core/register") 去引入,跟require("babel-register")是一样的。但是,babel 的团队把 register 独立出来了,而且未来的某一天(升 7.0)会从 babel-core 中废除,所以我们现在最好还是使用 babel-register 吧。babel-core/register.js

babel-runtime
npm install babel-runtime --save

这个包很简单,就是引用了 core-js 和 regenerator,然后生产环境把它们编译到 dist 目录下,做了映射,供使用。那么什么是 core-js 和 regenerator 呢。
首先我们要知道上面提到的 babel-core 是对语法进行 transform 的,但是它不支持 build-ints(Eg: promise,Set,Map),prototype function(Eg: array.reduce,string.trim),class static function (Eg:Array.form,Object.assgin),regenerator (Eg:generator,async)等等拓展的编译。所以才要用到 core-js 和 regenerator。

core-js

core-js 是用于 JavaScript 的组合式标准化库,它包含 es5 (e.g: object.freeze), es6的 promise,symbols, collections, iterators, typed arrays, es7+提案等等的 polyfills 实现。也就是说,它几乎包含了所有 JavaScript 最新标准的垫片。不过为什么它不把 generator 也实现了...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91786.html

相关文章

  • Babel 配置工程师应知应会

    摘要:,标题党了,本文仅介绍相关生态和一些配置心得。函数是在时候常用的工具函数,对编译模块时,会将用到的放到模块顶部。用来看最终引入了哪些必须配合,貌似加入了此项以后,会得到类似于的效果。 Babel Sorry,标题党了,本文仅介绍 Babel 相关生态和一些配置心得。 Babel 各个 package 的用途 babel-core: 核心部分 babel-cli: 允许使用命令行 ...

    caikeal 评论0 收藏0
  • 库,组件,框架 - 收藏集 - 掘金

    摘要:哈哈,我理解,架构就是骨架,如下图所示译年月个有趣的和库前端掘金我们创办的使命是让你及时的了解开发中最新最酷的趋势。 翻译 | 上手 Webpack ? 这篇就够了! - 掘金译者:小 boy (沪江前端开发工程师) 本文原创,转载请注明作者及出处。 原文地址:https://www.smashingmagazine.... JavaSrip... 读 Zepto 源码之代码结构 - ...

    tommego 评论0 收藏0
  • 关于c++的namespace,真的了解真的会用

    摘要:据我了解,很多学校在学习的时候,老师会让学生死记一条语句,那就是那么你真的了解它吗命名空间是一个命名空间。如果我们真的想使用的话,的命名空间遍给了我们解决方法使用命名空间。 据我了解,很多学校在学习c++的时候,老师会让学生死记一条语句,那就是 using namespace std; 那么...

    Lionad-Morotar 评论0 收藏0
  • 2019前端工程师自检清单与思考

    摘要:前端工程师自检清单对于,掌握其语法和特性是最基本的,但是这些只是应用能力,最终仍旧考量仍然是计算机体系的理论知识,所以数据结构,算法,软件工程,设计模式等基础知识对前端工程师同样重要,这些知识的理解程度,可以决定你在前端工程师这条路上能走多 2019前端工程师自检清单 对于JavaScript,掌握其语法和特性是最基本的,但是这些只是应用能力,最终仍旧考量仍然是计算机体系的理论知识,所...

    Honwhy 评论0 收藏0
  • 真的会用Drawable

    摘要:究其原因可能是真的是封装得太好了,以至于基本不用关心它的实现。上面已经封装好了很多,比如,,等等,真的不用关心里面实现就能完成大部分开发。这是一种减少过度绘制,提高页面帧率的非常有效而且简单的方式。比如是对的封装,最终起作用的其实是后者。 Drawable在android当中非常常见,每天都会和它打交道,但很多人却很少知道Drawable有哪些常用的方法,甚至有时候在面试的时候问起也是...

    chavesgu 评论0 收藏0

发表评论

0条评论

mochixuan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<