You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
先确认root与rootMode参数的值是什么,默认是process.cwd(),注意monorepo项目,当我们在根目录下执行yarn build or lerna run build or lerna exec -- yarn build这样的命令时候,process.cwd()的值是子包的根目录,而不是项目的根目录
目录
背景
有一个webpack单页项目,然后根据之前对babel的了解,在根目录下建了一个.babelrc文件,然后在babel-loader通过exclues排除node_modules目录,且配置开启babel-loader缓存相关的配置参数,其它babel的presets与plugin则通过根目录下的.babelrc文件来进行配置,如下所示
最开始babel能够有效的对文件做处理,然后突然有一个需求,添加了公司内部的一个npm包,然后这个npm包只输出了ts文件,所以需要将node_modules下的这个包通过babel-loader处理,根据之前的经验,只需要在excludes那里通过增则排除下需要处理的npm包即可,如下所示
实际运行的结果就是babel-loader对node_modules下的文件做处理了,但是babel相关的插件没有对npm包内的文件生效
由于时间紧迫只给了一个,临时方案就是是在babel-loader那里对这个npm包单独处理,传入presets与plugin,如下所示
虽然这次问题临时解决了,但是有一个问题困扰着我,babel不是会一直遍历上级目录,一直找到有babel配置的目录为止吗?那么这次为什么没有生效?
两类配置文件
于是带着疑问又重新去看了babel的官方文档,有关配置的内容在这里Config Files
配置文件类型:
babel提供了两种配置文件类型,可以二者结合使用,也可以只用单独的一种
babel.config.json
files, with the different extensions (.js
,.cjs
,.mjs
).babelrc.json
files, with the different extensions (.babelrc
,.js
,.cjs
,.mjs
)package.json
files with a"babel"
key项目级配置文件
优点
缺点
相对于文件路径配置
所以到这里我们就知道我们最开始的问题在哪里了,在我们项目根目录使用的是相对于文件路径配置而不是全局配置,所以src目录下的文件都能够读取到根目录下的.babelrc配置,但是node_modules下的项目就无法读取到根目录下的.babelrc配置文件了
配置项详解
babelrc
参数类型:Boolean 默认值: true
当该配置选项为 true 的时候,允许加载 babelrc 的配置文件,配合 babelrcRoots 可以加载子包的 babel 配置,当为 false 的时候就完全禁止加载 babelrc 配置,整个项目只会有 babel.config.js 全局配置
babelrcRoots
参数类型:boolean | MatchPattern | MatchPattern[] 默认参数 opts.root babel 默认只会使用项目根节点的.babelrc 配置文件,如果需要使用子包的.babelrc 可以配置该参数允许加载子包的
root
参数类型:String 默认值:process.cwd();
用来确定当前 babel 执行环境的的根目录位置
rootMode
参数类型:"root" | "upward" | "upward-optional" 默认: "root" 这个配置选项,和 root 配置选项是关联的,定义了 babel 如何选择项目的根目录,通过传入不同参数可以选择 babel 不同的处理 root 值,以获得最终项目的根目录
"root" 传递原 root 值不变
"upward" 让 babel 从 root 的上级目录查找 babel.config.js 全局配置,如果没有会报错
"upward-optional" 让 babel 从 root 的上级目录查找 babel.config.js ,如果没有找到就回退到当前目录作为 babel 的根目录
plugins
参数类型: String[] | [String, Options][] 默认值:[]
该选项配置包含了,当 babel 启动的时候要激活的 babel 插件数组
presets
参数类型: String[] | [String, Options][] 默认值:[]
预设本质就是插件的集合,该配置表示 babel 处理文件要激活的预设插件数组.
extends
参数类型:String
该选项参数不能放置在 presets 选项配置上. 该选项允许继承其他配置文件的配置,extends 选项在当前配置文件配置范围将会合并继承 extends 指向的配置文件的相同配置范围的配置内容,当前配置文件覆盖在继承文件配置之上
overrides
参数类型:Options[]
该选项参数不允许放置在嵌套的 overrides 配置和 env 配置里. 该选项参数允许用户提供一个覆盖当前配置文件的配置内容的配置数组.使用实例
此功能经常配置 "test", "include", "exclude" 选项一起使用,可以提供 babel 覆盖当前全局配置的条件
test
参数类型:
MatchPattern | Array<MatchPattern>
该选项配置是一个匹配规则或者规则列表,如果 babel 当前编译的文件和配置规则都不符合,则 babel 编译的时候会将该文件忽略,该选项经常配合 overrides 一起使用,让 babel 做配置文件条件输出,而且该选项可以放在配置文件的任何位置
include
该选项配置是"test"选项的的别名
exclude
参数类型:
MatchPattern | Array<MatchPattern>
与 include 配置相反,该配置表示的是当任意一个的匹配规则列表符合匹配当前编译文件的,babel 都会忽略该文件,该选项经常配合 overrides 一起使用,让 babel 做配置文件条件输出,而且该选项还可以放在配置文件的任何位置
ignore
参数类型:
Array<MatchPattern>
该选项参数不允许放置在"presets"配置内 功能与"exclude"类似,当 babel 编译的时候匹配到任意符合匹配规则列表的内容时,会立即中止当前所有的 babel 处理。完全禁用 babel 的其他处理sourceMaps / sourceMap
参数类型:boolean | "inline" | "both" 默认值:false
babel 创建 sourceMap, + true 为编译文件创建一个 sourceMap + inline 将 map 作为 data:url 直接内嵌到文件里 + both 既创建 map 也内嵌 注意:该配置选项我自己实验的时候 只能在命令行中使用,在配置文件里配置无效,而@babel/cli 会将 map 写入到 .map后缀的格式文件内
sourceType
参数类型:"script" | "module" | "unambiguous" 默认值:"module"
该选项配置参数主要引导 babel 的文件解析是否转换 import 或者 require,babel 默认处理模块是 es 模块,默认使用 import
compact
参数类型:Boolean | "auto" 默认值:"auto"
该配置选项引导 babel 是否开启紧凑模式,紧凑模式会省略所有可选的换行符和空格. 当配置选项是”auto“的时候,babel 会根据文件的字符数判断,当字符长度 code.length > 50,000 时 会开启紧凑模式
minified
参数类型:Boolean 默认值:false
该配置选项为 ture 的时候, 相当于 compact:true 基础上,还省略了块级作用域末尾的分号,以及其他很多地方省略,babel 尽可能的压缩代码,比 compact 更短的输出
配置文件读取规则
我们从各个插件中是进一步看,babel配置的文件的读取
babel-loader原理(8.2.2)
@rollup/plugin-babel原理(5.3.0)
babel先于rollup处理代码,这种方式会传filename参数
通过@babel/core内提供的loadPartialConfigAsync || loadPartialConfig方法查找babel配置文件
调用babel.transformAsync(code, options)方法,,options是上一步找到babel配置文件
返回code与map继续后续工作,babel的工作就做完了
babel后于rollup处理代码,这种方式不会传filename参数
通过@babel/core内提供的loadPartialConfigAsync || loadPartialConfig方法查找babel配置文件
调用babel.transformAsync(code, options)方法,,options是上一步找到babel配置文件
返回code与map继续后续工作,babel的工作就做完了
我们从上面看到都是调用了babel/core中提供的
loadPartialConfigAsync
||loadPartialConfig
这两个方法来读取项目中的babel配置,而这两个方法在内部都调用的是loadPrivatePartialConfig
这个方法,从源码(7.15.0)中一起看下具体的实现以下源码分析的过程中省略了部分代码,只保留关键实现
读取配置项入口
cwd默认值为
process.cwd()
rootDir(root参数的别名)默认值为
opts.cwd
所以当我们cwd与root都没有传值的时候,传入不同的rootMode参数有下面三种结果
再接着看
loadPrivatePartialConfig
方法后面的实现来看
buildRootChain
的内部实现项目级配置文件的名称
看到这里我们就知道项目配置文件读取步骤
所以这里会有三个参数configFile、root、rootMode影响到项目级配置文件也就是babel.config.js配置文件的查找,小结如下
继续往下看
buildRootChain
方法根据filename向上寻找package.json文件所在目录的逻辑
判断是否符合查找babelrc配置文件的条件
在packageData.directories目录内查找RELATIVE_CONFIG_FILENAMES目录内的文件
我们来总结下babelrc配置文件的读取规则,小结如下
最终合并找到的babelrc与babel.config文件的内容,如果一个filename二者都有匹配到结果会如下所示
到这里我们知道了babel是怎么去读取项目及配置文件与相对与文件的配置文件,且babel-loader还是@rollup/plugin-babel都是对babel的封装,而我们平常使用的时候,只需要知道babel是怎么读取配置文件及碰到babel的配置文件没有生效时,我们应该怎么排查就可以解决大部分问题
最后总结一下babel配置文件读取流程图,如下图所示
快速定位配置项问题
先确认root与rootMode参数的值是什么,默认是process.cwd(),注意monorepo项目,当我们在根目录下执行yarn build or lerna run build or lerna exec -- yarn build这样的命令时候,process.cwd()的值是子包的根目录,而不是项目的根目录
在确定configFile参数的取值
然后在看babelrc与babelrcRoots的值
最终在查看,当前文件被应用的babel.config.js与.babelrc文件
推荐实践
非menorepo项目
在项目根目录下配置一个babel.config.js文件即可,配置如下所示
我们可以通过exclude选项来排除需要使用babel-loader处理的node_modules下的包
lerna menorepo项目
这里的menorepo借助了rollup来构建,所以使用了@rollup/plugin-babel插件
在项目根目录下配置一个babel.config.js文件即可,配置如下所示
如果子包需要使用不同的babel配置,只需要在子包的根目录或者需要处理的文件的目录下,创建一个.babelrc配置文件即可,然后在.babelrc配置文件内配置想要特殊处理的babel配置
总结
babel引入了项目级配置文件的概念,虽然解决了一部分问题,但是无形中又增加了用户的理解与使用成本,所以我们在使用的过程中,只能尽可能的去总结一些更简单的实践,以提高我们的开发效率与排错成本
The text was updated successfully, but these errors were encountered: