紧接着上一篇 @babel/core 源码分析(2)
,我们已经可以知道loadPrivatePartialConfig方法干了什么,那么就继续分析full.ts的loadFullConfig。
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。