什么是babel,以及各个插件的区别

本文介绍了Babel的作用,它是将ES6等新语法转换为浏览器兼容的ES5语法的编译器。Babel的使用涉及解析、转换和生成代码三个步骤,其中转换主要依赖插件。文章详细比较了presets与plugins、env与其他preset、transform-runtime与polyfill的区别,并探讨了.babelrc配置文件的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

babel是干嘛的?

现在javascript的正式版本已经到ES2017了,也就是ES8,说明一下:

  • ES6 === ES2015
  • ES7 === ES2016
  • ES8 === ES2017

我们现在用的新版本的javascript语法(主要是ES6)与一些浏览器不兼容,那么就需要把我们的代码编译并生成浏览器兼容的语法(默认是ES5),这就是babel需要做的工作。


如何使用?

Babel 是一个编译器,编译我们的代码分为3步:

  1. 解析(得到源代码,什么都不做)
  2. 转换(将ES6等不兼容语法转换成ES5)
  3. 生成代码

最重要的是第二步:转换,需要通过插件来定义转换规则。

Babel提供了很多的接口,供我们编写自己的插件,转换我们的代码。

what? 要自己写插件?

当然不需要我们自己写啦!

babel官方提供了很多的插件,比如解析箭头函数的插件:

es2015-arrow-functions

这个插件只能转换箭头函数,还有许多的插件,官方把它们集成到了preset中。

如果使用webpack等构建工具,通常有一个.babelrc文件,这个就是babel 的配置文件,配置文件中有两个大项presetspliguns

{
    "presets": [
        ["env", {
            "debug": true,
            "modules": false,
            "targets": {
                "browsers": ["> 1%", "last 3 versions", "not ie <= 9"]
            }
        }]
    ],
    "plugins": ["transform-runtime"]
}

presets 和 plugins 的区别

presets其实是多个plugin的集合。

例如:ES2015的插件集合:

  1. check-es2015-constants
  2. es2015-arrow-functions
  3. es2015-block-scoped-functions
  4. es2015-block-scoping
  5. es2015-classes
  6. es2015-computed-properties
  7. es2015-destructuring
  8. es2015-duplicate-keys
  9. es2015-for-of
  10. es2015-function-name
  11. es2015-literals
  12. es2015-object-super
  13. es2015-parameters
  14. es2015-shorthand-properties
  15. es2015-spread
  16. es2015-sticky-regex
  17. es2015-template-literals
  18. es2015-typeof-symbol
  19. es2015-unicode-regex

如果ES2015这个插件集合还不能满足我们的需要,就需要添加其他的插件。

例如,我们在做vue和react开发的时候需要用到 jsx ,这个时候就需要一些其他的插件:

vue的jsx支持

  • transform-vue-jsx

react的 jsx 支持

  • react

需要polyfill的支持,但是又不想直接引入polyfill(有弊端),可以使用

  • transform-runtime

note: 所有的这些插件的前缀都是 babel-preset-babel-plugin-,只是如果插件名前缀是以 "babel-plugin-"和babel-preset-开头,那么就可以省略z这些前缀


env 和 es2015、es2016、es2017和 stage-x 的区别

env同时包含了es2015、es2016、es2017以及最新版本,也是官方推荐的。

每年每个 preset 只编译当年批准的内容。 而 babel-preset-env 相当于 es2015 ,es2016 ,es2017 及最新版本。

所以es2015(ES6)会编译2015年通过javascript提案,成为正式版本的那一部分语法。 以此类推。

es2015、es2016、es2017编译javscript正式版本的那一部分,stage-x会编译未被批准为 JavaScript 的正式版本,即试用和实验阶段的javascript提案

TC39 将提案分为以下几个阶段:

  • Stage 0 - 稻草人: 只是一个想法,可能是 babel 插件。
  • Stage 1 - 提案: 初步尝试。
  • Stage 2 - 初稿: 完成初步规范。
  • Stage 3 - 候选: 完成规范和浏览器初步实现。
  • Stage 4 - 完成: 将被添加到下一年度发布。

一般在开发项目时会加上stage-2。


babel-plugin-presets 和 polyfill 的区别

