babel学习记录

一、前言:最开始接触babel是开始学习vue的时候,因为使用vue开发单页应用时使用了许多ES6/ES7的语法,当时只知道babel是用来将ES6/ES7语法转换为浏览器能识别的ES5,而且还错误地认为babel仅仅是webpack的一个插件,是为webpack而生的,后来随着慢慢学习,才发现babel是一个强大的工具链,它可以进行语法转换,polyfill(打补丁),源码转换,jsx语法转换等等一系列操作。在webpack上使用只是对它的一种应用。babel还可以在gulp,grunt,rollup等一系列打包工具上使用,除此之外babel官方提供了cli可以不借助打包工具使用。

二、简单使用(babel7.x)

  • 安装包,@babel/core为核心包,@babel/cli为babel cli,用来执行babel,@babel/preset-env为插件,用来转换ES6/ES7或更高级的语法。如果只使用@babel/core,转换前与转换后相同,不做处理。@babel/polyfill,用来给新的API打补丁。
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
  • 配置,在项目根目录下创建babel.config.js,targets表示支持的浏览器,useBuiltIns为babel7.x新增的一个属性
module.exports = {
    presets: [
        [
            '@babel/env',
            {
                useBuiltIns: 'usage',
                corejs: 2,
                targets: {
                    edge: "17",
                    firefox: "60",
                    chrome: "67",
                    safari: "11.1",
                }
            }
        ]
    ]  
}
  • 执行babel,npx为npm的包执行器
./node_modules/.bin/babel src --out-dir lib
//或者
npx babel src --out-dir lib

我们来对如下代码进行转换

let a = 23
let fn = () => 34
let obj = {
    name: 'tom'
}
Object.assign(obj, { age: 23 })

当我们开启useBuiltIns时,

'use strict'

require('core-js/modules/es6.object.assign')

var a = 23

var fn = function fn() {
    return 34
}

var obj = {
    name: 'tom'
}
Object.assign(obj, {
    age: 23
})

当不使用useBuiltIns时,可以看到Object.assign没有被转换

'use strict'

var a = 23

var fn = function fn() {
    return 34
}

var obj = {
    name: 'tom'
}
Object.assign(obj, {
    age: 23
})

说明:@babel/polyfill 模块包括 core-js 和一个自定义的 regenerator runtime 模块用于模拟完整的 ES2015+ 环境,这意味着你可以使用诸如 Promise 和 WeakMap 之类的新的内置组件、 Array.from 或 Object.assign 之类的方法、 Array.prototype.includes 之类的实例方法以及生成器函数(generator functions)(前提是你使用了 regenerator 插件)。为了添加这些功能,polyfill 将添加到全局范围(global scope)和类似 String 这样的内置原型(native prototypes)中。对于软件库/工具的作者来说,这可能太多了。如果你不需要类似 Array.prototype.includes 的实例方法,可以使用 transform runtime 插件而不是对全局范围(global scope)造成污染的 @babel/polyfill。

幸运的是,我们所使用的 env preset 提供了一个 "useBuiltIns" 参数,当此参数设置为 "usage" 时,就会加载上面所提到的最后一个优化措施,也就是只包含你所需要的 polyfill。

注意问题:babel7.x

  1. 当我们使用上述方法进行polyfill时,可以看到,新的API是通过全局注入的,这样可能造成全局污染,解决方法后面介绍
  2. 在babel7.x中,当我们使用useBuiltIns,执行babel代码转换时,控制台会给我们提示如下信息:

大概意思是:babel编译器告诉你,你在env中使用了useBuiltIns参数,但并没有显示声明core-js的版本,在当前版本没指定core-js时,会默认引入2.x版本的core-js;并且下面建议我们安装使用core-js2.x或者core-js3.x。在这里,当我们不指定的时候,默认使用2.x,如果指定为1的时候,babel编译器执行时就报错,也就是说我们要么不指定,要么就是2,要么就是3或者以后的更高版本。两者的的区别

//使用2.x时,导入的补丁如下
require("core-js/modules/es6.object.assign");
//使用3.x时,导入的补丁如下
require("core-js/modules/es.object.assign");

当我们使用2.x的时候,如果我们没有安装core-js2.x,npx babel编译的时候并不会报错,但时当我们打开core-js/modules时,里面并没有es6.object.assign文件,所以运行时会报错。所以当你开启useBuiltIns时,记得安装对应版本的core-js。

