日期:2021年8月21日标签:JavaScript

Babel入门教程 #

本教程是针对新人的入门级教程。教程参考了官方文档

源码github:https://github.com/pengfeiw/babel-tutorial

假设你已经安装了node、npm(或yarn)等必要的开发环境。

一.JavaScript的编译器 #

Babel是JavaScript的编译器,我认为编译器这个词用于描述Babel不是很准确,因为JavaScript并不像C++、C#那样需要预先编译才能运行,JavaScript是一门解释型语言,Babel的作用是将ECMAScript 2015+的代码转换为旧的浏览器可兼容的代码,所以它是一个代码转换器,将新语法转换成旧的语法,这样以使新的项目可以在老版本的浏览器环境上执行。

Babel的主要作用如下:

  • 转换语法。
  • 预填充功能,借助第三方库(例如core-js)可以在不支持某些新函数的环境使用新函数运行程序。
  • 源码转换。
  • 其他功能。

例如使用Babel,可以将箭头函数转换成普通函数。

// Babel输入: ES2015的箭头函数
[1, 2, 3].map(n => n + 1);

// Babel输出: ES5等价的语法
[1, 2, 3].map(function(n) {
  return n + 1;
});

二.使用命令行进行编译 #

所有Babel的包都发布在npm上,并且名称以@babel为前缀(自从版本7.0之后)。接下来,我们一起看下@babel/core@babel/cli这两个包。

核心库——@babel/core #

core,中文意思即核心。封装了Babel的核心功能。可已通过npm或yarn进行安装。

npm install --save-dev @babel/core

yarn add @babel/core --dev

通过以上命令将@babel/core安装到开发依赖中,因为生产环境不需要@babel/core@babel/core的主要功能是转换代码(编译代码)。

安装后,我们可以在js代码中,直接引入babel模块用于转换代码。

const babel = require("@babel/core");

babel.transformSync("code", optionsObject);

transformSync函数的第一个参数是需要转换的代码,第二个参数为可选参数,用于设定babel的配置(configuration)。

命令行工具——@babel/cli #

CLI全称为Command Line Interface,即命令行接口、命令行界面。借助@babel/cli,我们可以在命令行使用babel。

通过yarn或者npm安装@babel/cli

npm install --save-dev @babel/cli

or

yarn add @babel/cli --dev

安装后,可以通过命令行编译代码:

./node_modules/.bin/babel src --out-dir lib

该命令调用的是./node_modules/.bin文件加下的babel脚本,通过脚本运行babel,编译代码,src为源码路径,--out-dir选项设置输出目录为lib。编译成功输出如下信息。

Babel入门教程

我们使用了--out-dir配置选项设置了输出目录,@babel/cli还支持其他的配置选项,可以通过--help查看其他可配置的选项。

./node_modules/.bin/babel --help

Babel入门教程

执行命令后,会输出一个options列表,列表中是CLI所有可配置选项,但是目前我们只关心两个最重要的配置选项--plugins--presets(插件和预定义配置)。

三.插件和预定义配置 #

插件 #

插件(plugins)是一段javascript程序,用于指示babel如何转换代码,你可以自己编写插件,也可以使用别人写好的插件。例如官方插件@babel/plugin-transform-arrow-functions,用于将ES2015+的箭头函数转换为function关键字形式的函数。

安装@babel/plugin-transform-arrow-functions

npm install --save-dev @babel/plugin-transform-arrow-functions

or

yarn add @babel/plugin-transform-arrow-functions --dev

使用--plugins配置选项,设置使用@babel/plugin-transform-arrow-functions进行编译:

./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions

执行命令后,你的源码中所有的箭头函数都会被转换为function关键字定义的函数:

const fn = () => 1;

// converted to

var fn = function fn() {
  return 1;
};

很好,我们已经知道插件是什么了,并且知道如何配置使用插件了,很不错。但是如果有很多插件呢,每个都添加在命令行中岂不是很麻烦。幸运的是CLI提供了--presets选项,可以将多个插件组合起来。

预定义配置 #

与插件相同,你可以自己创建一个预定义配置用于分享插件组合的配置。

官方早已为我们提供了@babel/preset-env这个预定义配置。

通过以下命令安装:

npm install --save-dev @babel/preset-env

or

yar add @babel/preset-env --dev

通过--presets选项指定使用预定义配置。

./node_modules/.bin/babel src --out-dir lib --presets=@babel/env

不需要我们设置其他的配置了,@babel/env包含了支持所有现代JavaScript(ES2015、ES2016等)的插件。预定义配置也支持选项配置,通过配置文件设置预定义配置的选项。

四.配置文件 #

首先,在项目目录下创建一个babel.config.json文件(需要v7.8.0和更高版本),并且添加如下内容:

{
    "presets": [
        [
            "@babel/env",
            {
                "targets": {
                "edge": "17",
                "firefox": "60",
                "chrome": "67",
                "safari": "11.1"
                }
            }
        ]
    ]
}

通过该配置文件,@babel/env将会只针对json文件中配置的targets的浏览器加载插件,如果某个现代JavaScript(ES2015、ES2016等)的语法在目标浏览器中不支持,执行babel转换时,将会加载对应的插件用于转换。

五.Polyfill #

我一直不知道如何翻译Polyfill这个单词,fill是填充的意思。poly在有道词典上的意思如下:

poly

n. (非正式)理工院校,工艺专科学校(polytechnic 的简称);聚乙烯(polythene 的简称);涤纶,聚酯纤维(polyester 的简称)

MDN术语表上的解释是:

Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。

我就将其翻译为预填充吧,主要作用是某些比较新的语法,浏览器还未来的及支持,使用预填充,可以让开发者不必考虑浏览器是否已经支持而直接使用新的语法。这里的语法与箭头函数和function关键字函数这种语法不一样,它指的是“功能”,例如PromiseWeakMapArray.from或者Object.assign等等。

我记得有一次项目,QQ浏览器不支持String.prototype.replaceAll方法,导致项目在QQ浏览器上运行出错,如果使用预填充功能,应该就可以解决问题。(感兴趣的朋友可以试试,目前QQ浏览器是否支持String.prototype.replaceAll方法)。

安装:

npm install --save @babel/polyfill

or

yarn add @babel/polyfill

注意: --save选项 这里是安装到生产依赖中的,不是开发依赖(细心一点)。

安装完成后,打开node_modules/@babel/polyfill/package.json文件,可以看到dependencies中有一个core-js包。

Babel入门教程

core-js是一个现代javascript语法库,@babel/polyfill就是利用core-js进行预填充的,你也可以直接从core-js中引入你需要的功能。

env预定义配置有一个"useBuiltIns"选项,如果设置为"usage"将会使用最新的功能进行预填充,在需要某个功能的模块文件里,会引入相应的功能。

{
    "presets": [
        [
        "@babel/env",
        {
            "targets": {
            "edge": "17",
            "firefox": "60",
            "chrome": "67",
            "safari": "11.1"
            },
            "useBuiltIns": "usage"
        }
        ]
    ]
}

假设你有如下代码:

Promise.resolve().finally();

使用babel转换后的代码如下:

"use strict";

require("core-js/modules/es7.promise.finally.js");

Promise.resolve().finally();

如果你没有设置"useBuiltIns": "usage",你需要设置"useBuiltIns": "entry",这样编译后的文件会在入口文件引入功能模块,如果不设置"useBuiltIns"选项,编译后的文件将不会引入任何新功能模块。

(完)

目录