前端应该都会知道babel,知道这是一个把es6转换成es5的工具,用react框架的可能会了解到是jsx,当然熟悉vue的也会知道jsx这种形式,但是我只是会用,会简单配置一下。并不了解,babel究竟是什么玩意。(也许是因为我还大学没毕业的原因吧,见识短见。。。)
官网说Babel 是一个 JavaScript 编译器。
编译分成3个阶段:解析,转换,打印输出。
babel如果本身没有任何插件,则基本就是源代码不发生变化,要想进行相应的转化,就必须有相应的插件带动它。
为了应征这一点,我们先测试一下。
npm init //初始化
npm i -D @babel/core @babel/cli //下载babel-core的作用就是babel的作用负责编译
//@babel/cli没必要说了,@babel/cli/bin 里面的指令可以进行编译
创建一个script.js文件
//随便写点代码
const a=10;
console.log(a)
let b =()=>console.log(a)
调用指令npx babel script.js或者 npx babel script.js --out-file script-compiled.js
也可以在package.json中配置一下script命令
"serve": "node_modules/.bin/babel script.js "
后者生成文件
可以得到在命令控制台
发现代码除了格式变了一下,没有任何变化
这里印证了官网说的没毛病,当然官网怎么可能会说的有毛病。
那么问题来了,怎么配置插件(plugin),插件那么多,配置起来那么麻烦,怎么办,优先级又是怎么样的?一大推问题来了,该怎么解决呢?
官方说,我知道你们也不容易,所以我就配置几个吧,preset(预设)就出来了,
比如我们经常用到的预设,@babel/preset-env,es6转成es5最常用的配置,当然还有@babel/preset-react,@babel/preset-typescript ,@babel/preset-flow。
preset 预设
首先preset本质的原理就是自己配置一大推的plugin,我们拿@babel/preset-env为例,如图
里面还有很多插件,太多了,就拍了一点,
官网也说过了,可以自己配置一个preset,格式如下
module.exports = function() {
return {
plugins: [
"pluginA",
"pluginB",
"pluginC",
]
};
}
这样preset的原理我们也懂了,其实就是一个插件的套餐。
#######优先级
在.babelrc preset是从后往前来的。
那么我们来测试一下@babel/preset-env吧
npm i @babel/preset-env -D //这里我们不考虑生产环境和开发环境因为主要是为了测试
创建文件夹.babelrc
{
"presets": ["@babel/preset-env"]
}
在运行指令npm run serve,如果没有配置的话,就调用npx babel script.js
代码成功的转换成了es5的形式。
插件plugin
首先插件(plugin)的优先级要>preset(预设)的
插件是从前往后运行的,这点和preset是相反的。
语法插件(syntax)
在有对应的转换(transform)插件的使用后,可以不写。这是一个小细节吧。
插件也没啥可说的,想用啥的时候就使用啥就哦了,还是介绍一个react ui antd经常用的按需加载的插件babel-plugin-import ,这个插件的作用是为了解决在按需加载的问题,当我们引用react的ui库antd时,就会引用这个插件。
尽管我感觉没啥用,因为treeshanking,在生产环境会完成按需加载。
plugins: [
['import',[{ // 导入一个插件
libraryName: 'antd', // 暴露的库名
style: true // 直接将ants样式文件动态编译成行内样式插入,就不需要每次都导入
}]]
]
Polyfills
@babel/polyfills 可以满足babel的所有功能,babel-preset-env不足以满足所有的功能,这时候就需要用到了它了,例如await, generator,symbol等等
注意:polyfills已经放弃更新了。
import @babel/polyfill
就可以在下面随便写代码了,
但是有一个缺点,体积太大
@babel/polyfills =core-js +regenerator-runtime
虽然@babel/polyfills不更新,但是core-js 还会继续更新。
因为缺点明显,体积过大,那么怎么解决这个问题呢?
肯定是按需求加载,这时就出现了一种方案useBuiltInts:usage
npm i core-js //新版本是3.x
presets:[['@babel/preset-env',{
useBuiltIns:'usage',
module:false,
//指定core-js版本
corejs:{
version:3
},
//指定兼容性做到哪个版本
targets:{
chrome:'60',
firefox:'60',
ie:'9'
}
}]]
这样就可以解决体积大的问题。
@babel/plugin-transform-runtime
从名字看我们就可以理解这个插件,作用是为了在不同模块都调用相同方法,如class,没必要调用第二次还生成一个function方法。
它需要babel-runtime,babel-runtime就是重复代码的集合处。
babel-runtime内部集成了core-js regenerator-runtime helpers
我们一块引用core-js 按需加载和@babel/plugin-transform-runtime 测试一下代码。
const a=10;
console.log(a)
let b =()=>console.log(a)
const c =new Promise((rej,res)=>{
rej(1)
})
c.then(function(data){
console.log(data)
})
class D{
constructor(){
this.value='123'
}
}
const e=new D()
console.log(e)
const f=`${e}hahahahah`
const z=new Promise((rej,res)=>{
rej(1)
})
z.then((data)=>{
console.log(data)
})
var map = new Map();
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/map"));
var a = 10;
console.log(a);
var b = function b() {
return console.log(a);
};
var c = new _promise.default(function (rej, res) {
rej(1);
});
c.then(function (data) {
console.log(data);
});
var D = function D() {
(0, _classCallCheck2.default)(this, D);
this.value = '123';
};
var e = new D();
console.log(e);
var f = "".concat(e, "hahahahah");
var z = new _promise.default(function (rej, res) {
rej(1);
});
z.then(function (data) {
console.log(data);
});
var map = new _map.default();
{
"presets": [["@babel/preset-env",{"useBuiltIns":"usage","corejs":3,"targets":{
"chrome":"60",
"firefox":"60",
"ie":"11"
}}]],
"plugins": [["@babel/plugin-transform-runtime",{"corejs":3}]]
}
发现和我们的想法一样,调用了runtime里面的内容,证明@babel/plugin-transform-runtime使用成功,而且也实现了按需求加载,没有require('@babel/polyfill'),所以也成功了!
babel-loader
这玩意大家肯定更熟悉,我也不用多说了,在代码压缩之前调用一次babel,不仅符合浏览器调用版本,而且还能压缩体积,还有比这爽的吗。(配置过程不爽!!!)
简单介绍一下配置过程
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
也可以 use:[{loader:'babel-loader',options:{
plugins:['xxx'],
presets:['xxxx']
}}]
}
]
在babel-loader里面配置优先级更大。
但是一般我们还是会选择在外边配置,package.json里面配置或者是.babelrc里面配置
先介绍到这吧!