babel是将你的语法转换为你目标浏览器支持的语法,默认转换es5,例如:

const  a=10;    ===>   var a = 10;
let    a = 20;  ===>   var a =20;
a=>10;(箭头函数)  ===> (function(a) {
                          return 10;
                        });

polyfill补充一些对象的实例方法、静态方法的支持,以及可以使用新的内置对象:

//新的内置对象
new Promise((resolve,reject)=>{});
new WeakMap();

//静态方法:
Array.from

//实例方法:
Object.assign
Array.prototype.includes

transform-runtime 和 polyfill 的区别

普通导入polyfill的方法是在入口文件导入

entry:{
   index:["babel-polyfill","index.js"] 
}

在代码中导入:

//index.js
import "babel-polyfill"

transform-runtime 是一个插件,在.babelrc中配置,会根据的你的代码,自动引用按需要被转换的polyfill。

主要有两个不同:

  1. import “babel-polyfill” 是一次性全部导入,有时候你只是用了其中一小部分需要转换的实例方法/静态方法,导入了很大一个文件,其中很大一部分是没有必要的,增加文件体积,虽然可以按需引入,但是特别麻烦。
  2. import “babel-polyfill” 是直接全局导入的(没看过源码,估计是 直接在内置对象上修改了原型),会污染全局变量。

我们做个试验,npm init一个项目:

//package.js
{
  "name": "babeltest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "babel src -d dist" //加上这个命令
  },
  "author": "",
  "license": "ISC",
  //下载下面这些依赖
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "babel-cli": "^6.26.0",
    "babel-loader": "^8.0.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0"
  },
  "dependencies": {
    "babel-polyfill": "^6.26.0"
  }
}
//.babelrc 
{
    "presets": [
        ["env", {
            "debug": true,
            "modules": false,
            "targets": {
                "browsers": ["> 1%", "last 3 versions", "not ie <= 9"]
            }
        }]
    ],
    "plugins": ["transform-runtime"]
}

测试代码:

//index.js
import './child'
const a = 10;
let b = 20;
a => 10;
var assignObj = Object.assign({});

var fromArr = Array.from([1, 2, 3])

var promise = new Promise(resolve => console.log('promise'))

//chiild.js
const a = 10;
let b = 20;
a => 10;
Object.assign({});

Array.from([1, 2, 3])

运行命令:

npm run build

得到编译后的文件:

//index.js
import _Promise from 'babel-runtime/core-js/promise';
import _Array$from from 'babel-runtime/core-js/array/from';
import _Object$assign from 'babel-runtime/core-js/object/assign';
import './child';
var a = 10;
var b = 20;
(function (a) {
  return 10;
});
var assignObj = _Object$assign({});

var fromArr = _Array$from([1, 2, 3]);

var promise = new _Promise(function (resolve) {
  return console.log('promise');
});
//child.js
import _Array$from from "babel-runtime/core-js/array/from";
import _Object$assign from "babel-runtime/core-js/object/assign";
var a = 10;
var b = 20;
(function (a) {
  return 10;
});
_Object$assign({});

_Array$from([1, 2, 3]);

可以代码都被转换成了ES5的语法,并且一些实例方法静态方法已经被替换,这些替换的函数(_Array f r o m , O b j e c t from,_Object fromObjectassign)就是polyfill,
我们可以看到index.jschild.js中根据需要,各自引入了一部分polyfill,这就是transform-runtime的好处。


最后说一下.babelrc的配置

{
    "presets": [
        ["env", {
            "debug": true,
            "targets": {
                "browsers": ["> 1%", "last 3 versions", "not ie <= 9"]
            }
        }],
        "stage-2"
    ],
    "plugins": ["transform-runtime"]
}

presets:即官方的插件合集,官方推荐env,省略了前缀。

配置项有很多,一般只需要用到targets属性,说明你的web应用需要兼容到那一部分的浏览器。
plugin一般会加上transform-runtime,自动帮你加载你需要的polyfill

更多presets的配置选项,看官方文档

感兴趣的可以看一下babel应用插件时的转换顺序:presets和plugin的转换排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值