@docusaurus/core
Version:
Easy to Maintain Open Source Documentation Websites
187 lines (186 loc) • 8.19 kB
JavaScript
;
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadPlugins = loadPlugins;
exports.reloadPlugin = reloadPlugin;
const logger_1 = require("@docusaurus/logger");
const init_1 = require("./init");
const synthetic_1 = require("./synthetic");
const translations_1 = require("../translations/translations");
const routeConfig_1 = require("./routeConfig");
const actions_1 = require("./actions");
const pluginsUtils_1 = require("./pluginsUtils");
async function translatePluginContent({ plugin, content, context, }) {
const rawTranslationFiles = (await plugin.getTranslationFiles?.({ content })) ?? [];
const translationFiles = await Promise.all(rawTranslationFiles.map((translationFile) => (0, translations_1.localizePluginTranslationFile)({
localizationDir: context.localizationDir,
translationFile,
plugin,
})));
const translatedContent = plugin.translateContent?.({ content, translationFiles }) ?? content;
const translatedThemeConfigSlice = plugin.translateThemeConfig?.({
themeConfig: context.siteConfig.themeConfig,
translationFiles,
});
// TODO dangerous legacy, need to be refactored!
// Side-effect to merge theme config translations. A plugin should only
// translate its own slice of theme config and should make no assumptions
// about other plugins' keys, so this is safe to run in parallel.
Object.assign(context.siteConfig.themeConfig, translatedThemeConfigSlice);
return translatedContent;
}
async function executePluginContentLoading({ plugin, context, }) {
return logger_1.PerfLogger.async(`Load ${(0, pluginsUtils_1.formatPluginName)(plugin)}`, async () => {
let content = await logger_1.PerfLogger.async('loadContent()', () => plugin.loadContent?.());
content = await logger_1.PerfLogger.async('translatePluginContent()', () => translatePluginContent({
plugin,
content,
context,
}));
const defaultCodeTranslations = (await logger_1.PerfLogger.async('getDefaultCodeTranslationMessages()', () => plugin.getDefaultCodeTranslationMessages?.())) ?? {};
if (!plugin.contentLoaded) {
return {
...plugin,
content,
defaultCodeTranslations,
routes: [],
globalData: undefined,
};
}
const pluginActionsUtils = await (0, actions_1.createPluginActionsUtils)({
plugin,
generatedFilesDir: context.generatedFilesDir,
baseUrl: context.siteConfig.baseUrl,
trailingSlash: context.siteConfig.trailingSlash,
});
await logger_1.PerfLogger.async('contentLoaded()', () =>
// @ts-expect-error: should autofix with TS 5.4
plugin.contentLoaded({
content,
actions: pluginActionsUtils.getActions(),
}));
return {
...plugin,
content,
defaultCodeTranslations,
routes: pluginActionsUtils.getRoutes(),
globalData: pluginActionsUtils.getGlobalData(),
};
});
}
async function executeAllPluginsContentLoading({ plugins, context, }) {
return logger_1.PerfLogger.async(`Load plugins content`, () => {
return Promise.all(plugins.map((plugin) => executePluginContentLoading({ plugin, context })));
});
}
async function executePluginAllContentLoaded({ plugin, context, allContent, }) {
return logger_1.PerfLogger.async(`allContentLoaded() - ${(0, pluginsUtils_1.formatPluginName)(plugin)}`, async () => {
if (!plugin.allContentLoaded) {
return { routes: [], globalData: undefined };
}
const pluginActionsUtils = await (0, actions_1.createPluginActionsUtils)({
plugin,
generatedFilesDir: context.generatedFilesDir,
baseUrl: context.siteConfig.baseUrl,
trailingSlash: context.siteConfig.trailingSlash,
});
await plugin.allContentLoaded({
allContent,
actions: pluginActionsUtils.getActions(),
});
return {
routes: pluginActionsUtils.getRoutes(),
globalData: pluginActionsUtils.getGlobalData(),
};
});
}
async function executeAllPluginsAllContentLoaded({ plugins, context, }) {
return logger_1.PerfLogger.async(`allContentLoaded()`, async () => {
const allContent = (0, pluginsUtils_1.aggregateAllContent)(plugins);
const allRoutes = [];
const allGlobalData = {};
await Promise.all(plugins.map(async (plugin) => {
var _a;
const { routes, globalData: pluginGlobalData } = await executePluginAllContentLoaded({
plugin,
context,
allContent,
});
const pluginRoutes = routes.map((route) => (0, pluginsUtils_1.toPluginRoute)({ plugin, route }));
allRoutes.push(...pluginRoutes);
if (pluginGlobalData !== undefined) {
allGlobalData[_a = plugin.name] ?? (allGlobalData[_a] = {});
allGlobalData[plugin.name][plugin.options.id] = pluginGlobalData;
}
}));
return { routes: allRoutes, globalData: allGlobalData };
});
}
// This merges plugins routes and global data created from both lifecycles:
// - contentLoaded()
// - allContentLoaded()
function mergeResults({ baseUrl, plugins, allContentLoadedResult, }) {
const routes = (0, routeConfig_1.sortRoutes)([...(0, pluginsUtils_1.aggregateRoutes)(plugins), ...allContentLoadedResult.routes], baseUrl);
const globalData = (0, pluginsUtils_1.mergeGlobalData)((0, pluginsUtils_1.aggregateGlobalData)(plugins), allContentLoadedResult.globalData);
return { routes, globalData };
}
/**
* Initializes the plugins and run their lifecycle functions.
*/
async function loadPlugins(context) {
return logger_1.PerfLogger.async('Load plugins', async () => {
const initializedPlugins = await logger_1.PerfLogger.async('Init plugins', () => (0, init_1.initPlugins)(context));
// TODO probably not the ideal place to hardcode those plugins
initializedPlugins.push((0, synthetic_1.createBootstrapPlugin)(context), await (0, synthetic_1.createMDXFallbackPlugin)(context));
const plugins = await executeAllPluginsContentLoading({
plugins: initializedPlugins,
context,
});
const allContentLoadedResult = await executeAllPluginsAllContentLoaded({
plugins,
context,
});
const { routes, globalData } = mergeResults({
baseUrl: context.baseUrl,
plugins,
allContentLoadedResult,
});
return { plugins, routes, globalData };
});
}
async function reloadPlugin({ pluginIdentifier, plugins: previousPlugins, context, }) {
return logger_1.PerfLogger.async(`Reload plugin ${(0, pluginsUtils_1.formatPluginName)(pluginIdentifier)}`, async () => {
const previousPlugin = (0, pluginsUtils_1.getPluginByIdentifier)({
plugins: previousPlugins,
pluginIdentifier,
});
const plugin = await executePluginContentLoading({
plugin: previousPlugin,
context,
});
/*
// TODO Docusaurus v4 - upgrade to Node 20, use array.with()
const plugins = previousPlugins.with(
previousPlugins.indexOf(previousPlugin),
plugin,
);
*/
const plugins = [...previousPlugins];
plugins[previousPlugins.indexOf(previousPlugin)] = plugin;
const allContentLoadedResult = await executeAllPluginsAllContentLoaded({
plugins,
context,
});
const { routes, globalData } = mergeResults({
baseUrl: context.baseUrl,
plugins,
allContentLoadedResult,
});
return { plugins, routes, globalData };
});
}