babel中files相关配置文件加载

2 篇文章 0 订阅
1 篇文章 0 订阅
文章详细描述了在Node.js项目中如何通过`config-chain.ts`中的`findPackageData`、`findRelativeConfig`和`findRootConfig`函数查找并加载`.babelrc`和`babel.config.js`等配置文件的过程,涉及`loadOneConfig`和`readConfig`方法,以及如何处理异步和`@babel/register`影响的配置加载策略。
摘要由CSDN通过智能技术生成

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;
  }
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值