程序员

浅谈Babel

2018-09-27  本文已影响3人  snow_in

前几天遇到一个用户反馈说页面打不开的问题,而且还是其中两个页面,其他的都没有问题,于是就要来了账号自己登陆一下看看是哪里报错。奇怪的是我们登陆都好好的啊~~ 这时候用户发来了报错信息:


babel0.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:


babel1.png

目录就是这样的,我们在package.json的scriptes中添加一条命令,用来转译我们的文件。

如果我们什么都没有配置,Babel并不会起作用,而是会原样输出代码。现在,我们在没有配置Babel的情况下执行命令看一下输出
原文件:


babel2.png

转译之后:


babel3.png
我们发现前后并没有变化
要想Babel起作用,就得告诉他要做什么。自然,我们就得要配置插件啦。

babel转译器

  1. plugins
    用来转译单一功能的插件,像是transform-es2015-classes,就只转译class类。且如果插件以babel-plugin-开头,则可以省略该前缀。
{
  "plugins": [
    "myPlugin", // 等价于
    "babel-plugin-myPlugin"
  ]
}
  1. presets
    转译器,一组插件的集合。人都是有惰性的,让我们一个个地配置plugin岂不是很烦,presets就是帮我们解决这个烦恼的。babel提供了如下的一些preset:

es20xx的preset只转译该年份批准的标准,而env则代指最新的标准,包括了latest和es20xx各年份

了解了plugins和presets之后,我们就来配置一下Babel吧。我们的例子是用了es6的class类,转译class类的插件就是transform-es2015-classes


babel5.png

现在再执行一下命令:


babel6.jpg
可以看到代码已经被编译了。
如果我们又用到了箭头函数,就要在Babel配置的plugins里面再添加transform-es2015-arrow-functions插件。一个一个配置太繁琐,这时候presets就登场了。
babel7.png

执行命令之后:


babel8.png

可以看到不论是class还是箭头函数都被转译了。

我们看上面转译class的代码,是定义了两个函数_createClass和_classCallCheck,那如果我们在多个文件中都用到了class,岂不是要定义很多遍?现在我们在index.js文件里面也定义一个class,执行命令看一下结果:


image.png

果然跟我们想的一样,那这样不是产生了很多冗余吗??不用担心,我们还有transform-runtime


babel9.png
再执行命令:
babel10.png

可以看到是从babel-runtime引入辅助函数,而不是定义了,这就避免了冗余代码。

babel-runtime是把我们开发中依赖的全局内置函数等提取到公共模块中,在转译代码的时候通过导入模块引入,避免了污染全局作用域。为什么说可以避免污染全局作用域呢?假如我们全局引入了babel-polyfill,我们在项目中由于某种原因自定义了Array.from()方法,那么babel-polyfill中的Array.from()方法就跟我们自定义的产生了冲突。babel-runtime就没有这个问题。

babel-plugin-transform-runtime 插件做了如下事情:

可以通过配置来控制开关

{
  "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'

就可以正常工作了。

上一篇 下一篇

猜你喜欢

热点阅读