三、@babel/polyfill,@babel/runtime,@babel/plugin-transform-runtime三者的使用与区别。

  • @babel/polyfill,上面已经介绍过了,用来polyfill想Object.assign,Array.form等新的API,使用方式,babel7.x之前可以在webpack中的入口处指定,也可以在main.js中直接引入,在babel7.x中,@babel/preset-env中新增加的参数useBuiltIns可以指定使用polyfill。
//相当于按需引入
 presets: [
        [
            '@babel/env',
            {
                useBuiltIns: 'usage',
                corejs:2
            }
        ]
 ]
//相当于全部polyfill引入,不建议这么使用  
//import '@babel/polyfill'
 presets: [
        [
            '@babel/env',
            {
                useBuiltIns: 'entry',
                corejs:2
            }
        ]
 ]
  • @babel/runtime:作用与@babel/polyfill一样,@babel/polyfill是相当于将对应的polyfill挂在构造函数的原型上,这样会造成原型污染,@babel/runtime相当于局部的polyfill,不会造成全局变量污染。
  • @babel/plugin-transform-runtime:@babel/runtime的使用依赖@babel/plugin-transform-runtime(官网上说得)

针对上面提到的@babel/polyfill会产生原型污染和全局污染,我们使用@babel/runtime

plugins: [
    [
        '@babel/plugin-transform-runtime',
        {
            helpers: true,
            corejs: 2
        }
    ]
]

在这里我们没有使用@babel/polyfill,同样也能polyfill新的api

//源代码
let a = 23
let fn = () => 34
let obj = {
    name: 'tom'
}
Object.assign(obj, { age: 23 })

使用@babel/runtime后

"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));

var a = 23;
var fn = function fn() {
  return 34;
};
var obj = {
  name: 'tom'
};
(0, _assign["default"])(obj, {
  age: 23
});

注意:同样在这里我们打开node_modules文件夹下的@babel文件夹,发现并没有runtime-corejs2文件夹,这是因为babel7.x后@babel/runtime已经将其剔除了,里面只剩helpers和regenerator了,要使用,必须手动安装,安装方式如下

npm i @babel/runtime-corejs2 -S

使用时必须配置参数corejs:2

helpers:是babel转换时的一些辅助函数,在babel7.x之前我们可以在preset-env中的参数开启,在babel7.x之后已经从preset-env中被剔除,被加入到transform-runtime中,可以在其参数中设置其值为true开启,默认值为false

regenerator:可以将AST语法书转换成代码,可以在transform-runtime开启,默认值为false

helpers和regenerator在我们自定义插件时相当有用,一般情况可以不用管。

总结:在转换新的语法时我们使用preset-env,在polyfill新的API时,我们可以使用@babel/polyfill或者@babel/runtime,使用前者我们可以在preset-env中设置参数开启,也可以直接导入。使用后者时我们需要配合@babel/plugin-tranform-runtime插件。在babel7.x之前,我们直接安装@babbel/polyfill或者babel/rutime就行了,在7.x之后,当我们使用@babel/polyfill时需要手动安装core-js@2或者core-js@3作为生产依赖,当我们使用@babel/rutime是需要手动安装@babel/runtime-corejs2作为生产依赖。在@babel/preset-env中一些stage-n里的特性已经不被包含,比如在class使用箭头函数时,我们需要安装插件@babel/plugin-proposal-class-properties,然后在plugins里面配置,具体哪些不包含,我们可以在打包错我信息的提示中查看。

最后再说说babel在项目中使用的方法吧

  • 创建babel.config.js(推荐做法)
  • 创建.babelrc文件,以json格式配置
  • 在npm的package.json中配置
  • 在webpack中使用,还可以在babel-loader的参数中配置
//在babel.config.js中
module.exports = function (api) {
  api.cache(true);

  const presets = [ ... ];
  const plugins = [ ... ];

  return {
    presets,
    plugins
  };
}
//在.babelrc中
{
  "presets": [...],
  "plugins": [...]
}
//在packag.json中
{
  "name": "my-package",
  "version": "1.0.0",
  "babel": {
    "presets": [ ... ],
    "plugins": [ ... ],
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值