前言
前端发展到现在, 可谓是混乱至极, 已经远远超出我对前端所谓一把 jQuery 抄起来就是怼,
webpack, babel, node.js, react, vue 各种工程框架, 构建工具你不会点好像都不算是个合格的
前端工程师, 语法相关的 ES6/7 总是绕不过 Babel, 这篇文章就是直接讨论 Babel.
本文只要围绕以下几块来说:
Babel 编译过程介绍
Babel 插件及预设
Babel-register 在项目中的使用
babel 的 polyfill 引入机制
babel 在前端工程的定位
Babel 编译过程介绍
核心包
- // 暴露 babel.transform 方法来编译 source code
- babel-core
- // 语法字符串解析 parser
- babylon
- // 结合 plugins 遍历 AST 语法树
- babel-traverse
- // 生成最后的编译字符串
- babel-generator
babel 编译流程
- input string
- -> babylon parser
- -> AST
- -> babel-traverse // 使用 plugins 遍历 AST 语法树
- -> AST
- -> babel-generator
- -> output string
Babel 是一个 JavaScrpit 的编译器, 从宏观的角度来看, 它有三个运行阶段: 解析, 转化, 生成. 基本上如果不设置配置文件. babelrc,Babel 运行的结果便是 const babel = code => code , 通过读取代码, 最后生成一样的代码. Babel 的最核心的概念便是插件, 通过在配置文件 .babelrc 中添加不同的插件基本可以做所有的事情.
Babel 插件 (plugins) 及预设(presets)
首先聊聊插件与预设的关系, 官方预设便是由官方评审维护的一系列插件组合. 插件与预设的关系便是父子集合的关系.
每年 babel 都会评估当年的插件, babel-preset-env 取代了 es2015, es2016, es2017 以及最新的代码
- http://babeljs.io/docs/plugins/preset-env/
- http://babeljs.io/docs/plugins/preset-react/
- http://babeljs.io/docs/plugins/preset-flow/
Babel-register 在项目中的使用
babel-register 的设计思想非常厉害, 简单的来说就是 require hook. 也是 babel 常见的一种使用方法.
这种方法只需要引入文件就可以运行 Babel, 或许能更好地融入你的项目设置.
让我们先在项目中创建 index.js 文件
- // index.js
- console.log("hello world");
接着需要我们安装 babel-register
$ npm install i -D babel-register
接着, 在项目中创建 register.js 文件并添加如下代码:
- require("babel-register");
- require("./index.js");
然后我们只需要启动 node register.js 便可, 通过修改 require function, 对所有的通过 require 引入的代码先经过 babel 编译一遍, 再给到 runtime 执行.
babel 的 polyfill 引入机制
Babel 几乎可以编译所有时新的 JavaScript 语法, 但对于 APIs 来说却并非如此.
比方说, 下列含有箭头函数的需要编译的代码:
- function addAll() {
- return Array.from(arguments).reduce((a, b) => a + b);
- }
最终会变成这样
- function addAll() {
- return Array.from(arguments).reduce(function(a, b) {
- return a + b;
- });
- }
然而, 它依然无法随处可用因为不是所有的 JavaScript 环境都支持 Array.from.
为了解决这个问题, 我们使用一种叫做 Polyfill(代码填充, 也可译作兼容性补丁) https://remysharp.com/2010/10/08/what-is-a-polyfill 的技术. 简单地说, polyfill 即是在当前运行环境中用来复制 (意指模拟性的复制, 而不是拷贝) 尚不存在的原生 api 的代码. 能让你提前使用还不可用的 APIs,Array.from 就是一个例子.
要使用 Babel polyfill, 首先用 npm 安装它:
$ npm install --save babel-polyfill
然后只需要在文件顶部导入 polyfill 就可以了:
import "babel-polyfill";
所以我的个人建议是按需引入 core-js 的模块而不是整个 babel-polyfill bundle, 来对 ES6/7 新增的数据对象和方法做 polyfill.
babel-runtime 引入机制
为了实现 ECMAScript 规范的细节, Babel 会使用 "助手" 方法来保持生成代码的整洁.
由于这些助手方法可能会特别长并且会被添加到每一个文件的顶部, 因此你可以把它们统一移动到一个单一的 "运行时(runtime)" 中去.
通过安装
babel-plugin-transform-runtime
和 babel-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 总结
babel 的出现让开发者可以自由的采用 ES6/7 的语法来编写 JS 项目, 极大的丰富了开发 (browser, node) 层面的 JS 语言特性.
babel 的 AST parser,polyfill, register 一起完成了 babel 体系对 JS 的完备解决方案.
参考资料
babel 知识体系漫游 https://zhuanlan.zhihu.com/p/24648188
- babel handbook https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/user-handbook.md
- babel docs http://babeljs.io/docs/core-packages/
来源: https://juejin.im/post/5afc141e51882542836e36cf