babel 7.4 配置文件(翻译)

1,858 阅读10分钟

附文:一文读懂 babel7 的配置文件加载逻辑 blog.csdn.net/weixin_3419…

配置文件

配置文件类型

babel有两种并行配置文件格式,可以一起使用,也可以独立使用。

  • 项目范围配置
  • 文件相对配置
    • .babelrc(和.babelrc.js)文件
    • 带有“babel”键的package.json文件

项目范围配置

在babel 7.x中,babel有一个“根”目录的概念,默认为当前的工作目录。. 对于项目范围的配置,babel将自动在这个根目录中搜索“babel.config.js”。或者,用户可以使用显式的“config file”值来覆盖默认的配置文件搜索行为。

由于项目范围内的配置文件与配置文件的物理位置分离,因此它们非常适合必须广泛应用的配置,甚至允许插件和预设轻松应用于节点模块或符号链接包中的文件,传统上,这些配置对于在Babel6.x中配置。 这个项目范围配置的主要缺点是,因为它依赖于工作目录,所以如果工作目录不是monorepo根目录,那么在monorepo中使用它可能会更痛苦。有关如何在该上下文中使用配置文件的示例,请参阅monorepo文档。

通过将“configfile”设置为false,还可以禁用项目范围的配置。

文件相对配置

babel通过从正在编译的“文件名”开始搜索目录结构来加载.babelrc(和.babelrc.js/package.json_babel)文件(受以下注意事项限制)。 这可能很强大, 因为它允许您为包的子部分创建独立的配置。文件相关配置也在项目范围的配置值的顶部进行合并,这使得它们对于特定的覆盖可能有用,尽管也可以通过“覆盖”来实现。 一旦找到包含package.json的目录,搜索将停止,因此相对配置仅适用于单个包。 在编译的“文件名”必须在“babelrcroots”包中,否则将完全跳过搜索。

这些注意事项意味着: .babelrc文件仅适用于自己包中的文件 除非您选择“babelrc root s”,否则将忽略不属于babel“root”的包中的.babelrc文件。 有关如何配置具有多个包的monorepo的更多讨论,请参阅monorepo文档。 通过将“babelrc”设置为false,也可以禁用文件相对配置。

6.x与7.x.babelrc加载

来自Babel6.x的用户可能会遇到这两个边缘案例,这在Babel7.x中是新的。这两个限制是为了解决Babel6.x中的常见问题而增加的:

  • .babelrc文件应用于节点模块依赖项,通常是意外的。
  • .babelrc文件无法应用于符号链接节点_模块,因为人们希望它们的行为类似于正常的依赖项。 节点模块依赖项中的.babelrc文件将被检测到,即使它们内部的插件和预设通常没有安装,甚至可能在编译该文件的babel版本中无效。 这些情况将主要导致Monorepo结构的用户出现问题,因为如果 .babelrc packages/ mod1/ package.json src/index.js mod2/ package.json src/index.js

配置现在将被完全忽略,因为它跨越包边界。 另一种选择是在每个使用“extends”作为 { "extends": "../../.babelrc" }

不幸的是,这种方法可能有点重复,并且根据Babel的使用方式,可能需要设置“babelrcRoots”。 鉴于此,将.babelrc重命名为项目范围的“babel.config.js”可能更为可取。正如上面的项目范围部分所提到的,这可能需要显式设置“config file”,因为如果工作目录不正确,babel将找不到配置文件。

Monorepo

Monorepo结构化存储库通常包含许多包,这意味着它们经常遇到文件相关配置和配置文件加载中提到的警告。本节旨在帮助用户了解如何处理Monorepo配置。 对于monorepo设置,要理解的核心是babel将您的工作目录视为其逻辑“根”,如果您希望在特定的子包中运行babel工具,而不将babel作为一个整体应用于repo,则会导致问题。 另外,决定是使用.babelrc文件还是只使用中心babel.config.js也很重要。子文件夹特定配置不需要.babelrc文件,就像在babel 6中一样,因此在babel 7中通常不需要这些文件,而需要babel.config.js。

根babel.config.js文件

任何monorepo结构的第一步都应该是在repository根目录中创建babel.config.js文件。这就建立了babel对存储库基本目录的核心概念。即使您想使用.babelrc文件来配置每个单独的包,也必须将其作为repo级别选项的位置。 您通常可以将所有repo配置放在根babel.config.js中。使用“overrides”,您可以轻松地指定仅适用于存储库的某些子文件夹的配置,这通常比在repo中创建许多.babelrc文件更容易执行。 您可能会遇到的第一个问题是,默认情况下,babel期望从目录集中加载babel.config.js文件作为其“根”,这意味着如果创建babel.config.js,但在单个包中运行babel,例如。

cd packages/some-package; babel src -d dist

在这种情况下,babel使用的“根”不是monorepo根,它将无法找到babel.config.js文件。 如果所有的构建脚本都是相对于存储库根运行的,那么事情应该已经开始了,但是如果您是在子包中运行babel编译过程,那么您需要告诉babel在哪里查找配置。有几种方法可以做到这一点,但推荐的方法是“向上”的“rootmode”选项,它将使babel从工作目录向上搜索babel.config.js文件,并将其位置用作“根”值。 测试配置是否被检测到的一个有用方法是在其中放置一个console.log()调用。因为它是一个JS文件,所以日志将在babel第一次加载它时执行。 您如何设置此值因项目而异,但以下是几个示例: CLI babel --root-mode upward src -d lib

