加载 JavaScript

Webpack 默认处理 ES2015 模块并将其转换为代码。但它不会转换特定语法,例如 const。生成的代码可能会出现问题,尤其是在旧版浏览器中。

如果想要了解默认转换,请观察下面例子的输出(npm run build -- --devtool false --mode development):

dist/main.js

...
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = ((text = "Hello world") => {
  const element = document.createElement("div");

  element.className = "pure-button";
  element.innerHTML = text;

  return element;
});
...

通过 Babel 编译代码可以解决这个问题,Babel 是一个支持 ES2015 + 语法的著名 JavaScript 编译器。类似于ESLint,它建立在预设和插件之上。预设是插件的集合,您也可以定义自己的插件。

鉴于扩展现有预设时的局限性,modify-babel-preset 允许您基于一个基本预设来进行灵活的扩展。

配置 Webpack 使用 Babel

尽管 Babel 可以单独使用,但您也可以将它与 Webpack 连接起来。在开发过程中,如果您使用的浏览器支持的语言特性,则跳过处理。

如果您不依赖任何自定义语言特性并使用现代浏览器工作,则跳过处理是一个不错的选择。但是,在编译生产代码时,通过 Babel 处理几乎是必需的。

你可以通过 babel-loader 在 Webpack 中使用 babel。它可以获取项目级别的 Babel 配置,或者您可以在 webpack loader 本身进行配置。babel-webpack-plugin 是另一个鲜为人知的选择。

您可以使用 babel 来编译项目的 Webpack 配置。要实现此目的,请使用 webpack.config.babel.js 来命名 Webpack 配置。interpret 包使用了这种方式,它也支持其他编译器。

鉴于 Node 现在支持 ES2015 规范,您可以使用许多 ES2015 语法特性,而无需通过 Babel 处理配置。

如果您使用 webpack.config.babel.js,请注意设置 "modules": false。如果要使用 ES2015 模块语法,您可以跳过 Babel 全局配置中的设置,然后按照下面的讨论为每个环境进行单独配置。

配置 babel-loader

配置 Babel 的第一步是设置 babel-loader,它将现有的代码转换为旧浏览器可以理解的格式。首先,我们安装 babel-loader 及其依赖项 @ babel/core

npm install babel-loader @babel/core --save-dev

像往常一样,让我们​​为 Babel 定义一个配置函数:

webpack.parts.js

exports.loadJavaScript = ({ include, exclude } = {}) => ({
  module: {
    rules: [
      {
        test: /\.js$/,
        include,
        exclude,
        use: "babel-loader",
      },
    ],
  },
});

接下来,您需要将其合并到主配置。如果您使用现代浏览器进行开发,则可以考虑仅仅通过 Babel 编译生产环境的代码。下面的配置中,它用于生产和开发环境。并且,只有应用程序代码通过 Babel 处理。

调整如下:

webpack.config.js

const commonConfig = merge([
  ...

  parts.loadJavaScript({ include: PATHS.app }),

]);

即使您安装了 Babel 并进行了 Webpack 配置,您仍然缺少一点:Babel 配置。可以使用 .babelrc 设置 Babel 配置,因为其他工具可以使用这个文件。

如果您尝试导入配置根目录之外的文件,然后通过 babel-loader 编译它们,则会失败。这是一个已知的问题,有一些解决方法,包括在项目的目录的更外层维护_.babelrc_,并通过配置 Webpack require.resolve 来解析 Babel 的预设。

设置 .babelrc

你需要 @babel/preset-env,它是一个 Babel 预设,可根据您传递给它的选项来确定要启用的插件。

首先,安装这个包:

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

要让 Babel 找到这个预设,你需要写一个 .babelrc 。鉴于 Webpack 支持开箱即用的 ES2015 模块,您可以告诉 Babel 跳过处理它们。跳过这一步将破坏Webpack 的 HMR 机制,尽管生产构建仍然有效。您还可以将构建的代码限制为仅在最新版本的 Chrome 中有效。

你可以按照 browserslist 来调整配置,以期达到目标浏览器的兼容性要求,下面是一个配置的例子:

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
      }
    ]
  ]
}

如果你运行 npm run build -- --devtool false --mode development,然后检查 dist/main.js,你会看到一些不一样的东西,它们是根据 .browserslistrc 生成的。

尝试只包含 IE 8,代码应该相应地改变:

dist/main.js

...
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = (function () {
  var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "Hello world";

  var element = document.createElement("div");

  element.className = "pure-button";
  element.innerHTML = text;

  return element;
});
...

特别注意函数是如何转换的。您可以尝试启用不同的浏览器和语言特性,以查看输出是如何相应第改变的。

Polyfilling 功能

@ babel/preset-env 允许您为旧版浏览器支持某些语言特性。为此,您应该启用其 useBuiltIns 选项(设置 "useBuiltIns": true"useBuiltIns": "usage")并安装 @babel/polyfill。您必须通过 import 或 entry(app: ["@babel/polyfill", PATHS.app])将其包含在项目中。@babel/preset-env 根据您选定的浏览器重写导入,并仅加载所需要的 polyfill。

