理解现代 Web 技术栈:Babel

2025-06-08

理解现代 Web 技术栈:Babel

版本信息和存储库

(本教程使用Babel v7编写,但一般概念适用于任何版本)

您可以在此处找到“了解现代 Web 堆栈”教程系列的官方存储库

这包含每个教程代码示例的最终版本,以确保您没有遗漏任何内容。您也可以提交 Pull 请求,以纠正您发现的任何错误或更正(我会相应地更新博客文章)。

目录

  1. Babel 是什么
  2. 先决条件
  3. 初始化项目
  4. 安装 Babel
  5. 转换你的代码
  6. Polyfills
  7. 总结

Babel 是什么?

Babel 是一款工具,它允许您使用所有最新的语法和功能编写 JavaScript 代码,并在可能不支持这些功能的浏览器中运行。Babel 是一个转译器,可以将您当前的 JS 代码转换为更多浏览器能够理解的旧版 JavaScript 代码。

Babel 通常内置于我们日常构建现代 Web 应用程序的工具中(例如create-react-app),因此许多开发者并不完全了解该工具的实际功能。本教程旨在逐步讲解 Babel 的配置,它是构建自定义开发环境系列教程的一部分。

先决条件

你需要在你的机器上安装Node.js并可以在终端中使用。安装 Node的同时会自动安装npm ,而 npm 正是你安装 Babel 时使用的。

打开你选择的终端。如果你在运行以下两个命令时看到版本号(你的版本号可能与本例不同),那么你就可以开始了:

node --version
> v15.5.0

npm --version
> 7.16.0
Enter fullscreen mode Exit fullscreen mode

初始化项目

让我们从初始化一个新npm项目开始。运行以下命令来生成一个:

npm init -y
Enter fullscreen mode Exit fullscreen mode

-y标志将自动为所有内容选择默认值,这在我们的示例中是合适的。

接下来,让我们使用一些现代语法创建一个非常基本的 Javascript 文件。script.js使用以下代码创建一个名为 的文件:

script.js

const x = 5;
let y;

const sampleFunction = () => "this is a return value";

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const hasThree = [1, 2, 3].includes(3);
console.log(hasThree);

y ||= "a new value";
console.log(y);
Enter fullscreen mode Exit fullscreen mode

在上面的例子中const,,,let数组方法和都是ES6arrow function的功能,它们无法在旧版浏览器中正常运行,例如(不幸的是,即使在 2021 年,一些组织仍在广泛使用这些浏览器)。includesclassInternet Explorer 11

您可能还会遇到全新的(截至 2021 年)逻辑或赋值。它无法在 Firefox 79 之前的版本和 Chrome 85 之前的版本中运行,并且根本无法在 IE11 中运行。

那么,我们怎样做才能在旧版浏览器上运行此代码,而不必自己重写它呢?

安装 Babel

为了实现我们的目标,我们需要三个基本软件包,它们都是 Babel 生态系统的一部分,但每个都有不同的功能。首先运行以下命令:

npm install @babel/core @babel/cli @babel/preset-env --save-dev
Enter fullscreen mode Exit fullscreen mode

让我们看看每个人在做什么:

  • @babel/core- 这是主引擎,它知道如何根据给定的一组指令转换代码
  • @babel/cli- 这是我们将要运行的实际程序,用于触发核心引擎并输出转换后的 Javascript 文件
  • @babel/preset-env- 这是一个预设,用于告诉核心引擎需要进行哪些类型的转换。它会package.json根据您希望支持的浏览器,检查您的环境(在我们的例子中是我们的配置文件)来确定需要进行哪些类型的更改。

我们需要在文件中添加几个值package.json

  • browserslist- 这告诉 Babel 我们的目标浏览器是哪些。浏览器越老/支持越少,Babel 就需要做越多的工作和转换才能让你的应用程序在这些浏览器中正常工作。语法是一个简单的字符串数组。你可以在这里了解更多
  • babel- 我们在这里定义了所有要使用的预设,以及与这些预设相关的配置选项。我们将从最简单的一个开始,@babel/preset-env

所以我们的package.json文件应该是这样的:

package.json

{
  "devDependencies": {
    "@babel/cli": "^7.15.7",
    "@babel/core": "^7.15.5",
    "@babel/preset-env": "^7.15.6"
  },
  "browserslist": ["last 2 Chrome versions"],
  "babel": {
    "presets": [["@babel/preset-env"]]
  }
}
Enter fullscreen mode Exit fullscreen mode

您的应该devDependencies已经存在了npm install。上面描述的另外两个属性需要您自行添加。

转换你的代码

其最基本的配置babel将把您的现代语法转换为更广泛支持的ES5

package.json让我们从一个简单的例子开始。在包含你的文件和文件的项目根目录中运行以下命令script.js

npx babel script.js --out-file script-transformed.js
Enter fullscreen mode Exit fullscreen mode

假设您已经遵循了到目前为止的所有说明,您应该会看到一个名为 的新文件,script-transformed.js如下所示:

script-transformed.js

"use strict";

const x = 5;
let y;

const sampleFunction = () => "this is a return value";

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const hasThree = [1, 2, 3].includes(3);
console.log(hasThree);
y ||= "a new value";
console.log(y);
Enter fullscreen mode Exit fullscreen mode

