资讯专栏INFORMATION COLUMN

一天快速了解Babel

qiangdada / 1507人阅读

摘要:在做项目中一直使用的是脚手架搭建的环境,一直没有仔细的去了解这一工具,这周末抽出一天时间通过官网还有各种博客文章算是了解了一些内容,起码可以在项目中自己完成的配置了。不过好像目前浏览器端对这种诸如之类的方法支持的还不错了。

在做项目中一直使用的是脚手架搭建的环境,一直没有仔细的去了解 babel 这一工具,这周末抽出一天时间通过官网还有各种博客文章算是了解了一些内容,起码可以在项目中自己完成 .babelrc 的配置了。

这篇文章就是把自己的理解和找到的优秀文章的内容做一融合和整理,理解有误的地方还请大家批评指正~

因为主要是面对项目,所以本文内容主要还是围绕 .babelrc 展开,与babel 相关的其他工具无关。

Babel 是什么?
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in old browsers or environments.

由于浏览器对 ECMAScript 的支持各有差异,因此 Babel 是一个用来将 ES6 版本以上代码转为 ES5 版本代码的工具,从而使得编写的代码可以在指定的环境下运行。

.babelrc 配置文件

在项目中我们使用 Babel 做转码一般使用配置文件的形式。Babel 的配置文件名为 .babelrc 并且通常放在项目根路径下,其格式大致如下:

{
  "env": {
    "production": {
      "presets": [],    // 转码规则
      "plugins": [],    // 插件
      "ignore": ["node_modules/"]    // 转码时候忽略的文件
    }
  }
}

这里的 env 的值取得是项目中的 process.env.BABEL_ENV 如果该值找不到,则取 process.env.NODE_ENV 最后如果该值还找不到,则设为 development

处理顺序

plugins 优先于 presets

plugins 从数组第一个到最后一个进行编译

presets 从数组最后一个到第一个进行编译 ,这个目的主要为了向后降级

presets

presets 用于设置转码的规则,常用的 presetsenvstage-x

关于 env 后文会提到,先来看看 stage-x

stage-x  是新特性纳入标准所经过的几个阶段,x 值越小,表示阶段越靠后,靠后的阶段包含前面的所有内容,即 stage-0 包含 stage-1/2/3  的所有内容

上图是 stage-2index.js 文件,可以看到其中直接引用了 stage-3 的所有特性。

实际上来说,presets 就是 plugins 的集合,如果没有 preset 也是可以完成代码转换工作的,如下。

{
  "plugins": [
    "check-es2015-constants",
    "es2015-arrow-functions"
  ]
}

但是由于这么配置过于繁琐,因此 Babel 把一些属于同一标准的 transform-plugins 划归到一个 presets 中,这样有了 presets 就不用再一个一个地导入 transform-plugins 了。

babel-polyfill & babel-runtime

Babel 默认只转换 JS 语法,而不转换新的 API ,新标准中的全局对象和定义在这些全局对象上的方法都不会转码,这些 API 很多,具体参考 definitions.js

这就导致了 babel-polyfillbabel-runtime 的产生

babel-polyfill

把所有的 polyfill 一次性全部引入,不管你在项目中是否真正用到

污染全局对象,可能引发冲突。如果你开发的是一个应用项目,那么这一点可以暂时忽略,但是如果你开发的是一款插件或者别人将来引入的包,那么很有可能会给使用者带来不便

因为需要在自己的代码之前运行这些 polyfill 所以该包应该被添加到 dependency

webpack 结合使用时候需要放在 entry 数组中 entry: ["babel-polyfill", "app.js"]

babel-runtime

babel-polyfill 的一次性引入不同,babel-runtime 支持自己手动引入 helper 函数,来完成对某一 API 的转码。它更像是一个个分散的 polyfill 模块。

