babel-loader

免责声明:babel-loader 是由社区成员维护的第三方包,它可能没有与 webpack 相同的支持、安全策略或许可证,并且不受 webpack 维护。

此自述文件适用于使用 Babel v7 的 babel-loader v8/v9。如果您使用的是旧版 Babel v6,请参阅 7.x 分支 文档

NPM Status codecov

此包允许使用 Babelwebpack 转换 JavaScript 文件。

注意:输出问题应报告给 Babel Issues 跟踪器。

安装

babel-loader支持的 webpack 版本支持的 Babel 版本支持的 Node.js 版本
8.x4.x 或 5.x7.x>= 8.9
9.x5.x^7.12.0>= 14.15.0
npm install -D babel-loader @babel/core @babel/preset-env webpack

用法

webpack 文档:加载器

在 webpack 配置对象中,你需要将 babel-loader 添加到模块列表中,如下所示

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', { targets: "defaults" }]
          ]
        }
      }
    }
  ]
}

选项

请参阅 babel 选项

你可以使用 options 属性将选项传递给加载器

module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', { targets: "defaults" }]
          ],
          plugins: ['@babel/plugin-proposal-class-properties']
        }
      }
    }
  ]
}

此加载器还支持以下特定于加载器的选项

  • cacheDirectory:默认值为 false。设置后,将使用给定的目录来缓存加载器的结果。将来的 webpack 构建将尝试从缓存中读取,以避免在每次运行时都需要运行可能代价高昂的 Babel 重新编译过程。如果在选项中将值设置为 true{cacheDirectory: true}),则加载器将使用 node_modules/.cache/babel-loader 中的默认缓存目录,或者如果没有在任何根目录中找到 node_modules 文件夹,则回退到默认的操作系统临时文件目录。

  • cacheIdentifier:默认值是一个字符串,由 @babel/core 的版本、babel-loader 的版本、.babelrc 文件的内容(如果存在)以及环境变量 BABEL_ENV 的值(回退到 NODE_ENV 环境变量)组成。如果标识符发生更改,则可以将其设置为自定义值以强制清除缓存。

  • cacheCompression:默认值为 true。设置后,每个 Babel 转换输出都将使用 Gzip 压缩。如果你想退出缓存压缩,请将其设置为 false -- 如果你的项目编译了数千个文件,这可能会受益。

  • customize:默认值为 null。导出 custom 回调的模块的路径 类似于你传递给 .custom() 的路径。由于你已经必须创建一个新文件来使用它,因此建议你改为使用 .custom 来创建一个包装加载器。只有在你必须继续直接使用 babel-loader 但仍希望自定义时才使用此选项。

  • metadataSubscribers:默认值为 []。获取一个上下文函数名称数组。例如,如果你传递了 ['myMetadataPlugin'],则会在 webpack 插件的钩子中将订阅函数分配给 context.myMetadataPlugin,并且该函数将使用 metadata 调用。

故障排除

babel-loader 速度很慢!

确保您转换的文件尽可能少。因为您可能匹配 /\.m?js$/,您可能正在转换 node_modules 文件夹或其他不需要的源。

要排除 node_modules,请参阅上面记录的 loaders 配置中的 exclude 选项。

您还可以通过使用 cacheDirectory 选项将 babel-loader 的速度提高 2 倍。这将把转换缓存到文件系统。

我的 node_modules 中的一些文件未针对 IE 11 进行转换

虽然我们通常建议不要编译 node_modules,但当使用不支持 IE 11 或任何旧目标的库时,您可能需要这样做。

为此,您可以使用 testnot 的组合,或 传递函数 给您的 exclude 选项。您还可以使用负向前瞻正则表达式,如 此处 所建议。

{
    test: /\.(?:js|mjs|cjs)$/,
    exclude: {
      and: [/node_modules/], // Exclude libraries in node_modules ...
      not: [
        // Except for a few of them that needs to be transpiled because they use modern syntax
        /unfetch/,
        /d3-array|d3-scale/,
        /@hapi[\\/]joi-date/,
      ]
    },
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "ie 11" }]
        ]
      }
    }
  }

Babel 将助手注入到每个文件中并使我的代码膨胀!

Babel 使用非常小的助手来执行常见函数,例如 _extend。默认情况下,这将添加到需要它的每个文件中。

您还可以将 Babel 运行时作为一个单独的模块来避免重复。

以下配置禁用了 Babel 中的自动逐文件运行时注入,而是需要 @babel/plugin-transform-runtime 并使所有助手引用使用它。

请参阅 文档 了解更多信息。

注意:您必须运行 npm install -D @babel/plugin-transform-runtime 以将其包含在您的项目中,并将 @babel/runtime 本身作为依赖项与 npm install @babel/runtime 一起安装。

rules: [
  // the 'transform-runtime' plugin tells Babel to
  // require the runtime instead of inlining it.
  {
    test: /\.(?:js|mjs|cjs)$/,
    exclude: /node_modules/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { targets: "defaults" }]
        ],
        plugins: ['@babel/plugin-transform-runtime']
      }
    }
  }
]

注意:transform-runtime 和自定义 polyfill(例如 Promise 库)

由于 @babel/plugin-transform-runtime 包含一个多态填充,其中包括一个自定义 regenerator-runtimecore-js,因此使用 webpack.ProvidePlugin 的以下常见垫片方法将不起作用