@babel/polyfill 会在全局范围内提供了像 PromiseSet 这样的对象,这会污染全局作用域,对于一些库的开发者来说这可能会造成影响,这时候可以使用 @babel/plugin-transform-runtime 。它可以作为 Babel 插件启用,避免了全局变量污染的问题。

某些 Webpack 功能,例如 代码拆分,可以在 loader 运行之后,在 Webpack 启动代码部分写入 Promise,在执行应用程序代码之前运行垫片程序,从而解决这个问题。示例:entry: { app: ["core-js/es/promise", PATHS.app] }

Babel 小技巧

除了 .babelrc 中介绍的技巧以外,还有很多其他的功能,类似 ESLint,.babelrc 支持 JSON5 作为其配置格式,这意味着您可以在 JSON 配置中包含注释,使用单引号字符串等。

有时您希望在项目中使用一些实验性功能,虽然你可以在一些所谓的 stage 预设中找到它们,但最好逐个启用,甚至将它们组织成自己的预设,除非你正在进行一次性项目。如果您希望项目能够存活很长时间,那么最好记录您正在使用的功能。

Babel 并不是唯一的选择,尽管它是最受欢迎的选择。Rich Harris 的 Buble 是另一个值得一试的编译器。有一个实验性质的 buble-loader,允许你在 Webpack 中使用它。Buble 不支持 ES2015 模块,但这不是问题,因为Webpack 提供了这种功能。

Babel 插件

Babel 最棒的事情可能就是可以使用插件对其进行扩展:

可以通过 babel-registerbabel-cli 将 Babel 与 Node 连接起来。如果您想在不使用 Webpack 的情况下通过 Babel 编译代码,这些包会很方便。

在每个环境中启用预设和插件

Babel 允许您通过其 env 选项 控制每个环境使用哪些预设和插件。您可以通过这种方式管理不同构建目标时 Babel 的行为。

env 检查 NODE_ENVBABEL_ENV,并基于此来执行构建。如果设置了BABEL_ENV,它将覆盖 NODE_ENV

考虑下面的例子:

.babelrc

{
  ...
  "env": {
    "development": {
      "plugins": [
        "annotate-console-log"
      ]
    }
  }
}

我们在开发环境中启用了 annotate-console-log 插件,env 允许您精细化地配置 Babel。

我们还可以将 Webpack 环境参数传递给 Babel:

webpack.config.js

module.exports = mode => {

  process.env.BABEL_ENV = mode;


  ...
};

env 的工作方式很微妙,设置好 env 并确保它与您的 Babel 配置匹配,否则 Babel 可能不会按照你的期望进行打包。

设置 TypeScript

Microsoft 的 TypeScript 是一种需要编译的语言,遵循与 Babel 类似的设置。与 JavaScript 不同的是,它具备强类型。这样,一个好的 IDE 可以更好的提示,提高编码体验。强类型对于开发来说是很有意义的,因为它比较清晰地约束了变量的类型。

与 Facebook 的类型检查器 Flow 相比,TypeScript 是一种更安全的选择。因为,它的预定义类型比较多,总体上的维护质量也更好。

您可以使用以下 loader 将T ypeScript 与 Webpack 一起使用:

ESLint 有一个 TypeScript 解析器。你也可以通过 tslint 来 lint ts 代码。

设置 Flow

Flow 根据您的代码及其类型声明执行静态分析。您必须将其作为单独的工具安装,然后把它应用在你的代码上。有一个 flow-status-webpack-plugin,允许你在开发过程中通过 Webpack 运行它。

如果您使用 React,则 React 特定的 Babel 预设 babel-plugin-syntax-flow 可以完成大部分工作。它可以删除代码中的 Flow 声明并将您的代码转换为可以进一步转换的格式。

还有 babel-plugin-typecheck,允许您根据 Flow 声明执行运行时检查。flow-runtime 进一步发展并提供更多的功能。这些方法补充了 Flow 静态检查程序,使您可以捕获更多问题。

flow-coverage-report 显示了你的代码中 Flow 声明的覆盖情况。

总结

Babel 已经成为开发人员不可或缺的工具,因为它使旧版浏览器也能使用较新的 JavaScript 语法。即使您针对的是现代浏览器,通过 Babel 进行转换也是一种不错的选择。

回顾一下:

  • Babel 让您可以控制要支持的浏览器。它可以将 ES2015+ 语法特性编译为旧浏览器所理解的形式。babel-preset-env 很有价值,因为它可以根据您的浏览器定义选择要编译的语法以及要启用的 polyfill。
  • Babel 允许您使用实验语法特性。您可以找到许多插件,通过优化改善开发体验和生产构建。
  • 可以为每个环境启用 Babel 功能。这样您就可以确保在正确的位置使用正确的插件。
  • 除了 Babel 之外,Webpack 还支持 TypeScript 或 Flow 等其他解决方案。Flow 可以补充 Babel,而 TypeScript 可以整体上编译为 JavaScript。
用户头像
登录后发表评论