babel简介
目前ECMAScript 2015+版本的代码在不同的浏览器环境或者同一种浏览器的不同版本中,被支持的程度不一样。导致开发阶段需要做很多兼容处理。如果采用传统的人工兼容方式,不仅耗时耗力,而且不能够保证达到要求。
幸运的是,目前已经有许多的开源社区在做这方面的事情,只需要使用社区提供的工具或者第三方库就可以很方便实现各种运行环境的兼容,其中的佼佼者就是Babel了。
Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转换为向后兼容的JavaScript代码,使之可以运行在各种环境中。
Babel主要能做的事情大致如下:
- 语法转换
- 通过Polyfill方式在目标环境中添加缺失的特性
- 原始码转换
Babel用于处理JavaScript代码实现在不同运行环境的兼容,其可以单独使用,也可以集成到各种构建工具中去,本章节着重讲一下如何在Webpack中集成Babel。(写此部分内容的时候,当前Babel版本为7.8.0)
安装依赖
在Webpack中使用Babel需要安装如下几个基础的第三方库:
- babel-loader(Webpack中用于处理js文件的Loader,可以使用babel的功能)
- @babel/core(babel核心功能库)
- @babel/preset-env(一个智能预设:插件集合,转换你所使用的最新JavaScript)
安装命令:npm install --save-dev babel-loader @babel/core @babel/preset-env -D
Loader配置
安装所需依赖之后,要使用babel-loader需要在Webpack的配置文件中进行如下配置:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// 预设集合
presets: ['@babel/preset-env'],
// 插件集合
plugins: [
// 使用其他插件
]
}
}
}
]
}
}
上面配置中针对JavaScript文件,使用了babel-loader进行处理,在options配置中告诉了Babel要使用哪些预设和插件进行JavaScript代码的处理。
Babel的其他配置方式
上面使用配置文件配置Babel的转换时所需要的预设和插件只是其中一种配置方式,下面简单介绍一下Babel中其他的几种配置方式。
babel.config.json
在项目根目录下新建babel.config.json文件内容如下:
{
"presets": [
"@babel/preset-env"
],
"plugins": []
}
babel.config.js
在项目根目录下新建babel.config.js文件内容如下:
module.exports = function (api) {
api.cache(true);
const presets = [
"@babel/preset-env"
];
const plugins = [
// 其他插件
];
return {
presets,
plugins
};
}
.babelrc.json
在项目根目录下新建.babelrc.json文件内容如下
{
"presets": [
"@babel/preset-env"
],
"plugins": []
}
.babelrc
在项目根目录下新建.babelrc文件内容如下:
{
"presets": [
"@babel/preset-env"
],
"plugins": []
}
package.json中进行配置
在package.json中新增如下配置:
{
"babel": {
"presets": [
"@babel/preset-env"
],
"plugins": []
}
}
上面介绍的几种配置方式,都可以用于Babel的配置,Babel会根据一定规则去读取配置,推荐使用JavaScript配置的方式,该方式相对其他几种方式更加灵活。
babel/cli
Webpack构建后的代码难以阅读,要查看Babel转换后的代码可以使用babel/cli,该工具可以针对源代码产生可阅读性较高的转换代码。使用之前,需要安装babel/cli。
项目的src目录下新建index.js内容如下:
const func = () => {
console.log("hello babel");
}
在这里使用了const和箭头函数两个JavaScript的新特性,需要检验这两个特性是否被兼容处理。
下面介绍三种babel/cli使用的方式:
- 终端运行命令: ./node_modules/.bin/babel src --out-dir lib
- 终端运行命令: npx babel src --out-dir lib
- 使用npm scripts,在package.json中配置如下:
{
"scripts": {
"babel": "babel src --out-dir lib"
}
}
终端运行命令: npm run babel
上面三种方式的作用都是把src下面的JavaScript文件进行转换,并把结果输出到lib目录下。不管使用那种方式,最后在lib目录下的index.js得到的结果如下:
"use strict";
var func = function func() {
console.log("hellp babel");
};
可以看到新特性成功进行了转换,值得注意的是不是所有特性都可以直接转换,需要开发者自己配置对应的Presets和Plugins进行处理。
Presets和Plugins简单分析
当某些高版本的JavaScript特性无法直接转换或者只针对某些特性进行转换的时候,需要借助babel生态社区中的相关Presets和Plugins,来对JavaScript进行兼容处理。(Babel中内置了很多插件,可以通过手动配置覆盖默认配置)
Plugins
Babel可以使用各种插件针对不同特性JavaScript特性进行转换。比如你只需要转换源代码中的箭头函数,那么你只需要安装@babel/plugin-transform-arrow-functions插件,进行如下所示配置:
{
"presets": [],
"plugins": [
"@babel/plugin-transform-arrow-functions"
]
}
进行如下配置的后,上面项目执行编译会得到如下结果:
const func = function () {
console.log("hello babel");
};
很明显,在箭头函数得到了兼容处理,但是const没有得到处理,此时需要使用其他插件来进行其他JavaScript特性的转换了。更多关于plugins的介绍和使用请前往https://babeljs.io/docs/en/plugins进行查阅。
Presets
Babel配置中Plugins字段就是用于配置各种插件,实际开发中,为了开发效率会使用到很多JavaScript的新特性,如果针对每一个特性都进行插件的配置,过程就过于繁琐,此时可以使用Presets。Presets就是一组转换JavaScript插件的集合。例如上面使用的@babel/preset-env就是Babel官方推荐对JavaScript新特性转换的插件集合,使用Presets避免了多次Plugins中进行插件的配置。一个Presets构成大致如下:
module.exports = function () {
return {
plugins: [
"pluginA",
"pluginB",
"pluginC",
]
};
}
根据实际情况开发者还可以编写针对自己项目的Presets,去转换一些特殊场景的JavaScript代码。
Preset的缩写
在Presets中配置的Preset还可以进行缩写,如下所示:
{
"presets": [
"@babel/env"
],
"plugins": []
}
是否采用缩写完全取决于开发者自己,推荐使用全名称的方式,可以很明显的知道使用的相关Presets。
Preset 的执行顺序
Webpack中Loader的默认执行顺序是从右到左,从后向前,Preset的执行顺序和Loader的默认执行顺序一样。如下所示:
{
"presets": [
"a",
"b",
"c"
]
}
该配置将按c,b,a的顺序执行,该执行方式主要是为了确保向后兼容。
Preset 的参数
Plugin和Preset都可以接受参数,将Presets中的每一项写成一个数组,数组的第一项就是需要使用的Presets,数组其他项就是该Presets对应的参数。
如果不指定参数,下面这几种形式都是一样的:
{
"presets": [
"presetA",
[
"presetA"
],
[
"presetA",
{
}
]
]
}
要指定参数,请传递一个以参数名作为键(key)的对象:
{
"presets": [
[
"@babel/preset-env",
{
"loose": true,
"modules": false
}
]
]
}
更多关于presets的介绍和使用请前往https://babeljs.io/docs/en/presets添加链接描述进行查阅。
@babel/preset-env解析
@babel/preset-env是Babel官方提供的一个用于转换JavaScript大多数新特性的Preset,其可以对大部分高级JavaScript特性进行兼容,可以针对该Presets进行精细化的配置,达到项目所需的目标。
Targets
Targets表示@babel/preset-env需要作用的目标环境,之前的练习配置如下:
{
"babel": {
"presets": [
"@babel/preset-env"
],
"plugins": []
}
}
并没有指定Targets,其默认值为一个空对象,如果未指定目标,则@babel/preset-env将默认转换所有ECMAScript 2015+代码。
Babel官网中给出的Targets配置如下:
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage"
}
]
]
}
使用该配置进行代码的转换,lib/index.js内容如下所示:
const func = () => {
console.log("hellp babel");
};
可以看出代码原样输出,其原因是当前的tatgets配置指定的目标环境中,已经能够支持const ,箭头函数等新特性,所以不需要进行转换。
现在做如下修改:
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": "10",
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
}
}
]
]
}
在这里新增目标环境ie:10,在执行转换,结果如下:
var func = function func() {
console.log("hellp babel");
};
在增加ie:10的目标环境以后,源代码进行了转换。Targets中配置了多个目标环境的时候,会执行少数压倒多数的原则,只要有一个目标环境不支持相关特性,就需要进行代码的转换。
Targets的配置除了是一个指明相关环境信息的对象,还可以是一个浏览器兼容列表的一个查询,如下所示:
{
"presets": [
[
"@babel/env",
{
"targets": "> 0.25%, not dead"
}
]
]
}
该配置表示仅包括浏览器市场份额超过0.25%的需要Polyfill和代码转换。
可以对browserslistrc进行配置来代替Targerts的配置,browserslistrc用于指定相关前端工具进行操作的时候需要考虑到的目标环境。
使用.browserslistrc文件进行配置
在项目根目录新建.browserslistrc文件内容如下:
# Browsers that we support
> 0.25%
not dead
在package.json中配置
{
"browserslist": [
"> 0.25%",
"not dead"
]
}
上面两种方式都可以为Babel进行转化的时候指明目标环境。
实际开发中推荐使用browserslistrc配置,其配置可以被多种工具使用,例如这里的babel和后面章节中要介绍的Postcss。有关browserslistrc配置的详细介绍请前往https://github.com/browserslist/browserslist进行查阅。
在省略Targets值配置的时候,也没有配置browserslistrc,(targets的权重高于browserslistrc)那么Babel默认会对源码进行兼容的转换。推荐在项目中指明所运行的目标环境,因为Babel转换是一个耗时的操作,应该进行最小的转换,而不是去转换那些被目标环境所支持的特性。
UseBuiltIns
此选项配置@babel/preset-env如何处理Polyfills。Polyfill 是一块代码(通常是Web上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。
UseBuiltIns可以进行多种形式的配置,如下所示:
通过安装core-js来实现环境的Polyfills:
npm install core-js@3 --save
or
npm install core-js@2 --save
Corejs
在给UseBuiltIns设置"entry"或者"usage"的时候,执行Babel转换,终端会提示你指明corejs的版本号。其默认值为2,仅注入用于稳定ECMAScript功能的Polyfill。如果你想对ECMAScript中相关提案都进行core-js填充,可以指明corejs的版本号为3:
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": "10",
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
有关@babel/preset-env更多配置请前往https://babeljs.io/docs/en/babel-preset-env进行查阅。