@babel/core 源码分析(3)

73 阅读2分钟

紧接着上一篇 @babel/core 源码分析(2) ,我们已经可以知道loadPrivatePartialConfig方法干了什么,那么就继续分析full.tsloadFullConfig

export default gensync(function* loadFullConfig(
  inputOpts: unknown,
): Handler<ResolvedConfig | null> {
// 这里上一篇文章已经重点分析过,所以这里result就是总的一个plugin和preset。
  const result = yield* loadPrivatePartialConfig(inputOpts);
  if (!result) {
    return null;
  }
  // 从result中获取options、context和fileHandling。
  const { options, context, fileHandling } = result;
// 其中fileHandling的值为“transpile”、“ignored”或“unsupported”,以指示调用者如何处理该文件。
//这个值可以从.babelignore文件中读取,或者.babelrc文件中的ignore值中读取。
  if (fileHandling === "ignored") {
    return null;
  }

  const optionDefaults = {};

  const { plugins, presets } = options;

  if (!plugins || !presets) {
    throw new Error("Assertion failure - plugins and presets exist");
  }

  const presetContext: Context.FullPreset = {
    ...context,
    targets: options.targets,
  };

 // 获取UnloadedDescriptor,具体configItem配置在 ‘item.ts’
 // UnloadedDescriptor:
 // Represents a plugin or presets at a given location in a config object.
 // At this point these have been resolved to a specific object or function,
 // but have not yet been executed to call functions with options.  const toDescriptor = (item: PluginItem) => {
    const desc = getItemDescriptor(item);
    if (!desc) {
      throw new Error("Assertion failure - must be config item");
    }

    return desc;
  };

  const presetsDescriptors = presets.map(toDescriptor);
  const initialPluginsDescriptors = plugins.map(toDescriptor);
  const pluginDescriptorsByPass: Array<Array<UnloadedDescriptor>> = [[]];
  const passes: Array<Array<Plugin>> = [];

  const externalDependencies: DeepArray<string> = [];

  const ignored = yield* enhanceError(
    context,
    function* recursePresetDescriptors(
      rawPresets: Array<UnloadedDescriptor>,
      pluginDescriptorsPass: Array<UnloadedDescriptor>,
    ): Handler<true | void> {
      const presets: Array<{
        preset: ConfigChain | null;
        pass: Array<UnloadedDescriptor>;
      }> = [];

      for (let i = 0; i < rawPresets.length; i++) {
        const descriptor = rawPresets[i];
        if (descriptor.options !== false) {
          try {
            // eslint-disable-next-line no-var
            // 加载preset得到plugins,此函数后续详解
            // 简单来说 preset是plugin的集合,所以这个函数就是把preset里包含的plugin全部加载出来
            var preset = yield*  loadPresetDescriptor(descriptor, presetContext);
          } catch (e) {
            if (e.code === "BABEL_UNKNOWN_OPTION") {
              checkNoUnwrappedItemOptionPairs(rawPresets, i, "preset", e);
            }
            throw e;
          }

          externalDependencies.push(preset.externalDependencies);

          // Presets normally run in reverse order, but if they
          // have their own pass they run after the presets
          // in the previous pass.
          // 来源配置中的passPerPreset,已经被废弃。
          // 为了改变preset运行的顺序
          if (descriptor.ownPass) {
            presets.push({ preset: preset.chain, pass: [] });
          } else {
            presets.unshift({
              preset: preset.chain,
              pass: pluginDescriptorsPass,
            });
          }
        }
      }

      // resolve presets
      if (presets.length > 0) {
        // The passes are created in the same order as the preset list, but are inserted before any
        // existing additional passes.
        pluginDescriptorsByPass.splice(
          1,
          0,
          ...presets.map(o => o.pass).filter(p => p !== pluginDescriptorsPass),
        );

        for (const { preset, pass } of presets) {
          if (!preset) return true;
            // 改变了pluginDescriptorsPass =》pluginDescriptorsByPass[0]
          pass.push(...preset.plugins);
           // 继续拆分嵌套里的preset,统计plugins 
          const ignored = yield* recursePresetDescriptors(preset.presets, pass);
          if (ignored) return true;

          preset.options.forEach(opts => {
            mergeOptions(optionDefaults, opts);
          });
        }
      }
    },
  )(presetsDescriptors, pluginDescriptorsByPass[0]);

  if (ignored) return null;

  const opts: any = optionDefaults;
  mergeOptions(opts, options);

  const pluginContext: Context.FullPlugin = {
    ...presetContext,
    assumptions: opts.assumptions ?? {},
  };

// 加载plugin
  yield* enhanceError(context, function* loadPluginDescriptors() {
    pluginDescriptorsByPass[0].unshift(...initialPluginsDescriptors);

    for (const descs of pluginDescriptorsByPass) {
      const pass: Plugin[] = [];
      passes.push(pass);

      for (let i = 0; i < descs.length; i++) {
        const descriptor: UnloadedDescriptor = descs[i];
        if (descriptor.options !== false) {
          try {
            // eslint-disable-next-line no-var
            var plugin = yield* loadPluginDescriptor(descriptor, pluginContext);
            // Plugin {
            //   key: 'babel-plugin-transform-vue-jsx',
            //   manipulateOptions: [Function: manipulateOptions],
            //   post: undefined,
            //   pre: undefined,
            //   visitor:
            //    { _exploded: {}, _verified: {}, JSXElement: { exit: [Array] } },
            //   parserOverride: undefined,
            //   generatorOverride: undefined,
            //   options: {},
            //   externalDependencies: [] }
          } catch (e) {
            if (e.code === "BABEL_UNKNOWN_PLUGIN_PROPERTY") {
              // print special message for `plugins: ["@babel/foo", { foo: "option" }]`
              checkNoUnwrappedItemOptionPairs(descs, i, "plugin", e);
            }
            throw e;
          }
          pass.push(plugin);

          externalDependencies.push(plugin.externalDependencies);
        }
      }
    }
  })();

  opts.plugins = passes[0];
  opts.presets = passes
    .slice(1)
    .filter(plugins => plugins.length > 0)
    .map(plugins => ({ plugins }));
  opts.passPerPreset = opts.presets.length > 0;

  return {
    options: opts,
    passes: passes,
    externalDependencies: freezeDeepArray(externalDependencies),
  };
});

总结

总的来说,loadFullConfig就是通过loadPrivatePartialConfig()来返回未加载的preset和plugins,每个里面还有value属性对应导出加载的函数。然后通过recursePresetDescriptors()递归加载preset,统计里面的pulgins。最后通过loadPluginDescriptors()加载每个plugins。