babel之配置文件.babelrc入门详解


Posted in Javascript onFebruary 22, 2018

介绍

es6特性浏览器还没有全部支持,但是使用es6是大势所趋,所以babel应运而生,用来将es6代码转换成浏览器能够识别的代码
babel有提供专门的命令行工具方便转码,可以自行去了解

什么是Babel

官方解释,是下一代JavaScript 语法的编译器。

既然是下一代Javascript的标准,浏览器因版本的不同对此会有兼容性问题,JavaScript的新的方法都不能使用,但是目前我们在项目开发一直提倡使用最新的语法糖编写,不但能减少代码量,而且async,await等新特性还解决了回调的编写机制,减轻了代码维护成本。

Babel就因此而生,它可以让你放心使用大部分的JavaScript的新的标准的方法,然后编译成兼容绝大多数的主流浏览器的代码。在项目工程脚手架中,一般会使用.babelrc文件,通过配置一些参数配合webpack进行打包压缩。也通过网上了解,写法各有不同,参数也大不相同,因此,我重新整理一份资料,详细的介绍下各个配置项的意义所在,以便清晰了解如果使用。

以下配置主要正对webpack3+写法。

Babel转译器

在.babelrc配置文件中,主要是对预设(presets)和插件(plugins)进行配置,因此不同的转译器作用不同的配置项,大致可分为以下三项:

1.语法转义器。主要对javascript最新的语法糖进行编译,并不负责转译javascript新增的api和全局对象。例如let/const就可以被编译,而includes/Object.assign等并不能被编译。常用到的转译器包有,babel-preset-env、babel-preset-es2015、babel-preset-es2016、babel-preset-es2017、babel-preset-latest等。在实际开发中可以只选用babel-preset-env来代替余下的,但是还需要配上javascirpt的制作规范一起使用,同时也是官方推荐

{
 "presets": ["env", {
   "modules": false
  }],
  "stage-2"
}

2.补丁转义器。主要负责转译javascript新增的api和全局对象,例如babel-plugin-transform-runtime这个插件能够编译Object.assign,同时也可以引入babel-polyfill进一步对includes这类用法保证在浏览器的兼容性。Object.assign 会被编译成以下代码:

__WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default()

3.jsx和flow插件,这类转译器用来转译JSX语法和移除类型声明的,使用Rect的时候你将用到它,转译器名称为babel-preset-react

创建预设(presets)

主要通过npm安装babel-preset-xx插件来配合使用,例如通过 npm install babel-preset-stage-2 babel-preset-env --save-dev 安装,会有相应如下配置。

{
 "presets": [
  ["env", options],
  "stage-2"
 ]
}

stage-2配置

babel主要提供以下几种转义器包,括号里面是对应配置文件的配置项

babel-preset-stage-0(stage-0) 
babel-preset-stage-1(stage-1) 
babel-preset-stage-2(stage-2) 
babel-preset-stage-3(stage-3)

不同阶段的转译器之间是包含的关系,preset-stage-0转译器除了包含了preset-stage-1的所有功能还增加了transform-do-expressions插件和transform-function-bind插件,同样preset-stage-1转译器除了包含preset-stage-2的全部功能外还增加了一些额外的功能。

options配置介绍

官方推荐使用babel-preset-env来替代一些插件包的安装(es2015-arrow-functions,es2015-block-scoped-functions等等),并且有如下几种配置信息,介绍几个常用的,

更多配置可以参考官网https://babeljs.io/docs/plugins/preset-env/

{
  "targets": {
    "chrome": 52,
    "browsers": ["last 2 versions", "safari 7"],
    "node":"6.10"
  }
  "modules": false
}

targets可以制定兼容浏览器版本,如果设置了browsers,那么就会覆盖targets原本对浏览器的限制配置。

targets.node正对node版本进行编译

modules通常都会设置为false,因为默认都是支持CommonJS规范,同时还有其他配置参数:"amd" | "umd" | "systemjs" | "commonjs",systemjs我还不知道规范写法是什么,amd和umd以及commonjs相对比较熟悉,下面简要列举下书写规范。

