前几天遇到一个用户反馈说页面打不开的问题,而且还是其中两个页面,其他的都没有问题,于是就要来了账号自己登陆一下看看是哪里报错。奇怪的是我们登陆都好好的啊~~ 这时候用户发来了报错信息:
![](https://img.haomeiwen.com/i5262488/504cd24b21cbec0c.png)
一想这应该是浏览器兼容问题了,不识别es新的API,于是下载了低版本的Chrome浏览器打开果然报错。
简介
我们知道babel是转译es的,究竟babel哪里没配置对呢?让我们来捋一捋babel
Babel is a JavaScript compiler。这是Babel官网上的简单介绍,就是“Babel是一个JavaScript转译器”,这里有的翻译为编译器,有的翻译为转译器,我觉得转译器比较贴切,因为经过Babel转译后还是JS语言。
我们知道,JS的发展非常迅速,新的语法/特性等层出不穷。但是浏览器的发展速度跟不上JS的发展,新的特性不能及时普及,在得到广泛普及之前,Babel能够让我们提前使用它们。它可以把 ECMAScript 2015+ 代码转换为向后兼容版本的 JavaScript 代码。不过Babel只转译新的语法,JS新增的API和全局对象并不支持。
我们写个简单的例子直观的看一下Babel:
![](https://img.haomeiwen.com/i5262488/e9fa6df7fb17c44a.png)
目录就是这样的,我们在package.json的scriptes中添加一条命令,用来转译我们的文件。
如果我们什么都没有配置,Babel并不会起作用,而是会原样输出代码。现在,我们在没有配置Babel的情况下执行命令看一下输出
原文件:
![](https://img.haomeiwen.com/i5262488/530a324f3ccf205b.png)
转译之后:
![](https://img.haomeiwen.com/i5262488/dc27285404372de7.png)
我们发现前后并没有变化
要想Babel起作用,就得告诉他要做什么。自然,我们就得要配置插件啦。
babel转译器
- plugins
用来转译单一功能的插件,像是transform-es2015-classes,就只转译class类。且如果插件以babel-plugin-开头,则可以省略该前缀。
{
"plugins": [
"myPlugin", // 等价于
"babel-plugin-myPlugin"
]
}
- presets
转译器,一组插件的集合。人都是有惰性的,让我们一个个地配置plugin岂不是很烦,presets就是帮我们解决这个烦恼的。babel提供了如下的一些preset:
- es2015
- es2016
- es2017
- env
es20xx的preset只转译该年份批准的标准,而env则代指最新的标准,包括了latest和es20xx各年份
了解了plugins和presets之后,我们就来配置一下Babel吧。我们的例子是用了es6的class类,转译class类的插件就是transform-es2015-classes
![](https://img.haomeiwen.com/i5262488/ffded062846bc4c6.png)
现在再执行一下命令:
![](https://img.haomeiwen.com/i5262488/13f6bbcc892cf410.jpg)
可以看到代码已经被编译了。
如果我们又用到了箭头函数,就要在Babel配置的plugins里面再添加transform-es2015-arrow-functions插件。一个一个配置太繁琐,这时候presets就登场了。
![](https://img.haomeiwen.com/i5262488/e441db5a0afc41fa.png)
执行命令之后:
![](https://img.haomeiwen.com/i5262488/1d2a5a7597744b16.png)
可以看到不论是class还是箭头函数都被转译了。
我们看上面转译class的代码,是定义了两个函数_createClass和_classCallCheck,那如果我们在多个文件中都用到了class,岂不是要定义很多遍?现在我们在index.js文件里面也定义一个class,执行命令看一下结果:
![](https://img.haomeiwen.com/i5262488/b19e6ea39b6112e6.png)
果然跟我们想的一样,那这样不是产生了很多冗余吗??不用担心,我们还有transform-runtime
![](https://img.haomeiwen.com/i5262488/0f93f968a5649465.png)
再执行命令:
![](https://img.haomeiwen.com/i5262488/1e51ae35840a19f2.png)
可以看到是从babel-runtime引入辅助函数,而不是定义了,这就避免了冗余代码。
babel-runtime是把我们开发中依赖的全局内置函数等提取到公共模块中,在转译代码的时候通过导入模块引入,避免了污染全局作用域。为什么说可以避免污染全局作用域呢?假如我们全局引入了babel-polyfill,我们在项目中由于某种原因自定义了Array.from()方法,那么babel-polyfill中的Array.from()方法就跟我们自定义的产生了冲突。babel-runtime就没有这个问题。
babel-plugin-transform-runtime 插件做了如下事情:
- core-js:自动导入babel-runtime/core-js,并将全局静态方法、全局内置对象等映射到对应的模块。
- helper:将内联的工具函数移除,改成通过babel-runtime/helpers模块进行导入,比如_classCallCheck工具函数。
- regenerator:使用 async/generator 函数时自动导入 babel-runtime/regenerator模块。
可以通过配置来控制开关
{
"plugins": [
["transform-runtime", {
"corejs": false,
"helpers": true,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}
有了transform-runtime怎么还需要babel-polyfill呢?看看官方怎么说的:
NOTE: Instance methods such as "foobar".includes("foo") will not work since that would require modification of existing built-ins (Use babel-polyfill for that).
因为transform-runtime不污染全局变量,所以实例方法无法使用,还得引入babel-polyfill,这就是文章开头说的为什么报错的原因。我们在项目的入口文件加上
import 'babel-polyfill'
就可以正常工作了。
网友评论