Babel知识点

本文深入探讨Babel编译器的三个核心阶段:解析、转换和生成,以及如何使用插件和预设来处理现代JavaScript语法。了解Babel如何通过插件系统支持新特性,如模板字符串和ES模块转换,以及如何利用babel-polyfill和babel-plugin-transform-runtime确保代码在不同环境中兼容。
摘要由CSDN通过智能技术生成
不会很详细说明每个东西该怎么用,大概介绍Babel这个大家族的一些常见知识点

Babel编译三个阶段:
1、解析
2、转换
3、生成

Babel自6.0开始就只负责解析和生成了,转换代码需要插件完成

"plugins": [ "transform-es2015-template-literals" 
// 转译模版字符串的 plugins 

利用这个插件做模板字符串的转换

先执行plugins再执行presets

plugins从左到右执行
presets从右到左执行

Babel常见plugin简介

babel-core 伴随着babel-loader使用而安装
babel-preset-env 使用最新JavaScript自动帮你转换成ES5
babel-polyfill Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。

Babel 包

babel-core

提供一个ES2015环境,把ES6代码构建成一个AST,提供给后续的插件处理。

babel-cli

用于在命令行编译指定文件
安装:

npm install --save-dev @babel/core @babel/cli

使用方法:
1、编译文件

npm babel index.js 

①指定输出文件名

npm babel index.js --out-file index.compiler.js

②指定输出目录

npm babel src --out-dir dist

2、忽略文件

npm babel src --out-dir lib --ignore "src/**/*.spec.js","src/**/*.test.js"

3、使用插件/预设

//plugin
npm babel index.js --out-file index.compiler.js --plugin=@babel/proposal-class-properties,@babel/transform-modules-amd

//preset
npm babel index.js --out-file index.compiler.js --presets=es2015,react

babel-node

babel-node是babel-cli下的命令,主要实现node脚本执行能力。另外,babel-node 已经内置了 polyfill,并依赖 babel-register 来编译脚本。

babel-register

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 (
    <div>{item}</div>
  )
});
console.log(elements);

Babel plugin

要说 plugins 就不得不提 babel 编译的过程。babel 编译分为三步:
parser:通过 babylon 解析成 AST。
transform[s]:All the plugins/presets ,进一步的做语法等自定义的转译,仍然是 AST。
generator: 最后通过 babel-generator 生成 output string。
所以 plugins 是在第二步加强转译的,所以假如我们自己写个 plugin,应该就是对 ast 结构做一个遍历,操作。

babel-plugin-transform-runtime

transform-runtime 是为了方便使用 babel-runtime 的,它会分析我们的 ast 中,是否有引用 babel-rumtime 中的垫片(通过映射关系),如果有,就会在当前模块顶部插入我们需要的垫片。试一下:
npm install babel-plugin-transform-runtime

// 编译前
console.log(Object.values({ 1: 2 }));
node_modules/.bin/babel --plugins transform-runtime values.js
// 编译后
'use strict';

var _values = require('babel-runtime/core-js/object/values');

var _values2 = _interopRequireDefault(_values);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

onsole.log((0, _values2.default)({ 1: 2 }));

transform-runtime 对比 babel-polyfill

babel-polyfill 是当前环境注入这些 es6+ 标准的垫片,好处是引用一次,不再担心兼容,而且它就是全局下的包,代码的任何地方都可以使用。缺点也很明显,它可能会污染原生的一些方法而把原生的方法重写。如果当前项目已经有一个 polyfill 的包了,那你只能保留其一。而且一次性引入这么一个包,会大大增加体积。如果你只是用几个特性,就没必要了,如果你是开发较大的应用,而且会频繁使用新特性并考虑兼容,那就直接引入吧。
transform-runtime 是利用 plugin 自动识别并替换代码中的新特性,你不需要再引入,只需要装好 babel-runtime 和 配好 plugin 就可以了。好处是按需替换,检测到你需要哪个,就引入哪个 polyfill,如果只用了一部分,打包完的文件体积对比 babel-polyfill 会小很多。而且 transform-runtime 不会污染原生的对象,方法,也不会对其他 polyfill 产生影响。所以 transform-runtime 的方式更适合开发工具包,库,一方面是体积够小,另一方面是用户(开发者)不会因为引用了我们的工具,包而污染了全局的原生方法,产生副作用,还是应该留给用户自己去选择。缺点是随着应用的增大,相同的 polyfill 每个模块都要做重复的工作(检测,替换),虽然 polyfill 只是引用,编译效率不够高效。

总的来说:
babel-polyfill会把所有垫片载入,并注册到全局变量,会污染全局变量
transform-runtime则会检测代码,按需加载polyfill,并且不是全局注册的。

Babel预设

Babel-preset

各种配置 plugin 实在是费劲,es6+ 编译要加入好多 plugins,比如为了在 node 中使用 esmodule,要把 esmodule 转化成 commomjs,使用 transform-es2015-modules-commonjs,还有 asyncToGenerator,React jsx转化等等,不仅要装好多,还要配好多。
presets 就是 plugins 的组合,你也可以理解为是套餐… 主要有

  • env

  • es2015

  • react

  • lastet

  • stage-x 具体的语法属于哪个 stage 可参照tc39

大部分的 presets 我觉得都不需要介绍了,官网上写的比较详细。而且 babel-preset-lastet(包括 es2105,es2016,es2017)跟默认情况下的 env 是一样的,也就是说包括 lastest 在内,这四个 presets 都要被 babel-preset-env 代替。即:

{ "presets": ["latest"] } === { "presets": ["env"] }

babel-preset-env

原理:
它能根据当前的运行环境,自动确定你需要的 plugins 和 polyfills。通过各个 es标准 feature 在不同浏览器以及 node 版本的支持情况,再去维护一个 feature 跟 plugins 之间的映射关系,最终确定需要的 plugins。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值