amd代码规范,在ng1中会用到比较多,主要用于依赖注入:

define(['jquery'], function ($) {
  //  方法
  function myFunc(){};
 
  //  暴露公共方法
  return myFunc;
})

commonjs规范,也是node环境中尊崇的一种规范:

var $ = require('jquery');
//  方法
function myFunc(){};
 
//  暴露公共方法(一个)
module.exports = myFunc;
{% endcodeblock %}
>umd规范,兼容amd以及commonjs规范,目前在第三方插件编写使用比较多:
{% codeblock lang:javascript %}
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node, CommonJS之类的
    module.exports = factory(require('jquery'));
  } else {
    // 浏览器全局变量(root 即 window)
    root.returnExports = factory(root.jQuery);
  }
}(this, function ($) {
  //  方法
  function myFunc(){};
 
  //  暴露公共方法
  return myFunc;
}));

插件(plugins)

插件配置项同预设配置项一样,需要搭配babel相应的插件进行配置,可以选择配置插件来满足单个需求,例如早期我们会有如下配置:

{
 "plugins": [
  "check-es2015-constants",
  "es2015-arrow-functions",
  "es2015-block-scoped-functions",
  // ...
 ]
}

但是这些插件从维护到书写极为麻烦,后来官方统一推荐使用env,全部替代了这些单一的插件功能,可以简化配置如下,也就是我前面提到了babel-preset-env:

{
 "presets": [
  "es2015"
 ]
}

这里主要介绍两款常用插件,分别是babel-plugin-transform-runtime,babel-plugin-syntax-dynamic-import。

基本配置代码如下:

{
 "plugins": [
  "syntax-dynamic-import",["transform-runtime"]
 ]
}

transform-runtime

为了解决这种全局对象或者全局对象方法编译不足的情况,才出现了transform-runtime这个插件,但是它只会对es6的语法进行转换,而不会对新api进行转换。如果需要转换新api,也可以通过使用babel-polyfill来规避兼容性问题。

对Object.assign进行编译,配置与未配置经过webpack编译后的代码片段如下:

// 未设置代码片段:
__webpack_require__("ez/6");
var aaa = 1;

function fna() {
 var dd = 33333;
 var cc = Object.assign({ key: 2 });
 var xx = String.prototype.repeat.call('b', 3);
 if ("foobar".String.prototype.includes("foo")) {
  var vv = 1;
 }

 return dd;
}
// 设置代码片段:
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign__);

__webpack_require__("ez/6");
var aaa = 1;

function fna() {
 var dd = 33333;
 var cc = __WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default()({ key: 2 });
 var xx = String.prototype.repeat.call('b', 3);
 if ("foobar".String.prototype.includes("foo")) {
  var vv = 1;
 }

 return dd;
}

对class定义类会进行编译,配置与未配置经过webpack编译后的代码片段如下:

// 未设置代码片段:
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Canvas = function Canvas(height, width) {
 _classCallCheck(this, Canvas);

 this.height = height;
 this.width = width;
};

var Canvas2 = function Canvas2(height, width) {
 _classCallCheck(this, Canvas2);

 this.height = height;
 this.width = width;
};
// 设置代码片段:
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__);

var Canvas = function Canvas(height, width) {
 __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, Canvas);

 this.height = height;
 this.width = width;
};

var Canvas2 = function Canvas2(height, width) {
 __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, Canvas2);

 this.height = height;
 this.width = width;
};

对Generator函数也有同上的编译效果,目前项目中使用该函数较小,一般使用promise替代,以及async await所以未对该函数做测试。

官方说对promise也会产生编译,但是实际测试结果却没有效果

经过webpack打包最终测试,引入transform-runtime该配置项后,打包入口js文件大小会略微增大,并不像官方说的能够缩小文件体积

未配置的最终打包效果:

babel之配置文件.babelrc入门详解

配置后的最终打包效果:

babel之配置文件.babelrc入门详解

