babel-loader

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

本 README 适用于 Babel v7 配合 babel-loader v8/v9/v10 使用。如果您正在使用旧版 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
10.x^5.61.0^7.12.0 || ^8.0.0-alpha^18.20.0 || ^20.10.0 || >=22.0.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: {
          targets: "defaults",
          presets: [
            ['@babel/preset-env']
          ]
        }
      }
    }
  ]
}

选项

请参阅 babel 选项

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

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

此处传递的 options 将与 Babel 配置文件(例如 babel.config.js.babelrc合并

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

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

  • cacheIdentifier:默认是由 @babel/core 的版本和 babel-loader 的版本组成的字符串。最终的缓存 ID 将由输入文件路径、通过 Babel.loadPartialConfigAsync 合并的 Babel 配置以及 cacheIdentifier 确定。合并后的 Babel 配置将由 babel.config.js.babelrc 文件(如果存在)或环境变量 BABEL_ENVNODE_ENV 的值决定。cacheIdentifier 可以设置为自定义值,以在标识符更改时强制清除缓存。

  • cacheCompression:默认为 true。设置后,每个 Babel 转换输出都将用 Gzip 压缩。如果你想禁用缓存压缩,请将其设置为 false —— 如果你的项目转译数千个文件,这可能会有帮助。

  • customize:默认为 null。导出 custom 回调的模块路径,类似于你传递给 .custom() 的回调。由于你必须创建一个新文件才能使用此功能,因此建议你改为使用 .custom 来创建包装加载器。仅当你必须直接使用 babel-loader 但仍想自定义时才使用此功能。

  • metadataSubscribers:默认为 []。接受一个上下文函数名称数组。例如,如果你传递 ['myMetadataPlugin'],你将在你的 webpack 插件的钩子中将订阅函数分配给 context.myMetadataPlugin,并且该函数将使用 metadata 调用。有关示例,请参阅 https://github.com/babel/babel-loader/main/test/metadata.test.js

故障排除

启用调试模式日志记录

指定 webpack 选项 stats.loggingDebug 以输出详细的调试日志。

// webpack.config.js
module.exports = {
  // ...
  stats: {
    loggingDebug: ["babel-loader"]
  }
}

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 正在将 helper 注入到每个文件中并使我的代码膨胀!

Babel 为诸如 _extend 等常见函数使用非常小的 helper。默认情况下,这将被添加到每个需要它的文件中。

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

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

有关更多信息,请参阅文档

注意:你必须运行 npm install -D @babel/plugin-transform-runtime 将其包含在你的项目中,并运行 npm install @babel/runtime@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 和自定义 polyfills(例如 Promise 库)

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

// ...
        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 的 caller API 提供一个 target 属性。

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

// babel.config.js

module.exports = api => {
  return {
    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