files内相关文件
文件夹中代码的功能主要是 配置的路径查找和加载
承接 config-chain.ts 的调用
import {findPackageData, findRelativeConfig,findRootConfig,loadConfig} from "./files/index.ts";
configuration.ts
...
// 根目录 babel.config.*
export const ROOT_CONFIG_FILENAMES = [
"babel.config.js",
"babel.config.cjs",
"babel.config.mjs",
"babel.config.json",
"babel.config.cts",
];
// 相对 .babelrc.*
const RELATIVE_CONFIG_FILENAMES = [
".babelrc",
".babelrc.js",
".babelrc.cjs",
".babelrc.mjs",
".babelrc.json",
".babelrc.cts",
];
const BABELIGNORE_FILENAME = ".babelignore";
...
// 查找 babel.config.*
export function findRootConfig(
dirname: string, // 项目根目录 context.root
envName: string,
caller: CallerMetadata | undefined,
): Handler<ConfigFile | null> {
return loadOneConfig(ROOT_CONFIG_FILENAMES, dirname, envName, caller);
}
// 查找 .babelrc
export function* findRelativeConfig(
packageData: FilePackageData,
envName: string,
caller: CallerMetadata | undefined,
): Handler<RelativeConfig> {
let config = null;
let ignore = null;
const dirname = path.dirname(packageData.filepath);
// directories:通过编译原文件src/index.js 所在目录以及所有上层目录,查找 .babelrc.*
for (const loc of packageData.directories) {
if (!config) {
config = yield* loadOneConfig(
RELATIVE_CONFIG_FILENAMES,
loc,
envName,
caller,
packageData.pkg?.dirname === loc
? packageToBabelConfig(packageData.pkg)
: null,
);
}
if (!ignore) {
const ignoreLoc = path.join(loc, BABELIGNORE_FILENAME);
ignore = yield* readIgnoreConfig(ignoreLoc);
if (ignore) {
debug("Found ignore %o from %o.", ignore.filepath, dirname);
}
}
}
return { config, ignore };
}
// 可以看出 findRootConfig 和 findRelativeConfig 都调用了 loadOneConfig 方法
function* loadOneConfig(
names: string[], // 扩展名数组
dirname: string, // 目录绝对路径
envName: string,
caller: CallerMetadata | undefined,
previousConfig: ConfigFile | null = null,
): Handler<ConfigFile | null> {
/**
* configs 是根据 .babelrc.*/babel.config.* 配置读取的 configFile 的数组
* readConfig 方法根据不同的扩展名返回 configFile
*/
const configs = yield* gensync.all(
names.map(filename =>
// 拼接 地址路径 xxx/.babelrc.*或者xxx/babel.config.*
readConfig(path.join(dirname, filename), envName, caller),
),
);
// 找出 有且仅有 的一个 config
const config = configs.reduce((previousConfig: ConfigFile | null, config) => {
if (config && previousConfig) {
throw new ConfigError(
`Multiple configuration files found. Please remove one:\n` +
` - ${path.basename(previousConfig.filepath)}\n` +
` - ${config.filepath}\n` +
`from ${dirname}`,
);
}
return config || previousConfig;
}, previousConfig);
if (config) {
debug("Found configuration %o from %o.", config.filepath, dirname);
}
/**
* config === configFile
* {
* filepath,
* dirname: _path().dirname(filepath),
* options:{
* plugins:[],
* presets:[["@babel/env",{corejs:'3.xxx',...}]]
* }
* }
*/
return config;
}
// readConfig 根据不同扩展名进行不同的查找方法,本案例是.babelrc.js,
// 所以调用 readConfigCode --- loadCodeDefault(),
// 其中 loadCodeDefault 来自 module-types.ts文件
function* readConfigCode(
filepath: string,
data: ConfigCacheData,
): Handler<ConfigFile | null> {
if (!nodeFs.existsSync(filepath)) return null;
// loadCodeDefault返回 .babelrc.*或者babel.config.* 的 module.exports的函数
let options = yield* loadCodeDefault(
filepath,
"You appear to be using a native ECMAScript module configuration " +
"file, which is only supported when running Babel asynchronously.",
);
let cacheNeedsConfiguration = false;
if (typeof options === "function") {
// 读取配置 options={plugins:[],presets:[["",{}]]},即 module.exports的函数的返回对象
({ options, cacheNeedsConfiguration } = yield* runConfig(options, data));
}
...
/**
* 返回 一个组装的 configFile 结构为
* {
* filepath,
* dirname: _path().dirname(filepath),
* options:{
* plugins:[],
* presets:[]
* }
* }
*/
return buildConfigFileObject(options, filepath);
}
module-types.ts
export default function* loadCodeDefault(
filepath: string,
asyncError: string,
): Handler<unknown> {
switch (path.extname(filepath)) {
...
// 最终 会调用 loadCjsDefault 方法
}
}
const LOADING_CJS_FILES = new Set();
// 返回值为 .babelrc.*或者babel.config.* 的 module.exports的函数
function loadCjsDefault(filepath: string) {
// 如果像 @babel/register 这样的 require Hook 已经加载到系统中,
// 那么 调用 下面的require方法会是的代码重新进入,
// 会导致babel编译.babelrc.js文件,为了涵盖这种情况,自动忽略重入的配置,
// esm不会发生这种情况
if (LOADING_CJS_FILES.has(filepath)) {
debug("Auto-ignoring usage of config %o.", filepath);
return {};
}
let module;
try {
LOADING_CJS_FILES.add(filepath);
// filepath:.babelrc或者babel.config.*的绝对路径
// 可以看作是 let module = require(filepath)
module = endHiddenCallStack(require)(filepath);
} finally {
LOADING_CJS_FILES.delete(filepath);
}
if (process.env.BABEL_8_BREAKING) {
return module?.__esModule ? module.default : module;
} else {
return module?.__esModule
? module.default ||
/* fallbackToTranspiledModule */ (arguments[1] ? module : undefined)
: module;
}
}