显而易见 babel-runtime 的缺点之一就是每次使用 API 的时候,都需要我们进行手动引入,很麻烦;此外,在代码中直接引入 helper 函数,会导致打包的文件中出现很多重复 helper 代码。因此现在实际工作中会使用 babel-runtime + babel-plugin-transform-runtime 的形式

babel-plugin-transform-runtime

这个包可以帮我们完成 babel-runtimehelper 函数的自动引入,并且它还做了公用方法的抽离,你引入的函数都是引用自一个地方,就避免了重复的代码

该包依赖 babel-runtime ,这也是为什么我们在使用 webpack 配置 babel 的时候,只需要安装 babel-plugin-transform-runtime 的原因,
devDependencies 里只看见了 babel-plugin-transform-runtime

该插件主要做了三件事:

当你使用 generators/async 方法、函数时自动调用 babel-runtime/regenerator

当你使用 ES6 的 Map 或者内置的东西时自动调用 babel-runtime/core-js

移除内联 babel helpers 并替换使用 babel-runtime/helpers 来替换

优点

不会污染全局变量

多次使用只打包一次

依赖按需引入,无重复引入

适合编写库类型的代码

缺点

不支持实例化的方法 "foobar".includes("foo") 不能转化

配置
一般直接默认就行,不需要对该插件进行配置
{
  "plugins": [
    ["transform-runtime", {
      "polyfill": true,       // 是否把新特性转换为非全局的 polyfill
      "helpers": true,        // 是否用模块中的 helpers 替换内联 helpers
      "regenerator": true,    // 是否把生成器函数转换为非全局的 polyfill
      "moduleName": "babel-runtime"  // 导入 helpers 的时候的模块路径
    }]
  ]
}
一次小测试

.babelrc

转码前的 a.js

转码后的 a-compiled.js

可以看到实例方法 "foo".includes("f") 并没有被转换

再来一个小测试

.babelrc

转码前的 b.js

使用 babel 转码后,Set 转码成功,并且可以看到在转码后的文件中,打印的并不是原生的 Set ,而是 babel 为我们包装的一个替代原生 Set 的模块,避免了全局污染。

当我们把 .babelrc 中改为 polyfill: false 时,再次对 b.js 转码,转码后,语句没有被处理。打印的就是原生的 Set ,污染了全局变量。

如果需要对实例方法进行转码,可以这么来,当然你需要在 .babelrc 里改为 polyfill: true ,不然没有这个 polyfill 根本没有这些方法。

转码前:

转码后:

如果非要在不支持的环境下使用实例方法的话,就还得借助 babel-polyfill 了(或者你自己实现一个)。不过好像目前浏览器端对这种诸如 includesrepeat 之类的方法支持的还不错了。

babel-preset-env
Without any configuration options, babel-preset-env behaves exactly the same as babel-preset-latest (or babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017 together).

首先官网上给了公式

没有任何配置的 env = latest = es2015 + es2016 + es2017

babel-preset-env 由于其灵活的配置和全面的功能,被官网推荐,同时也是目前应用很频繁的 presets

配置项 targets

提供需要支持的环境信息,版本等,默认为 {}

spec

通过牺牲转换时间来支持该 preset 的更多规范兼容性,默认为 false

loose

preset 中的插件开启松散转换

松散模式

优点:转换的代码更加简洁,没有为了接近 ES6 而添加的繁杂逻辑,文件更小,运行速度更快,兼容性更好

缺点:直接使用原生 ES6 可能会有问题

一般不推荐使用松散模式

简单来说,松散模式转换后的代码很容易就能看懂,而且很像我们平时写的代码,但这种不严谨的转换可能会造成问题,所以在开发中是不推荐的。

感受一下:

转码前:

转码后(正常):

转码后(松散):

modules

把 ES6 模块语法转为另一个模块类型,默认 commonjs

现在的 webpack 4.x 已经把模块统一的任务完成了,所以这里就不需要 babel 来做了,所以在 vue-cli 这种用 webpack 打包的脚手架里,你会看到 .babelrc 文件中有 module: false 这就是为了防止与 webpack 冲突
include