没什么区别吧?除了添加严格模式之外,实际上没有任何变化。

原因在于我们如何在中配置我们的环境package.json,这就是@babel/preset-env我们决定应该做什么的地方。

package.json

...
"browserslist": [
  "last 2 Chrome versions"
],
...
Enter fullscreen mode Exit fullscreen mode

由于我们仅针对最新的 2 个版本的 Chrome,因此 Babel 知道我们可以毫无问题地包含我们想要的所有现代 JS 语法,它将在这些现代浏览器中正常运行。

但是假设我们需要支持Internet Explorer 11。我们不想仅仅为了适应那个浏览器而改变代码编写方式,幸运的是,Babel 帮了大忙。更新你的package.json代码,将 IE11 添加到browserslist数组中:

...
"browserslist": [
  "last 2 Chrome versions",
  "IE 11"
],
...
Enter fullscreen mode Exit fullscreen mode

现在再次运行此命令:

npx babel script.js --out-file script-transformed.js
Enter fullscreen mode Exit fullscreen mode

看看这次的输出:

script-transformed.js

"use strict";

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var x = 5;
var y;

var sampleFunction = function sampleFunction() {
  return "this is a return value";
};

var Person = function Person(name, age) {
  _classCallCheck(this, Person);

  this.name = name;
  this.age = age;
};

var hasThree = [1, 2, 3].includes(3);
console.log(hasThree);
y || (y = "a new value");
console.log(y);
Enter fullscreen mode Exit fullscreen mode

这看起来和我们的原始文件大相径庭!注意,ES6我们上面讨论的几乎所有术语都消失了,const被替换为var,箭头函数被替换为function语法,并且我们的class已经转换为一个基本的Javascript对象。现在我们可以把这个script-transformed.js文件上传到服务器,Internet Explorer 11它就可以正常运行了……差不多了!

我们还有一个小问题:includes方法没有被转换。为什么呢?要理解原因,我们首先需要理解polyfills

Polyfills

要理解为什么我们需要,我们必须理解什么是新的和什么是新的polyfills之间的区别方法是新的。它背后有自己的逻辑,简单地改变代码的语法并不能向老版本的浏览器解释该方法的逻辑应该如何运行。syntaxfunctionalityincludesfunctionalityincludes

对于引入新功能的新功能,我们需要一个叫做polyfill的东西。polyfill 只是一些方法的源代码,includes你可以将它与应用程序捆绑在一起,以便教会旧版浏览器如何使用它。

您无需自行编写 polyfill,几乎所有 JS 功能的 polyfill 都已存在,并且易于添加。在后续的教程中,我们将讲解如何打包并仅添加我们需要的特定功能,但在此之前,我们只需添加一个名为core-js的库,即可立即让我们的应用访问所有现代 JS 功能,即使在旧版浏览器上也是如此。

为了测试一下,我们将整个库加载core-js到我们的应用中。由于我们还没有使用打包器,所以我们只需minified从 Web 加载已经打包好的版本即可。如果您还没有index.html模板,请在项目根目录中创建此文件:

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <script src="script-transformed.js"></script>
  </head>
  <body></body>
</html>
Enter fullscreen mode Exit fullscreen mode

(如果您不确定如何提供此文件,请先运行并查看输出,查看本教程

我们首先尝试在 IE11 中加载该文件。如果您的机器没有安装 Internet Explorer 11,可以直接按照此处的示例操作。此示例在Windows 11已完全移除 IE11 的浏览器中运行。幸运的是, IE 11Microsoft Edge附带了IE 11 模式,可用于测试需要向后兼容的应用程序。

当我们运行 Babel 并尝试在 IE11 中加载我们的script-transformed.js文件时,我们在控制台上收到以下错误:

数组包含错误

现在,让我们将core-js库添加到我们的 中的<script>标签中。您可以在此处找到最新的最小化包 URL <head>index.html

index.html

...
<head>
  <meta charset="UTF-8" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.1/minified.js"></script>
  <script src="script-transformed.js" defer></script>
</head>
...
Enter fullscreen mode Exit fullscreen mode

当我们在 IE11 中重新加载页面时,我们得到:

数组包含示例

成功了!我们正在编写现代 JavaScript,并在一个老旧的浏览器中运行它!太棒了!

总结

现在你应该已经扎实掌握了 Babel 的基本概念及其工作原理。当然,还有更多内容有待探索。在未来的教程中,我们将深入探讨 Babel 支持的另外两个用于转译 JavaScript 超集的主要预设:JSXTypescript

当我们开始使用时,webpack我们还将研究如何配置 Babel,以便它仅从core-js您在应用程序中实际使用的大型库(如Array.includes())中导入那些函数,这样您就不需要包含整个库本身。

请查看本系列的其他文章!如果您觉得其中任何一篇有帮助,欢迎留言或提问,并与他人分享:

Twitter 上的@eagleson_alex

感谢您的阅读,敬请期待!

鏂囩珷鏉ユ簮锛�https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp
PREV
如何构建全栈 Next.js 应用(使用 Storybook 和 TailwindCSS)
NEXT
JavaScript 中的 WeakMap - 简单介绍