# Babel 转化

提示

本节内容紧接着上节 Babel

代码向后兼容其实分为两种兼容,一种是 语法转化、一种是 API 垫片(Shim)。上节内容是简单的对单文件使用了语法转化。本节内容利用 Babel 搭配 Webpack 使用两种兼容方式。

# 语法转化

我们是通过 Webpack 打包整体代码的,在此之前需要用 Babel 对代码进行转化。这样我们就需要 babel-loader (opens new window) 这个 Webpack 转化器,其实就是 Webpack 为了更好的使用 Babel 而包装的转化器。你也可以不安装,自己写一个内部使用 Babel 的 loader。

# 安装
npm install babel-loader --save-dev
1
2

修改 build.js 打包配置,将 babel-loader 添加至 module.rules。配置将继续采用传入的方式,你也可以创建配置文件。
























 
 
 
 
 
 
 
 
 
 
 
 
 
 















// build.js
// build.js
var path = require("path");
var webpack = require("webpack");

webpack(
  {
    // 需要设置 production,自动开启代码优化功能
    // 或设置以下 optimization 手动开启代码优化功能
    mode: "none", // 方便查看产物的代码,可以临时设置 none
    // 入口
    entry: "./src/index.js",
    // 输出
    output: {
      filename: "library.js",
      path: path.resolve(__dirname, "dist"),
      library: {
        name: "library",
        type: "umd",
      },
    },
    target: ["web", "es5"],
    module: {
      rules: [
        {
          test: /\.m?js$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            // 传入配置方式 或者 创建配置文件
            options: {
              presets: ["@babel/preset-env"],
            },
          },
        },
      ],
    },
    // optimization: {
    //   usedExports: true,
    //   minimize: true,
    //   concatenateModules: true,
    // },
  },
  (err, stats) => {
    if (err || stats.hasErrors()) {
      // 这里处理错误
      console.log(err, stats);
    }
    // 处理完成
  }
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

运行 node build.js,重新查看产物,可以发现字符串模板、箭头函数、awaitasyncconst 均做了转化。String.prototype.includesPromise 均为未转化。下面 API 转化 将会解决该问题,本小节不做处理。

重新在浏览器运行,发现连 Chrome 都无法运行了。并且抛出 regeneratorRuntime is not defined 错误。这是由于我们使用了 ES8 的 awaitasync的语法糖,其本质就是 Generator 函数。Babel 是通过引入一个辅助函数来实现转化的,Babel 默认我们已经引入了,但我们是没有引入的,才导致该错误。

根据 Babel-简单的使用 小节的提示,我们知道有两种方式。当前我们先使用第一种:在打包的入口文件引入 regenerator-runtime/runtime。第二种将在 Babel 优化-避免全局污染和重复辅助函数 小节介绍。


 






// src/index.js
import "regenerator-runtime/runtime";
import { browser } from "./browser";
import { getRandomInt } from "./util";
import { createBackgroudImg, createRandomTextElement } from "./element";

export { browser, getRandomInt, createBackgroudImg, createRandomTextElement };
1
2
3
4
5
6
7

重新运行 node build.js,发现在 Chrome 已经可以运行,而 IE 控制台抛出 对象不支持“includes”属性或方法 的异常。这个将在下方 API 转化 小节解决。

# API 转化

默认情况下 @babel/preset-env 是不会转化 API 的,例如新的内置函数 PromiseWeakMap,静态方法 Array.fromObject.assgin、实例方法 Array.prototype.includesGenerator 函数等的。官网提供了 @babel/polyfill (其实就是 core-jsregenerator-runtime/runtime) 来解决改该问题,为你的代码中提供垫片。

注意

从 Babel 7.4.0 起,@babel/polyfill 将替换成 core-jsregenerator-runtime/runtime官方提示 (opens new window)

我们将安装 core-js@3core-js@2 从 2018 年开始就功能冻结,所有新功能只添加到 core-js@3 中。详见 (opens new window)

# 安装 core-js@3,采用
npm install core-js@3 --save
# 安装 core-js@2,不建议
npm install core-js@2 --save
1
2
3
4

在打包的入口文件引入 core-js/stable

提示

这里使用的是 stable 标准已稳定的垫片,如果有需要请使用 core-js 下的具体路径垫片。


 







// src/index.js
import "core-js/stable";
import "regenerator-runtime/runtime";
import { browser } from "./browser";
import { getRandomInt } from "./util";
import { createBackgroudImg, createRandomTextElement } from "./element";

export { browser, getRandomInt, createBackgroudImg, createRandomTextElement };
1
2
3
4
5
6
7
8

运行 node build.js,打开 index.html。Chrome 和 IE 均运行正常,说明 Babel 的垫片起效果了。