指定一组总是包括的插件,当原生实现有问题,或存在不支持或支持不好的特性时候使用,默认为 []

includeexclude 只工作于包含在 preset 里有的插件中,如果要使用 preset 里不包含的插件,直接填在 .babelrcplugins
exclude

指定一组总是不包括的插件,默认为 []

useBuiltIns

默认为 false
会启用一个插件来根据使用情况去按需加载 polyfill 来替代 import "babel-polyfill" 语句

其他 Babel 工具
所有的工具建议都在项目中安装,而不是采用全局安装

babel-cli 用于命令行转码

babel-node 跟随 babel-cli 安装,可直接运行 ES6 代码,因为采用这种方式是实时转码的,转码的所有工具都存在内存中,产生大量资源消耗因此只适合在开发中使用

babel-register 改写 require 命令,每次使用 require 加载 js 文件时候,就会先转码,因为是实时转码,只适合在开发环境使用

babel-core 提供 Babel 的 API,之后可以采用编程方式使用 Babel

参考链接

Babel · The compiler for next generation JavaScript

对babel-transform-runtime,babel-polyfill的一些理解

Babel 入门教程 - 阮一峰的网络日志

babel-polyfill的几种使用方式

Babel笔记 - Tony’s Blog

Babel的使用

Babel 6 松散模式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95666.html

相关文章

  • Vue 2019开发者图谱

    摘要:为了便于您更清晰的理解的体系架构,在这里我将为您展示年开发者知识图谱,它包含了所有开发过程中的关键部分。在数据展示前端导入导出图表面板数据绑定等场景无需大量代码开发和测试,可极大节省企业研发成本并降低交付风险。 作为 Vue 的初学者,您或许已经听过很多关于它的专业术语了,例如:单页面应用程序、异步组件、服务器端呈现等,您可能还听过和Vue经常一起被提到的工具和库,如Vuex、Webp...

    cgspine 评论0 收藏0
  • 关于JavaScript, NPM官方发布了2018年的回顾以及2019年的预测

    摘要:不过,根据伯克利大学的这篇文章来看,拥有丰富的开源库,是开发者在选择一门开发语言时,最重要的因素。拥有超过个可用的开源库,是目前世界上最大的开源库集合。月份,我们发布了。这和年的情况是相反的。在的调查中,超过的受访者表示他们正在使用。 showImg(https://segmentfault.com/img/bVblvke?w=693&h=300); 原文标题:This year in...

    dadong 评论0 收藏0
  • 你真的会用 Babel 吗?

    摘要:安装然后在的配置文件加入入口文件引入这样就可以啦,还是可以减少很多代码量的。是参数,等同于执行正常。这个包很简单,就是引用了和,然后生产环境把它们编译到目录下,做了映射,供使用。 引入 这个问题是对自己的发问,但我相信会有很多跟我一样的同学。对于 babel 的使用,近半年来一直停留在与 webpack 结合使用,以及在浏览器开发环境下。导致很多 babel 的包,我都不清楚他们是干嘛...

    mochixuan 评论0 收藏0
  • 教你如何打好根基快速入手react,vue,node

    摘要:谨记,请勿犯这样的错误。由于在之前的教程中,积累了坚实的基础。其实,这是有缘由的其复杂度在早期的学习过程中,将会带来灾难性的影响。该如何应对对于来说,虽然有大量的学习计划需要采取,且有大量的东西需要学习。 前言倘若你正在建造一间房子,那么为了能快点完成,你是否会跳过建造过程中的部分步骤?如在具体建设前先铺设好部分石头?或直接在一块裸露的土地上先建立起墙面? 又假如你是在堆砌一个结婚蛋糕...

    ddongjian0000 评论0 收藏0

发表评论

0条评论

qiangdada

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<