// ...
        new webpack.ProvidePlugin({
            'Promise': 'bluebird'
        }),
// ...

以下方法也不起作用

require('@babel/runtime/core-js/promise').default = require('bluebird');

var promise = new Promise;

输出到(使用 runtime

'use strict';

var _Promise = require('@babel/runtime/core-js/promise')['default'];

require('@babel/runtime/core-js/promise')['default'] = require('bluebird');

var promise = new _Promise();

在覆盖之前的 Promise 库被引用和使用。

一种方法是在应用程序中有一个“引导”步骤,该步骤将在应用程序之前覆盖默认全局变量

// bootstrap.js

require('@babel/runtime/core-js/promise').default = require('bluebird');

// ...

require('./app');

babel 的 Node.js API 已移至 babel-core

如果您收到此消息,则表示您已安装 npm 包 babel,并且在 webpack 配置中使用加载器的简短表示法(在 webpack 2.x 中不再有效)

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel',
  }

然后,webpack 尝试加载 babel 包而不是 babel-loader

要解决此问题,您应该卸载 npm 包 babel,因为它在 Babel v6 中已弃用。(相反,安装 @babel/cli@babel/core。)如果您的某个依赖项正在安装 babel,并且您无法自行卸载它,请在 webpack 配置中使用加载器的完整名称

  {
    test: /\.(?:js|mjs|cjs)$/,
    loader: 'babel-loader',
  }

排除不应转换的库

如果 core-jswebpack/buildin 被 Babel 转换,将导致错误。

您需要将它们从 babel-loader 中排除。

{
  "loader": "babel-loader",
  "options": {
    "exclude": [
      // \\ for Windows, / for macOS and Linux
      /node_modules[\\/]core-js/,
      /node_modules[\\/]webpack[\\/]buildin/,
    ],
    "presets": [
      "@babel/preset-env"
    ]
  }
}

顶级函数 (IIFE) 在 Webpack 5 中仍然是箭头

该函数是由 Webpack 本身在运行 babel-loader 之后注入的。默认情况下,Webpack 假设您的目标环境支持一些 ES2015 功能,但您可以使用 output.environment Webpack 选项(文档)覆盖此行为。

要避免顶级箭头函数,可以使用 output.environment.arrowFunction

// webpack.config.js
module.exports = {
  // ...
  output: {
    // ...
    environment: {
      // ...
      arrowFunction: false, // <-- this line does the trick
    },
  },
};

根据 webpack 目标自定义配置

Webpack 支持捆绑多个目标。对于希望为每个目标(如webnode)使用不同的 Babel 配置的情况,此加载器通过 Babel 的调用者API 提供了一个target属性。

例如,要根据 webpack 目标更改传递给@babel/preset-env的环境目标

// babel.config.js

module.exports = api => {
  return {
    plugins: [
      "@babel/plugin-proposal-nullish-coalescing-operator",
      "@babel/plugin-proposal-optional-chaining"
    ],
    presets: [
      [
        "@babel/preset-env",
        {
          useBuiltIns: "entry",
          // caller.target will be the same as the target option from webpack
          targets: api.caller(caller => caller && caller.target === "node")
            ? { node: "current" }
            : { chrome: "58", ie: "11" }
        }
      ]
    ]
  }
}

自定义加载器

babel-loader公开了一个加载器构建器实用程序,允许用户为它处理的每个文件添加对 Babel 配置的自定义处理。

.custom接受一个回调,该回调将使用加载器的babel实例进行调用,以便工具可以确保它使用与加载器本身完全相同的@babel/core实例。

在希望自定义但实际上没有文件来调用.custom的情况下,还可以传递customize选项,其中包含一个指向导出custom回调函数的文件的字符串。

示例

// Export from "./my-custom-loader.js" or whatever you want.
module.exports = require("babel-loader").custom(babel => {
  // Extract the custom options in the custom plugin
  function myPlugin(api, { opt1, opt2 }) {
    return {
      visitor: {},
    };
  }

  return {
    // Passed the loader options.
    customOptions({ opt1, opt2, ...loader }) {
      return {
        // Pull out any custom options that the loader might have.
        custom: { opt1, opt2 },

        // Pass the options back with the two custom options removed.
        loader,
      };
    },

    // Passed Babel's 'PartialConfig' object.
    config(cfg, { customOptions }) {
      if (cfg.hasFilesystemConfig()) {
        // Use the normal config
        return cfg.options;
      }

      return {
        ...cfg.options,
        plugins: [
          ...(cfg.options.plugins || []),

          // Include a custom plugin in the options and passing it the customOptions object.
          [myPlugin, customOptions],
        ],
      };
    },

    result(result) {
      return {
        ...result,
        code: result.code + "\n// Generated by some custom loader",
      };
    },
  };
});
// And in your Webpack config
module.exports = {
  // ..
  module: {
    rules: [{
      // ...
      loader: path.join(__dirname, 'my-custom-loader.js'),
      // ...
    }]
  }
};

customOptions(options: Object): { custom: Object, loader: Object }

根据加载器的选项,将自定义选项从babel-loader的选项中分离出来。

config(cfg: PartialConfig, options: { source, customOptions }): Object

根据 Babel 的PartialConfig对象,返回应传递给babel.transformoptions对象。

result(result: Result): Result

根据 Babel 的结果对象,允许加载器对其进行额外的调整。

许可证

MIT