你需要掌握的babel知识都在这里
Posted QIANDXX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你需要掌握的babel知识都在这里相关的知识,希望对你有一定的参考价值。
随着ES6以及后面版本的问世,确实给前端javascript增添了不少活力,层出不穷的高级语法不仅提升编码效率,还使得前端的编码风格越来越靠近贴近主流。然而这些高级语法在有些浏览器上却运行不了,是因为浏览器还没法编译js的高级语法导致出现兼容性问题,需要将这些高级语法编译成浏览器能够运行的低版本语法。今天讲解的babel就是来解决这个js兼容问题的。
Babel,又名Babel.js。 是一个用于web 开发,且自由开源的JavaScript 编译器、转译器。 Babel 使软件开发者能够以偏好的编程语言或风格来写作源代码,并将其利用Babel 翻译成JavaScript。 Babel 是一个常用来使用最新的JavaScript 语言特性的工具。——维基百科
前置知识
babel编译流程
babel其实就是将源码转换成目标源码的一个过程,大致分为三步
- parse: 通过parser把源码转成抽象ast语法树
- transform: 循环遍历ast,通过transform的能力对其进行语法转换
- generate: 根据转换后的源码生产目标源码
主要依赖库介绍
@babel-core:babel核心编译库,它能够进行语法、语义、词法分析,生成抽象语法树
@babel-cli:负责命令相关的功能,提供 bebel 命令
@babel/preset-env:ES6稳定语法transform插件的集合
@babel/runtime: 运行时,配合transform-runtime
@babel/plugin-transform-runtime:polyfill垫片防止污染全局变量(第三方库必须得接入)
@babel/polyfill:高级语法兼容解决方案依赖
学习babel,你主要掌握一下三个模块就差不多了:
- 1、环境搭建,基本配置
- 2、babel-polyfill
- 3、babel-runtime
基本配置
搭建一个简单的项目
┌-- src
┆ └--index.js
├-- .babelrc
└-- package.json
配置scripts命令
# package.json
...
"scripts":
"babel": "babel src/index.js --out-dir dist"
,
...
安装
开发依赖
yarn add @babel/cli @babel/core @babel/plugin-transform-runtime @babel/preset-env -D
生产依赖
yarn add @babel/polyfill @babel/runtime -S
配置.babelrc
"presets": [
[
"@babel/preset-env"
]
],
"plugins": []
到这里一个最基础版本的babel就配置好了,运行看看
src/index.js
const sum = (a, b) => a + b;
输出
dist/index.js
"use strict";
var sum = function sum(a, b)
return a + b;
;
证明babel已经可以将箭头函数转换为 function
函数了,大功告成!先别高兴太早,插播一段解释。。。。。。。
1、解释一下@babel/preset-env
这个是ES6稳定语法编译插件的集合,什么意思?就是除掉一小部分高级语法(无法用js完整表示)以外的ES6语法转换成低版本js的插件的集合。
举例:如果不用预设,上面src/inex.js
中的箭头函数得单独安装@babel/plugin-transform-arrow-functions
插件来完成转译"presets": [], "plugins": ["@babel/plugin-transform-arrow-functions"], //"targets": "last 2 Chrome versions"
也是可以正常转译箭头函数,也就是说在babel中一种语法就得需要对应一个插件来转译,这里所说的@babel/preset-env预设就是很多稳定语法转译成低版本js插件的集合,目的是方便使用,减少配置成本。
2、这里再补充一下几个官方的预设
@babel/preset-react
:用来编译jsx语法
@babel/preset-typescript
:用来将ts文件转成js文件
@babel/preset-flow
:用来将使用flow类型约束的文件转成js文件
3、既然babel是将高级语法转成低版本语法来做兼容处理,那到底要转到多低的版本呢???
@babel/preset-env会根据配置文件中的targets
属性来生成插件列表后编译,在浏览器或electron中,官方还是推荐用.browserslistrc
来配置目标环境。如果babel配置文件没有设置targets
或ignoreBrowserslistConfig
,@babel/preset-env会使用默认的browserslist配置源(**> 0.5%, last 2 versions, Firefox ESR, not dead**
)
好了,来继续,来试试promise
高级语法转译情况
src/index.js
const sum = (a, b) => a + b;
// 新的 API
Promise.resolve(100).then((data) => data);
编译后输出
"use strict";
var sum = function sum(a, b)
return a + b;
; // 新的 API
Promise.resolve(100).then(function (data)
return data;
);
发现Promsie
根本就没有转译,也就是说@babel/preset-env
预设没法转译promsie,怎么解决???
引入下一个知识点,@babel/polyfill
,简称 “垫片”,说白了就是用这个来抹平部分高级语法的兼容问题
@babel/polyfill 垫片
@babel/polyfill
其实是一个空壳,他当中包含 core-js
和 regenerate
,真正起作用的是这两个依赖包
使用
在入口文件的顶部引入
import "@babel/polyfill";
执行编译,输出,都正常了
但是@babel/polyfill
89.4kb完全引入了,而这里只需要promsie对应的垫片就OK了,造成编译出来的文件内存很大,又是一个头疼的问题来了!!!
官方出了解决方案,Babel@7.4.0
版本之前,还是得用上面这种全量引入的方式,之后,可以分开引入
import "core-js/stable";
import "regenerator-runtime/runtime";
这也差不多,没多大效果,那有没有一种自动按需引入
的解决方案呢?
要说还得看官方,这不方案就来了吗
"presets": [
[
"@babel/preset-env",
"useBuiltIns": "usage",
"corejs": "3"
]
]
配置完后,编译,输出
"use strict";
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.promise.js");
var sum = function sum(a, b)
return a + b;
; // 新的 API
Promise.resolve(100).then(function (data)
return data;
);
完美解决!!!
到这里,如果自己的业务项目配置到此就结束了
如果是开发第三方依赖包,还得继续往下看
@babel/plugin-transform-runtime
咱们不解释为啥,先看使用了@babel/plugin-transform-runtime
插件和没使用输出的代码。
src/index.js
class Test
未使用的输出情况
"use strict";
require("core-js/modules/es.object.define-property.js");
function _defineProperties(target, props) for (var i = 0; i < props.length; i++) var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor);
function _createClass(Constructor, protoProps, staticProps) if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", writable: false ); return Constructor;
function _classCallCheck(instance, Constructor) if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
var Test = /*#__PURE__*/_createClass(function Test()
_classCallCheck(this, Test);
);
使用后的输出情况
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var Test = /*#__PURE__*/(0, _createClass2["default"])(function Test()
(0, _classCallCheck2["default"])(this, Test);
);
从两段输出代码可以看出,后一种是用变量来储存插件的方法,而且是采用抽离公共代码的helper
文件导出方法的形式,而前一种则是把方法直接编译到了文件内,试想一下会出什么问题?
如果一个项目有多个地方用到了class类,转译时每个文件都要多出这段代码,造成严重的代码冗余
,还有一点,直接将方法编译到文件会污染文件的全局环境
,尤其是作为第三方类库提供给别人使用时,很可能被覆盖掉,应该避免不必要的冲突
@babel/runtime 和 @babel/plugin-transform-runtime
这两个插件要配合使用,得同时安装
"presets": [
[
"@babel/preset-env",
"useBuiltIns": "usage",
"corejs": 3
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
]
]
结论:开发类库用polyfill + runtime
,公司业务项目用polyfill
就行了
完结
以上是关于你需要掌握的babel知识都在这里的主要内容,如果未能解决你的问题,请参考以下文章
寒冬也挡不住进大厂的决心,Android面试知识架构,面试需要掌握的都在这里!