虽然文件大小会有所增大,但是解决一些兼容性的问题,同时,从以上给出的测试代码例子来看,使用transform-runtime后,可以减少内部全局函数的定义,从结构上看尊崇了webpack的模块化思想,所以还是建议使用该插件。

syntax-dynamic-import

这个插件主要解决动态引入模块的问题

function nDate() {
 import('moment').then(function(moment) {
  console.log(moment().format());
 }).catch(function(err) {
  console.log('Failed to load moment', err);
 });
}
nDate();

如果.babelrc配置项中使用了"stage-2",也可以不实用该插件,同样支持动态模块引入。

不然就会报以下错误:

  1. Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level, or (import 和 export只能在最外层,也就是不能用在函数或者块中)
  2. Module build failed: SyntaxError: Unexpected token, expected {

其他配置项

ignore

主要作用就是可以指定不编译那些代码

{
 "ignore":["./module/a.js"]
}

let,Object.assign,class定义都未编译,编译效果如下:

__webpack_require__("ez/6");
const aaa = 1;

function fna () {
 let dd = 33333
 let cc = Object.assign({key:2})
 let xx = String.prototype.repeat.call('b', 3)
 if ("foobar".String.prototype.includes("foo")) {
  let vv = 1
 }

 return dd
}

function fna2 () {
 return fna() + aaa + __WEBPACK_IMPORTED_MODULE_0__b__["a" /* default */]
}

class Canvas {
 constructor(height, width) {
  this.height = height;
  this.width = width;
 }
}

class Canvas2 {
 constructor(height, width) {
  this.height = height;
  this.width = width;
 }
}

minified

主要设置编译后是否是压缩,boolean类型,如果使用babel-cli进行打包编译文件这个配置项能够起到作用,但是目前大部分还是会依赖第三方打包工具,例如webpack,所以这个配置参数一般不用设置,webpack插件中的UglifyJsPlugin做了压缩的工作。

comments

在生成的文件中,不产生注释,boolean类型,webpack插件中的UglifyJsPlugin也同样集成了这个功能。

env

基本配置如下:

{
 "env": {
  // test 是提前设置的环境变量,如果没有设置BABEL_ENV则使用NODE_ENV,如果都没有设置默认就是development
  "test": {
   "presets": ["env", "stage-2"],
   // instanbul是一个用来测试转码后代码的工具
   "plugins": ["istanbul"]
  }
 }
}

再谈兼容性问题

Babel默认只转换新的JavaScript语法,而不转换新的API,比如Iterator、Generator、Set、Maps、Promise等等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码,具体的可以参考babel-plugin-transform-runtime模块的 definitions.js 文件。

这里主要涉及到babel编译后依然会存在浏览器兼容性问题,一般会使用transform-runtime和babel-polyfill配合使用,对于后者只需要在项目入口文件require引入即可。

当然在使用类似Object.assign函数功能时,可以使用lodash库来替代,promise可以使用Q.js替代等等方案,这样依赖可以不需要引入以上插件,具体可以根据项目具体安排

总结

.babelrc配置文件主要还是以presets和plugins组成,通过和webpack配合进行使用,分享下我们在项目中常用的配置。以上都是通过学习总结出来的,有什么不对的地方希望指出。

vue项目开发使用的配置如下:

{
 "presets": [
  ["env", {
   "modules": false
  }],
  "stage-2"
 ],
 // 下面指的是在生成的文件中,不产生注释
 "comments": false,
 "plugins": ["transform-runtime","syntax-dynamic-import"],
 "env": {
  // test 是提前设置的环境变量,如果没有设置BABEL_ENV则使用NODE_ENV,如果都没有设置默认就是development
  "test": {
   "presets": ["env", "stage-2"],
   // instanbul是一个用来测试转码后代码的工具
   "plugins": ["istanbul"]
  }
 }
}

react项目开发使用的配置如下:

{
 "presets": [
  ["env", { "modules": false }],
  "stage-2",
  "react"
 ],
 "plugins": ["transform-runtime"],
 "comments": false,
 "env": {
  "test": {
   "presets": ["env", "stage-2"],
   "plugins": [ "istanbul" ]
  }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
判断JavaScript对象是否可用的最正确方法分析
Oct 03 Javascript
QUnit jQuery的TDD框架
Nov 04 Javascript
js实现的黑背景灰色二级导航菜单效果代码
Aug 24 Javascript
ionic由于使用了header和subheader导致被遮挡的问题的两种解决方法
Sep 22 Javascript
老生常谈javascript的类型转换
Oct 12 Javascript
使用ReactJS实现tab页切换、菜单栏切换、手风琴切换和进度条效果
Oct 17 Javascript
jquery之基本选择器practice(实例讲解)
Sep 30 jQuery
vue.js+element-ui动态配置菜单的实例
Sep 07 Javascript
在vue项目中使用sass语法问题
Jul 18 Javascript
Node.js操作MongoDB数据库实例分析
Jan 19 Javascript
基于Echarts图表在div动态切换时不显示的解决方式
Jul 20 Javascript
关于angular 8.1使用过程中的一些记录
Nov 25 Javascript
javascript填充默认头像方法
Feb 22 #Javascript
一次记住JavaScript的6个正则表达式方法
Feb 22 #Javascript
利用CDN加速react webpack打包后的文件详解
Feb 22 #Javascript
node内置调试方法总结
Feb 22 #Javascript
详解vue移动端日期选择组件
Feb 22 #Javascript
webpack 单独打包指定JS文件的方法
Feb 22 #Javascript
webpack中使用iconfont字体图标的方法
Feb 22 #Javascript
You might like
提高PHP编程效率 引入缓存机制提升性能
2010/02/15 PHP
php printf输出格式使用说明
2010/12/05 PHP
Zend Studio去除编辑器的语法警告设置方法
2012/10/24 PHP
基于empty函数的判断详解
2013/06/17 PHP
Thinkphp5 自定义上传文件名的实现方法
2019/07/23 PHP
php获取小程序码的实现代码(B类接口)
2020/06/13 PHP
关于js拖拽上传 [一个拖拽上传修改头像的流程]
2011/07/13 Javascript
Nodejs极简入门教程(一):模块机制
2014/10/25 NodeJs
node.js抓取并分析网页内容有无特殊内容的js文件
2015/11/17 Javascript
js获取所有checkbox的值的简单实例
2016/05/30 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
大白话讲解JavaScript的Promise
2017/04/06 Javascript
Bootstrap Table使用整理(二)
2017/06/09 Javascript
微信小程序实现弹出菜单
2018/07/19 Javascript
three.js搭建室内场景教程
2018/12/30 Javascript
JS实现集合的交集、补集、差集、去重运算示例【ES5与ES6写法】
2019/02/18 Javascript
微信小程序如何连接Java后台
2019/08/08 Javascript
ES6中Set和Map用法实例详解
2020/03/02 Javascript
JS判断浏览器类型与操作系统的方法分析
2020/04/30 Javascript
为react组件库添加typescript类型提示的方法
2020/06/15 Javascript
Python的另外几种语言实现
2015/01/29 Python
Python中使用socket发送HTTP请求数据接收不完整问题解决方法
2015/02/04 Python
详尽讲述用Python的Django框架测试驱动开发的教程
2015/04/22 Python
解决DataFrame排序sort的问题
2018/06/07 Python
scrapy-redis的安装部署步骤讲解
2019/02/27 Python
Python如何测试stdout输出
2020/08/10 Python
String这个类型的class为何定义成final?
2012/11/13 面试题
应聘教师自荐信
2013/10/12 职场文书
会计电算化学生个人的自我评价
2014/02/08 职场文书
厂办主管岗位职责范本
2014/02/28 职场文书
公益广告语集锦
2014/03/13 职场文书
QQ空间主人寄语大全
2014/04/12 职场文书
入职担保书范文
2014/05/21 职场文书
社会实践的活动方案
2014/08/22 职场文书
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL
Win11电脑显示本地时间与服务器时间不一致怎么解决?
2022/04/05 数码科技