@babel/register require("@babel/register")({ rootMode: "upward" });

Webpack module: { rules: [{ loader: "babel-loader", options: { rootMode: "upward", } }] }

Jest

jest通常安装在monorepo的根目录下,可能不需要配置,但是如果每个包都安装了它,那么不幸的是配置起来可能更复杂。 主要部分是创建一个自定义的jest transformer文件,该文件包装babel jest的默认行为,以便设置选项,例如。 module.exports = require("babel-jest").createTransformer({ rootMode: "upward", });

保存到某个地方后,您将通过转换选项在jest选项中使用该文件代替babel jest: "transform": { "^.+\.jsx?$": "./path/to/wrapper.js" },

因此,所有JS文件都将使用您的babel jest版本处理,并启用选项。

其他: 有很多工具,但其核心是,如果工作目录还不是monorepo根目录,那么它们需要启用rootmode选项。

子包.babelrc文件

与babel.config.js文件必须位于“根”中的方式类似,默认情况下.babelrc文件必须位于根包中。这意味着,与工作目录影响babel.config.js加载的方式相同,它也影响.babelrc加载。 假设您已经像上面讨论的那样正确加载了babel.config.js文件,babel将只处理根包中的.babelrc文件(而不是子包),例如package.json babel.config.js packages/ mod/ package.json .babelrc index.js

编译packages/mod/index.js文件将不会加载packages/mod/.babelrc,因为该.babelrc位于子包中,而不是根包。 要启用该.babelrc的处理,您需要使用babel.config.js文件中的“babelrcroots”选项。babelrcRoots: [ ".", "packages/*", ],

因此,babel将考虑允许加载.babelrc文件的所有包/*包,以及原始repo根。

配置格式

单个配置文件本身的格式分为JS文件和JSON5文件。

JSON5

任何不是.js文件的文件都将被解析为json5,并且应该包含一个与babel接受的选项格式相匹配的对象。

javascript

任何.js文件都将require()ed,并且应该导出配置对象,或者在调用时返回配置对象的函数。主要的好处是,用户可以使用JS逻辑构建配置结构,这可能使配置逻辑更容易共享。.js文件可以用作项目范围的配置,也可以通过.babelrc.js文件进行文件相关配置。 返回配置的函数有一些特殊的功能,因为它们可以访问babel本身公开的API。有关详细信息,请参阅配置函数API。

配置函数API

JS配置文件可能会导出一个将传递配置函数API的函数: module.exports = function(api) { return {}; }

api对象公开了babel本身从其索引模块公开的所有内容,以及配置文件特定的api:

  • api.version Type: string 正在加载配置文件的babel版本的版本字符串。

  • api.cache JS配置非常好,因为它们可以即时计算配置,但缺点是它会使缓存变得更困难。Babel希望避免每次编译文件时都重新执行config函数,因为这样它还需要重新执行该配置中引用的任何插件和预设函数。 为了避免这种情况,babel希望配置函数的用户告诉它如何管理配置文件中的缓存。

    • api.cache.forever()-permacache计算的配置,不再调用函数。
    • api.cache.never()-不要缓存此配置,每次都重新执行函数。
    • api.cache.using(()=>process.env.node_env)-基于node_env值的缓存。每当using回调返回预期值以外的值时,将再次调用总体配置函数,并向缓存中添加一个新条目。
    • api.cache.invalidate(()=>process.env.node_env)-基于node_env值的缓存。每当using回调返回预期值以外的值时,将再次调用总体配置函数,并且缓存中的所有条目都将替换为结果。 由于实际回调结果用于检查缓存项是否有效,因此建议: 回调应该很小并且没有副作用。 回调应返回可能范围最小的值。例如,上面的.using(()=>process.env.node_env)用法并不理想,因为它将根据检测到的node_env值创建未知数量的缓存项。这样做比较安全。使用(()=>process.env.node_env==“development”),因为这样缓存项只能为true或false。 回调应该很小并且没有副作用。
  • api.env(…) 由于node_env是一种非常常见的切换行为的方法,babel还包含一个专门用于此目的的API函数。此API用作快速检查babel加载时使用的“envname”的方法,如果没有设置其他覆盖环境,则会考虑节点env。 它有几种不同的形式: 如果envname==“production”,则api.env(“production”)返回true。 如果[“development”,“test”]包含(envname),则env([“development”,“test”])返回true。 api.env()返回当前envname字符串。 如果env以“test-”开头,则api.env(envname=>envname.starts with(“test-”))返回true。 这个函数在内部使用下面提到的api.cache来确保babel知道这个构建依赖于一个特定的envname。

  • api.caller(cb) 此API用作访问已传递给babel的调用方数据的方法。由于babel的许多实例可能以不同的调用方值在同一进程中运行,因此该API被设计为自动配置api.cache,与api.env()的方式相同。 调用者值可用作回调函数的第一个参数。最好和类似的东西一起使用 function isBabelRegister(caller) { return !!(caller && caller.name === "@babel/register"); }

module.exports = function(api) { const isRegister = api.caller(isBabelRegister);

return { // ... }; }

根据特定环境切换配置行为。

  • api.assertVersion(range) 虽然api.version在一般情况下很有用,但有时只声明您的版本是很好的。此API公开了一种简单的方法来实现这一点: module.exports = function(api) { api.assertVersion("^7.2");

    return { // ... }; };