babel
# babel
参考地址-babel 插件手册:https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md (opens new window)
把同种的高版本规则翻译成低版本规则,输出的是另一种更低级的语言代码。
Babel 是 JavaScript 编译器,更确切地说是源码到源码的编译器,通常也叫做“转换编译器(transpiler)”。 意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。
# babel 编译过程
- 解析(PARSE):将代码字符串解析成抽象语法树。
解析步骤接收代码并输出 AST。 这个步骤分为两个阶段:词法分析(Lexical Analysis) 和 语法分析(Syntactic Analysis)。
(1)词法分析阶段把字符串形式的代码转换为 令牌(tokens) 流。
代码 => 字符串 => 词法分析是分词, 对字符串进行分割,对关键词进行分类。
这个过程会将由字符组成的字符串分解成有意义的代码块,这些代码块统称为词法单元(token)
(2)语法分析阶段会把一个令牌流转换成 AST 的形式。 这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。
- 转换(TRANSFORM):对抽象语法树进行转换操作。
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程 同时也是插件将要介入工作的部分
转换阶段: 例如 const 会转换成 var, 箭头函数会转换成 function () { return ... }
- 生成(GENERATE): 根据变换后的抽象语法树再生成代码字符串。
代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)。.
代码生成其实很简单:深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串。
# babel.config.js 和.babelrc
Babel 有两种并行的配置文件格式,可以一起使用,也可以分开使用。
- 项目范围的配置
babel.config.js 文件,具有不同的拓展名(json、js、html) babel.config.js 是按照 commonjs 导出对象,可以写 js 的逻辑。
- 相对文件的配置
.babelrc 文件,具有不同的拓展名
baberc 的加载规则是按目录加载的,是只针对自己的代码。config 的配置针对了第三方的组件和自己的代码内容。babel.config.js 是一个项目级别的配置,一般有了 babel.config.js 就不会在去执行.babelrc 的设置。
# babel 作用
# babel 插件和预设
# babel 两种插件
- 语法插件
语法插件作用于 @babel/parser
,负责将代码解析为抽象语法树(AST)
- 转换插件
转换插件作用于 @babel/core
,负责转换 AST 的形态(官方的转换插件以 babel-plugin-transform(正式)或 babel-plugin-proposal(提案)开头)
# 预设的插件集(presets)
预设的插件集,以 JS 标准为例,babel 提供了如下的一些 preset:
es2015
es2016
es2017
env: 代指最新的标准,包括了 latest 和 es20xx 各年份
stage-0 到 stage-4 的标准成形之前的各个阶段,都是实验版的 preset,建议不使用。
# 执行顺序
插件和预设都是通过数组的形式在配置文件中配置,如果插件和预设都要处理同一个代码片段,那么会根据一下执行规则来判定:
插件比预设先执行
插件执行顺序是插件数组从前向后执行
预设执行顺序是预设数组从后向前执行
# plugins
应用于 babel 转译的 transforming 阶段,如果该阶段不使用插件,babel 会原样输出代码。
主要关注 transfoming 阶段使用的插件,因为 transform 插件会自动使用对应的词法插件,所以 parsing 阶段的插件不需要再配置。
# polyfill
polyfill 是一段代码(或者插件),提供了那些开发者们希望浏览器原生提供支持的功能。程序库先检查浏览器是否支持某个 API,如果不支持则加载对应的 polyfill。主要特征:
是一个浏览器 API 的 Shim;
与浏览器有关;
没有提供新的 API,只是在 API 中实现缺少的功能;
以只需要引入 polyfill ,它会静静地工作;
# babel-polyfill
针对 es2015+ 环境的 shim
实现:把 core-js 和 regenerator runtime 包装
使用 babel-polyfill 会把 es2015+ 环境整体引入到代码环境中,代码可以直接使用新标准所引入的新原生对象,新 API 等,一般来说单独的应用和页面都可以这样使用
# Shim
Shim 指的是在一个旧的环境中模拟出一个新 API ,而且仅靠旧环境中已有的手段实现,以便所有的浏览器具有相同的行为。主要特征:
该 API 存在于现代浏览器中;
浏览器有各自的 API 或 可通过别的 API 实现;
API 的所有方法都被重新实现;
拦截 API 调用,并提供自己的实现;
是一个优雅降级。
shim 的概念要比 polyfill 更大一些,可以将 polyfill 理解为专门兼容浏览器 API 的 shim 。简单的说,如果浏览器 X 支持标准规定的功能,那么 polyfill 可以让浏览器 Y 的行为与浏览器 X 一样。
# shim 和 polyfill 有什么区别
一个 shim 是一个库,它将一个新的 API 引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现
一个 polyfill 就是一个用在浏览器 API 上的 shim.我们通常的做法是先检查当前浏览器是否支持某个 API, 如果不支持的话就加载对应的 polyfill.然后新旧浏览器就都可以使用这个 API 了.
参考:Babel 插件手册 (opens new window) Babel 用户手册 (opens new window)