UNPKG

@docusaurus/core

Version:

Easy to Maintain Open Source Documentation Websites

206 lines (205 loc) • 8.51 kB
"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; }