@docusaurus/core
Version:
Easy to Maintain Open Source Documentation Websites
206 lines (205 loc) • 8.51 kB
JavaScript
"use strict";
/**
* 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.loadContext = loadContext;
exports.loadSite = loadSite;
exports.reloadSite = reloadSite;
exports.reloadSitePlugin = reloadSitePlugin;
const tslib_1 = require("tslib");
const path_1 = tslib_1.__importDefault(require("path"));
const utils_1 = require("@docusaurus/utils");
const logger_1 = require("@docusaurus/logger");
const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
const bundler_1 = require("@docusaurus/bundler");
const config_1 = require("./config");
const clientModules_1 = require("./clientModules");
const plugins_1 = require("./plugins/plugins");
const htmlTags_1 = require("./htmlTags");
const siteMetadata_1 = require("./siteMetadata");
const i18n_1 = require("./i18n");
const translations_1 = require("./translations/translations");
const codegen_1 = require("./codegen/codegen");
const routes_1 = require("./routes");
const storage_1 = require("./storage");
const siteMessages_1 = require("./siteMessages");
/**
* Loading context is the very first step in site building. Its params are
* directly acquired from CLI options. It mainly loads `siteConfig` and the i18n
* context (which includes code translations). The `LoadContext` will be passed
* to plugin constructors.
*/
async function loadContext(params) {
const { siteDir, outDir: baseOutDir = utils_1.DEFAULT_BUILD_DIR_NAME, locale, config: customConfigFilePath, automaticBaseUrlLocalizationDisabled, } = params;
const generatedFilesDir = path_1.default.resolve(siteDir, utils_1.GENERATED_FILES_DIR_NAME);
const { siteVersion, loadSiteConfig: { siteConfig: initialSiteConfig, siteConfigPath }, } = await (0, combine_promises_1.default)({
siteVersion: (0, siteMetadata_1.loadSiteVersion)(siteDir),
loadSiteConfig: (0, config_1.loadSiteConfig)({
siteDir,
customConfigFilePath,
}),
});
// Not sure where is the best place to put this VCS initialization call?
// The sooner is probably the better
// Note: we don't await the result on purpose!
// VCS initialization can be slow for large repos, and we don't want to block
// VCS integrations should be carefully designed to avoid blocking
logger_1.PerfLogger.async('VCS init', () => {
return initialSiteConfig.future.experimental_vcs.initialize({ siteDir });
});
const currentBundler = await (0, bundler_1.getCurrentBundler)({
siteConfig: initialSiteConfig,
});
const i18n = await (0, i18n_1.loadI18n)({
siteDir,
config: initialSiteConfig,
currentLocale: locale ?? initialSiteConfig.i18n.defaultLocale,
automaticBaseUrlLocalizationDisabled: automaticBaseUrlLocalizationDisabled ?? false,
});
const localeConfig = (0, utils_1.getLocaleConfig)(i18n);
// We use the baseUrl from the locale config.
// By default, it is inferred as /<siteConfig.baseUrl>/
// eventually including the /<locale>/ suffix
const baseUrl = localeConfig.baseUrl;
// TODO not ideal: we should allow configuring a custom outDir for each locale
// The site baseUrl should be 100% decoupled from the file system output shape
// We added this logic to restore v3 retro-compatibility, because by default
// Docusaurus always wrote to ./build for sites having a baseUrl
// See also https://github.com/facebook/docusaurus/issues/11433
// This logic assumes the locale baseUrl will start with the site baseUrl
// which is the case if an explicit locale baseUrl is not provided
// but in practice a custom locale baseUrl could be anything now
const outDirBaseUrl = baseUrl.replace(initialSiteConfig.baseUrl, '/');
const outDir = path_1.default.join(path_1.default.resolve(siteDir, baseOutDir), outDirBaseUrl);
const localizationDir = path_1.default.resolve(siteDir, i18n.path, (0, utils_1.getLocaleConfig)(i18n).path);
const siteConfig = {
...initialSiteConfig,
url: localeConfig.url,
baseUrl,
};
const codeTranslations = await (0, translations_1.loadSiteCodeTranslations)({ localizationDir });
const siteStorage = (0, storage_1.createSiteStorage)(siteConfig);
return {
siteDir,
siteVersion,
siteStorage,
generatedFilesDir,
localizationDir,
siteConfig,
siteConfigPath,
outDir,
baseUrl,
i18n,
codeTranslations,
currentBundler,
};
}
function createSiteProps(params) {
const { plugins, routes, context } = params;
const { generatedFilesDir, siteDir, siteVersion, siteConfig, siteConfigPath, siteStorage, outDir, baseUrl, i18n, localizationDir, codeTranslations: siteCodeTranslations, currentBundler, } = context;
const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)({
plugins,
router: siteConfig.future.experimental_router,
});
const siteMetadata = (0, siteMetadata_1.createSiteMetadata)({ plugins, siteVersion });
const codeTranslations = {
...(0, translations_1.getPluginsDefaultCodeTranslations)({ plugins }),
...siteCodeTranslations,
};
(0, routes_1.handleDuplicateRoutes)(routes, siteConfig.onDuplicateRoutes);
const routesPaths = (0, routes_1.getRoutesPaths)(routes, baseUrl);
return {
siteConfig,
siteConfigPath,
siteMetadata,
siteVersion,
siteStorage,
siteDir,
outDir,
baseUrl,
i18n,
localizationDir,
generatedFilesDir,
routes,
routesPaths,
plugins,
headTags,
preBodyTags,
postBodyTags,
codeTranslations,
currentBundler,
};
}
// TODO global data should be part of site props?
async function createSiteFiles({ site, globalData, }) {
return logger_1.PerfLogger.async('Create site files', async () => {
const { props: { plugins, generatedFilesDir, siteConfig, siteMetadata, siteStorage, i18n, codeTranslations, routes, baseUrl, }, } = site;
const clientModules = (0, clientModules_1.getAllClientModules)(plugins);
await (0, codegen_1.generateSiteFiles)({
generatedFilesDir,
clientModules,
siteConfig,
siteMetadata,
siteStorage,
i18n,
codeTranslations,
globalData,
routes,
baseUrl,
});
});
}
/**
* This is the crux of the Docusaurus server-side. It reads everything it needs—
* code translations, config file, plugin modules... Plugins then use their
* lifecycles to generate content and other data. It is side-effect-ful because
* it generates temp files in the `.docusaurus` folder for the bundler.
*/
async function loadSite(params) {
const context = await logger_1.PerfLogger.async('Load context', () => loadContext(params));
const { plugins, routes, globalData } = await (0, plugins_1.loadPlugins)(context);
const props = createSiteProps({ plugins, routes, globalData, context });
const site = { props, params };
await createSiteFiles({
site,
globalData,
});
// For now, we don't re-emit messages on site reloads, it's too verbose
if (!params.isReload) {
await (0, siteMessages_1.emitSiteMessages)({ site });
}
return site;
}
async function reloadSite(site) {
// TODO this can be optimized, for example:
// - plugins loading same data as before should not recreate routes/bundles
// - codegen does not need to re-run if nothing changed
return loadSite({
...site.params,
isReload: true,
});
}
async function reloadSitePlugin(site, pluginIdentifier) {
const { plugins, routes, globalData } = await (0, plugins_1.reloadPlugin)({
pluginIdentifier,
plugins: site.props.plugins,
context: site.props,
});
const newProps = createSiteProps({
plugins,
routes,
globalData,
context: site.props, // Props extends Context
});
const newSite = {
props: newProps,
params: site.params,
};
// TODO optimize, bypass useless codegen if new site is similar to old site
await createSiteFiles({ site: newSite, globalData });
return newSite;
}