@docusaurus/core 3.1.1 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/docusaurus.mjs +10 -5
- package/lib/client/{serverRenderer.d.ts → renderToHtml.d.ts} +1 -1
- package/lib/client/{serverRenderer.js → renderToHtml.js} +1 -1
- package/lib/client/serverEntry.d.ts +3 -4
- package/lib/client/serverEntry.js +12 -113
- package/lib/client/theme-fallback/Error/index.js +22 -8
- package/lib/commands/build.d.ts +3 -3
- package/lib/commands/build.js +133 -112
- package/lib/commands/deploy.d.ts +2 -2
- package/lib/commands/deploy.js +3 -3
- package/lib/commands/external.js +2 -2
- package/lib/commands/serve.d.ts +2 -2
- package/lib/commands/serve.js +4 -4
- package/lib/commands/{start.d.ts → start/start.d.ts} +3 -3
- package/lib/commands/start/start.js +47 -0
- package/lib/commands/start/utils.d.ts +31 -0
- package/lib/commands/start/utils.js +87 -0
- package/lib/commands/start/watcher.d.ts +42 -0
- package/lib/commands/start/watcher.js +78 -0
- package/lib/commands/start/webpack.d.ts +15 -0
- package/lib/commands/start/webpack.js +133 -0
- package/lib/commands/swizzle/common.d.ts +1 -0
- package/lib/commands/swizzle/common.js +1 -0
- package/lib/commands/swizzle/context.js +2 -2
- package/lib/commands/swizzle/index.js +32 -3
- package/lib/commands/writeHeadingIds.js +2 -2
- package/lib/commands/writeTranslations.d.ts +2 -2
- package/lib/commands/writeTranslations.js +3 -3
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/server/brokenLinks.js +4 -4
- package/lib/server/clientModules.d.ts +1 -1
- package/lib/server/clientModules.js +3 -3
- package/lib/server/codegen/codegen.d.ts +20 -0
- package/lib/server/codegen/codegen.js +65 -0
- package/lib/server/codegen/codegenRoutes.d.ts +49 -0
- package/lib/server/codegen/codegenRoutes.js +190 -0
- package/lib/server/configValidation.js +6 -4
- package/lib/server/i18n.d.ts +2 -2
- package/lib/server/i18n.js +20 -2
- package/lib/server/plugins/actions.d.ts +19 -0
- package/lib/server/plugins/actions.js +62 -0
- package/lib/server/plugins/init.js +3 -3
- package/lib/server/plugins/plugins.d.ts +21 -0
- package/lib/server/plugins/plugins.js +188 -0
- package/lib/server/plugins/pluginsUtils.d.ts +16 -0
- package/lib/server/plugins/pluginsUtils.js +75 -0
- package/lib/server/plugins/routeConfig.d.ts +1 -1
- package/lib/server/plugins/routeConfig.js +4 -4
- package/lib/server/plugins/synthetic.d.ts +3 -3
- package/lib/server/plugins/synthetic.js +0 -2
- package/lib/server/routes.d.ts +3 -45
- package/lib/server/routes.js +16 -168
- package/lib/server/{index.d.ts → site.d.ts} +12 -5
- package/lib/server/site.js +164 -0
- package/lib/server/siteMetadata.d.ts +5 -4
- package/lib/server/siteMetadata.js +14 -10
- package/lib/server/translations/translations.d.ts +9 -2
- package/lib/server/translations/translations.js +21 -4
- package/lib/server/utils.d.ts +0 -2
- package/lib/server/utils.js +1 -9
- package/lib/ssg.d.ts +31 -0
- package/lib/ssg.js +167 -0
- package/lib/templates/templates.d.ts +28 -0
- package/lib/templates/templates.js +63 -0
- package/lib/utils.d.ts +9 -0
- package/lib/utils.js +78 -0
- package/lib/webpack/base.d.ts +5 -1
- package/lib/webpack/base.js +4 -6
- package/lib/webpack/client.d.ts +15 -1
- package/lib/webpack/client.js +78 -23
- package/lib/webpack/minification.d.ts +8 -0
- package/lib/webpack/minification.js +97 -0
- package/lib/webpack/server.d.ts +5 -3
- package/lib/webpack/server.js +41 -50
- package/lib/webpack/utils.d.ts +13 -4
- package/lib/webpack/utils.js +27 -83
- package/package.json +13 -11
- package/lib/commands/start.js +0 -212
- package/lib/server/index.js +0 -154
- package/lib/server/plugins/index.d.ts +0 -18
- package/lib/server/plugins/index.js +0 -106
- /package/lib/{webpack/templates/index.html.template.ejs → templates/dev.html.template.ejs} +0 -0
- /package/lib/{webpack/templates → templates}/ssr.html.template.d.ts +0 -0
- /package/lib/{webpack/templates → templates}/ssr.html.template.js +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.reloadSitePlugin = exports.reloadSite = exports.loadSite = exports.loadContext = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
|
+
const utils_1 = require("@docusaurus/utils");
|
|
13
|
+
const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
|
|
14
|
+
const config_1 = require("./config");
|
|
15
|
+
const clientModules_1 = require("./clientModules");
|
|
16
|
+
const plugins_1 = require("./plugins/plugins");
|
|
17
|
+
const htmlTags_1 = require("./htmlTags");
|
|
18
|
+
const siteMetadata_1 = require("./siteMetadata");
|
|
19
|
+
const i18n_1 = require("./i18n");
|
|
20
|
+
const translations_1 = require("./translations/translations");
|
|
21
|
+
const utils_2 = require("../utils");
|
|
22
|
+
const codegen_1 = require("./codegen/codegen");
|
|
23
|
+
const routes_1 = require("./routes");
|
|
24
|
+
/**
|
|
25
|
+
* Loading context is the very first step in site building. Its params are
|
|
26
|
+
* directly acquired from CLI options. It mainly loads `siteConfig` and the i18n
|
|
27
|
+
* context (which includes code translations). The `LoadContext` will be passed
|
|
28
|
+
* to plugin constructors.
|
|
29
|
+
*/
|
|
30
|
+
async function loadContext(params) {
|
|
31
|
+
const { siteDir, outDir: baseOutDir = utils_1.DEFAULT_BUILD_DIR_NAME, locale, config: customConfigFilePath, } = params;
|
|
32
|
+
const generatedFilesDir = path_1.default.resolve(siteDir, utils_1.GENERATED_FILES_DIR_NAME);
|
|
33
|
+
const { siteVersion, loadSiteConfig: { siteConfig: initialSiteConfig, siteConfigPath }, } = await (0, combine_promises_1.default)({
|
|
34
|
+
siteVersion: (0, siteMetadata_1.loadSiteVersion)(siteDir),
|
|
35
|
+
loadSiteConfig: (0, config_1.loadSiteConfig)({
|
|
36
|
+
siteDir,
|
|
37
|
+
customConfigFilePath,
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
const i18n = await (0, i18n_1.loadI18n)(initialSiteConfig, { locale });
|
|
41
|
+
const baseUrl = (0, utils_1.localizePath)({
|
|
42
|
+
path: initialSiteConfig.baseUrl,
|
|
43
|
+
i18n,
|
|
44
|
+
options: params,
|
|
45
|
+
pathType: 'url',
|
|
46
|
+
});
|
|
47
|
+
const outDir = (0, utils_1.localizePath)({
|
|
48
|
+
path: path_1.default.resolve(siteDir, baseOutDir),
|
|
49
|
+
i18n,
|
|
50
|
+
options: params,
|
|
51
|
+
pathType: 'fs',
|
|
52
|
+
});
|
|
53
|
+
const localizationDir = path_1.default.resolve(siteDir, i18n.path, i18n.localeConfigs[i18n.currentLocale].path);
|
|
54
|
+
const siteConfig = { ...initialSiteConfig, baseUrl };
|
|
55
|
+
const codeTranslations = await (0, translations_1.loadSiteCodeTranslations)({ localizationDir });
|
|
56
|
+
return {
|
|
57
|
+
siteDir,
|
|
58
|
+
siteVersion,
|
|
59
|
+
generatedFilesDir,
|
|
60
|
+
localizationDir,
|
|
61
|
+
siteConfig,
|
|
62
|
+
siteConfigPath,
|
|
63
|
+
outDir,
|
|
64
|
+
baseUrl,
|
|
65
|
+
i18n,
|
|
66
|
+
codeTranslations,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
exports.loadContext = loadContext;
|
|
70
|
+
function createSiteProps(params) {
|
|
71
|
+
const { plugins, routes, context } = params;
|
|
72
|
+
const { generatedFilesDir, siteDir, siteVersion, siteConfig, siteConfigPath, outDir, baseUrl, i18n, localizationDir, codeTranslations: siteCodeTranslations, } = context;
|
|
73
|
+
const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)(plugins);
|
|
74
|
+
const siteMetadata = (0, siteMetadata_1.createSiteMetadata)({ plugins, siteVersion });
|
|
75
|
+
const codeTranslations = {
|
|
76
|
+
...(0, translations_1.getPluginsDefaultCodeTranslations)({ plugins }),
|
|
77
|
+
...siteCodeTranslations,
|
|
78
|
+
};
|
|
79
|
+
(0, routes_1.handleDuplicateRoutes)(routes, siteConfig.onDuplicateRoutes);
|
|
80
|
+
const routesPaths = (0, routes_1.getRoutesPaths)(routes, baseUrl);
|
|
81
|
+
return {
|
|
82
|
+
siteConfig,
|
|
83
|
+
siteConfigPath,
|
|
84
|
+
siteMetadata,
|
|
85
|
+
siteVersion,
|
|
86
|
+
siteDir,
|
|
87
|
+
outDir,
|
|
88
|
+
baseUrl,
|
|
89
|
+
i18n,
|
|
90
|
+
localizationDir,
|
|
91
|
+
generatedFilesDir,
|
|
92
|
+
routes,
|
|
93
|
+
routesPaths,
|
|
94
|
+
plugins,
|
|
95
|
+
headTags,
|
|
96
|
+
preBodyTags,
|
|
97
|
+
postBodyTags,
|
|
98
|
+
codeTranslations,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// TODO global data should be part of site props?
|
|
102
|
+
async function createSiteFiles({ site, globalData, }) {
|
|
103
|
+
return utils_2.PerfLogger.async('Create site files', async () => {
|
|
104
|
+
const { props: { plugins, generatedFilesDir, siteConfig, siteMetadata, i18n, codeTranslations, routes, baseUrl, }, } = site;
|
|
105
|
+
const clientModules = (0, clientModules_1.getAllClientModules)(plugins);
|
|
106
|
+
await (0, codegen_1.generateSiteFiles)({
|
|
107
|
+
generatedFilesDir,
|
|
108
|
+
clientModules,
|
|
109
|
+
siteConfig,
|
|
110
|
+
siteMetadata,
|
|
111
|
+
i18n,
|
|
112
|
+
codeTranslations,
|
|
113
|
+
globalData,
|
|
114
|
+
routes,
|
|
115
|
+
baseUrl,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* This is the crux of the Docusaurus server-side. It reads everything it needs—
|
|
121
|
+
* code translations, config file, plugin modules... Plugins then use their
|
|
122
|
+
* lifecycles to generate content and other data. It is side-effect-ful because
|
|
123
|
+
* it generates temp files in the `.docusaurus` folder for the bundler.
|
|
124
|
+
*/
|
|
125
|
+
async function loadSite(params) {
|
|
126
|
+
const context = await utils_2.PerfLogger.async('Load context', () => loadContext(params));
|
|
127
|
+
const { plugins, routes, globalData } = await (0, plugins_1.loadPlugins)(context);
|
|
128
|
+
const props = await createSiteProps({ plugins, routes, globalData, context });
|
|
129
|
+
const site = { props, params };
|
|
130
|
+
await createSiteFiles({
|
|
131
|
+
site,
|
|
132
|
+
globalData,
|
|
133
|
+
});
|
|
134
|
+
return site;
|
|
135
|
+
}
|
|
136
|
+
exports.loadSite = loadSite;
|
|
137
|
+
async function reloadSite(site) {
|
|
138
|
+
// TODO this can be optimized, for example:
|
|
139
|
+
// - plugins loading same data as before should not recreate routes/bundles
|
|
140
|
+
// - codegen does not need to re-run if nothing changed
|
|
141
|
+
return loadSite(site.params);
|
|
142
|
+
}
|
|
143
|
+
exports.reloadSite = reloadSite;
|
|
144
|
+
async function reloadSitePlugin(site, pluginIdentifier) {
|
|
145
|
+
const { plugins, routes, globalData } = await (0, plugins_1.reloadPlugin)({
|
|
146
|
+
pluginIdentifier,
|
|
147
|
+
plugins: site.props.plugins,
|
|
148
|
+
context: site.props,
|
|
149
|
+
});
|
|
150
|
+
const newProps = await createSiteProps({
|
|
151
|
+
plugins,
|
|
152
|
+
routes,
|
|
153
|
+
globalData,
|
|
154
|
+
context: site.props, // Props extends Context
|
|
155
|
+
});
|
|
156
|
+
const newSite = {
|
|
157
|
+
props: newProps,
|
|
158
|
+
params: site.params,
|
|
159
|
+
};
|
|
160
|
+
// TODO optimize, bypass useless codegen if new site is similar to old site
|
|
161
|
+
await createSiteFiles({ site: newSite, globalData });
|
|
162
|
+
return newSite;
|
|
163
|
+
}
|
|
164
|
+
exports.reloadSitePlugin = reloadSitePlugin;
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { LoadedPlugin, PluginVersionInformation, SiteMetadata } from '@docusaurus/types';
|
|
8
|
-
export declare function
|
|
9
|
-
export declare function
|
|
8
|
+
export declare function loadSiteVersion(siteDir: string): Promise<string | undefined>;
|
|
9
|
+
export declare function loadPluginVersion(pluginPath: string, siteDir: string): Promise<PluginVersionInformation>;
|
|
10
|
+
export declare function createSiteMetadata({ siteVersion, plugins, }: {
|
|
11
|
+
siteVersion: string | undefined;
|
|
10
12
|
plugins: LoadedPlugin[];
|
|
11
|
-
|
|
12
|
-
}): Promise<SiteMetadata>;
|
|
13
|
+
}): SiteMetadata;
|
|
@@ -6,23 +6,27 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.createSiteMetadata = exports.loadPluginVersion = exports.loadSiteVersion = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
12
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
13
13
|
const utils_1 = require("@docusaurus/utils");
|
|
14
|
-
async function
|
|
14
|
+
async function loadPackageJsonVersion(packageJsonPath) {
|
|
15
15
|
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require
|
|
17
17
|
return require(packageJsonPath).version;
|
|
18
18
|
}
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
|
-
async function
|
|
21
|
+
async function loadPackageJsonName(packageJsonPath) {
|
|
22
22
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require
|
|
23
23
|
return require(packageJsonPath).name;
|
|
24
24
|
}
|
|
25
|
-
async function
|
|
25
|
+
async function loadSiteVersion(siteDir) {
|
|
26
|
+
return loadPackageJsonVersion(path_1.default.join(siteDir, 'package.json'));
|
|
27
|
+
}
|
|
28
|
+
exports.loadSiteVersion = loadSiteVersion;
|
|
29
|
+
async function loadPluginVersion(pluginPath, siteDir) {
|
|
26
30
|
let potentialPluginPackageJsonDirectory = path_1.default.dirname(pluginPath);
|
|
27
31
|
while (potentialPluginPackageJsonDirectory !== '/') {
|
|
28
32
|
const packageJsonPath = path_1.default.join(potentialPluginPackageJsonDirectory, 'package.json');
|
|
@@ -35,8 +39,8 @@ async function getPluginVersion(pluginPath, siteDir) {
|
|
|
35
39
|
}
|
|
36
40
|
return {
|
|
37
41
|
type: 'package',
|
|
38
|
-
name: await
|
|
39
|
-
version: await
|
|
42
|
+
name: await loadPackageJsonName(packageJsonPath),
|
|
43
|
+
version: await loadPackageJsonVersion(packageJsonPath),
|
|
40
44
|
};
|
|
41
45
|
}
|
|
42
46
|
potentialPluginPackageJsonDirectory = path_1.default.dirname(potentialPluginPackageJsonDirectory);
|
|
@@ -46,7 +50,7 @@ async function getPluginVersion(pluginPath, siteDir) {
|
|
|
46
50
|
// script in the parent directory of the site.
|
|
47
51
|
return { type: 'local' };
|
|
48
52
|
}
|
|
49
|
-
exports.
|
|
53
|
+
exports.loadPluginVersion = loadPluginVersion;
|
|
50
54
|
/**
|
|
51
55
|
* We want all `@docusaurus/*` packages to have the exact same version!
|
|
52
56
|
* @see https://github.com/facebook/docusaurus/issues/3371
|
|
@@ -65,10 +69,10 @@ Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?
|
|
|
65
69
|
}
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
|
-
|
|
72
|
+
function createSiteMetadata({ siteVersion, plugins, }) {
|
|
69
73
|
const siteMetadata = {
|
|
70
74
|
docusaurusVersion: utils_1.DOCUSAURUS_VERSION,
|
|
71
|
-
siteVersion
|
|
75
|
+
siteVersion,
|
|
72
76
|
pluginVersions: Object.fromEntries(plugins
|
|
73
77
|
.filter(({ version: { type } }) => type !== 'synthetic')
|
|
74
78
|
.map(({ name, version }) => [name, version])),
|
|
@@ -76,4 +80,4 @@ async function loadSiteMetadata({ plugins, siteDir, }) {
|
|
|
76
80
|
checkDocusaurusPackagesVersion(siteMetadata);
|
|
77
81
|
return siteMetadata;
|
|
78
82
|
}
|
|
79
|
-
exports.
|
|
83
|
+
exports.createSiteMetadata = createSiteMetadata;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import type { TranslationFileContent, TranslationFile, CodeTranslations, InitializedPlugin } from '@docusaurus/types';
|
|
7
|
+
import type { TranslationFileContent, TranslationFile, CodeTranslations, InitializedPlugin, LoadedPlugin } from '@docusaurus/types';
|
|
8
8
|
export type WriteTranslationsOptions = {
|
|
9
9
|
override?: boolean;
|
|
10
10
|
messagePrefix?: string;
|
|
@@ -23,9 +23,16 @@ export declare function localizePluginTranslationFile({ localizationDir, plugin,
|
|
|
23
23
|
plugin: InitializedPlugin;
|
|
24
24
|
translationFile: TranslationFile;
|
|
25
25
|
}): Promise<TranslationFile>;
|
|
26
|
-
export declare function
|
|
26
|
+
export declare function mergeCodeTranslations(codeTranslations: CodeTranslations[]): CodeTranslations;
|
|
27
|
+
export declare function loadPluginsDefaultCodeTranslationMessages(plugins: InitializedPlugin[]): Promise<CodeTranslations>;
|
|
28
|
+
export declare function getPluginsDefaultCodeTranslations({ plugins, }: {
|
|
29
|
+
plugins: LoadedPlugin[];
|
|
30
|
+
}): CodeTranslations;
|
|
27
31
|
export declare function applyDefaultCodeTranslations({ extractedCodeTranslations, defaultCodeMessages, }: {
|
|
28
32
|
extractedCodeTranslations: TranslationFileContent;
|
|
29
33
|
defaultCodeMessages: CodeTranslations;
|
|
30
34
|
}): TranslationFileContent;
|
|
35
|
+
export declare function loadSiteCodeTranslations({ localizationDir, }: {
|
|
36
|
+
localizationDir: string;
|
|
37
|
+
}): Promise<CodeTranslations>;
|
|
31
38
|
export {};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.applyDefaultCodeTranslations = exports.
|
|
9
|
+
exports.loadSiteCodeTranslations = exports.applyDefaultCodeTranslations = exports.getPluginsDefaultCodeTranslations = exports.loadPluginsDefaultCodeTranslationMessages = exports.mergeCodeTranslations = exports.localizePluginTranslationFile = exports.writePluginTranslations = exports.writeCodeTranslations = exports.readCodeTranslationFileContent = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
12
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
@@ -145,11 +145,22 @@ async function localizePluginTranslationFile({ localizationDir, plugin, translat
|
|
|
145
145
|
return translationFile;
|
|
146
146
|
}
|
|
147
147
|
exports.localizePluginTranslationFile = localizePluginTranslationFile;
|
|
148
|
-
|
|
148
|
+
function mergeCodeTranslations(codeTranslations) {
|
|
149
|
+
return codeTranslations.reduce((allCodeTranslations, current) => ({
|
|
150
|
+
...allCodeTranslations,
|
|
151
|
+
...current,
|
|
152
|
+
}), {});
|
|
153
|
+
}
|
|
154
|
+
exports.mergeCodeTranslations = mergeCodeTranslations;
|
|
155
|
+
async function loadPluginsDefaultCodeTranslationMessages(plugins) {
|
|
149
156
|
const pluginsMessages = await Promise.all(plugins.map((plugin) => plugin.getDefaultCodeTranslationMessages?.() ?? {}));
|
|
150
|
-
return pluginsMessages
|
|
157
|
+
return mergeCodeTranslations(pluginsMessages);
|
|
158
|
+
}
|
|
159
|
+
exports.loadPluginsDefaultCodeTranslationMessages = loadPluginsDefaultCodeTranslationMessages;
|
|
160
|
+
function getPluginsDefaultCodeTranslations({ plugins, }) {
|
|
161
|
+
return mergeCodeTranslations(plugins.map((p) => p.defaultCodeTranslations));
|
|
151
162
|
}
|
|
152
|
-
exports.
|
|
163
|
+
exports.getPluginsDefaultCodeTranslations = getPluginsDefaultCodeTranslations;
|
|
153
164
|
function applyDefaultCodeTranslations({ extractedCodeTranslations, defaultCodeMessages, }) {
|
|
154
165
|
const unusedDefaultCodeMessages = lodash_1.default.difference(Object.keys(defaultCodeMessages), Object.keys(extractedCodeTranslations));
|
|
155
166
|
if (unusedDefaultCodeMessages.length > 0) {
|
|
@@ -162,3 +173,9 @@ Please report this Docusaurus issue. name=${unusedDefaultCodeMessages}`;
|
|
|
162
173
|
}));
|
|
163
174
|
}
|
|
164
175
|
exports.applyDefaultCodeTranslations = applyDefaultCodeTranslations;
|
|
176
|
+
async function loadSiteCodeTranslations({ localizationDir, }) {
|
|
177
|
+
const codeTranslationFileContent = (await readCodeTranslationFileContent({ localizationDir })) ?? {};
|
|
178
|
+
// We only need key->message for code translations
|
|
179
|
+
return lodash_1.default.mapValues(codeTranslationFileContent, (value) => value.message);
|
|
180
|
+
}
|
|
181
|
+
exports.loadSiteCodeTranslations = loadSiteCodeTranslations;
|
package/lib/server/utils.d.ts
CHANGED
|
@@ -5,6 +5,4 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import { Globby } from '@docusaurus/utils';
|
|
8
|
-
import type { RouteConfig } from '@docusaurus/types';
|
|
9
|
-
export declare function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[];
|
|
10
8
|
export declare function safeGlobby(patterns: string[], options?: Globby.GlobbyOptions): Promise<string[]>;
|
package/lib/server/utils.js
CHANGED
|
@@ -6,18 +6,10 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.safeGlobby =
|
|
9
|
+
exports.safeGlobby = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
12
|
const utils_1 = require("@docusaurus/utils");
|
|
13
|
-
// Recursively get the final routes (routes with no subroutes)
|
|
14
|
-
function getAllFinalRoutes(routeConfig) {
|
|
15
|
-
function getFinalRoutes(route) {
|
|
16
|
-
return route.routes ? route.routes.flatMap(getFinalRoutes) : [route];
|
|
17
|
-
}
|
|
18
|
-
return routeConfig.flatMap(getFinalRoutes);
|
|
19
|
-
}
|
|
20
|
-
exports.getAllFinalRoutes = getAllFinalRoutes;
|
|
21
13
|
// Globby that fix Windows path patterns
|
|
22
14
|
// See https://github.com/facebook/docusaurus/pull/4222#issuecomment-795517329
|
|
23
15
|
async function safeGlobby(patterns, options) {
|
package/lib/ssg.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { AppRenderer, SiteCollectedData } from './common';
|
|
8
|
+
import type { Manifest } from 'react-loadable-ssr-addon-v5-slorber';
|
|
9
|
+
import type { SSRTemplateCompiled } from './templates/templates';
|
|
10
|
+
export type SSGParams = {
|
|
11
|
+
trailingSlash: boolean | undefined;
|
|
12
|
+
manifest: Manifest;
|
|
13
|
+
headTags: string;
|
|
14
|
+
preBodyTags: string;
|
|
15
|
+
postBodyTags: string;
|
|
16
|
+
outDir: string;
|
|
17
|
+
baseUrl: string;
|
|
18
|
+
noIndex: boolean;
|
|
19
|
+
DOCUSAURUS_VERSION: string;
|
|
20
|
+
ssrTemplate: SSRTemplateCompiled;
|
|
21
|
+
};
|
|
22
|
+
export declare function loadAppRenderer({ serverBundlePath, }: {
|
|
23
|
+
serverBundlePath: string;
|
|
24
|
+
}): Promise<AppRenderer>;
|
|
25
|
+
export declare function generateStaticFiles({ pathnames, renderer, params, }: {
|
|
26
|
+
pathnames: string[];
|
|
27
|
+
renderer: AppRenderer;
|
|
28
|
+
params: SSGParams;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
collectedData: SiteCollectedData;
|
|
31
|
+
}>;
|
package/lib/ssg.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateStaticFiles = exports.loadAppRenderer = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
|
+
const module_1 = require("module");
|
|
13
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
14
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
15
|
+
const eval_1 = tslib_1.__importDefault(require("eval"));
|
|
16
|
+
const p_map_1 = tslib_1.__importDefault(require("p-map"));
|
|
17
|
+
const html_minifier_terser_1 = require("html-minifier-terser");
|
|
18
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
19
|
+
const utils_1 = require("./utils");
|
|
20
|
+
const templates_1 = require("./templates/templates");
|
|
21
|
+
// Secret way to set SSR plugin concurrency option
|
|
22
|
+
// Waiting for feedback before documenting this officially?
|
|
23
|
+
const Concurrency = process.env.DOCUSAURUS_SSR_CONCURRENCY
|
|
24
|
+
? parseInt(process.env.DOCUSAURUS_SSR_CONCURRENCY, 10)
|
|
25
|
+
: // Not easy to define a reasonable option default
|
|
26
|
+
// Will still be better than Infinity
|
|
27
|
+
// See also https://github.com/sindresorhus/p-map/issues/24
|
|
28
|
+
32;
|
|
29
|
+
async function loadAppRenderer({ serverBundlePath, }) {
|
|
30
|
+
const source = await utils_1.PerfLogger.async(`Load server bundle`, () => fs_extra_1.default.readFile(serverBundlePath));
|
|
31
|
+
utils_1.PerfLogger.log(`Server bundle size = ${(source.length / 1024000).toFixed(3)} MB`);
|
|
32
|
+
const filename = path_1.default.basename(serverBundlePath);
|
|
33
|
+
const globals = {
|
|
34
|
+
// When using "new URL('file.js', import.meta.url)", Webpack will emit
|
|
35
|
+
// __filename, and this plugin will throw. not sure the __filename value
|
|
36
|
+
// has any importance for this plugin, just using an empty string to
|
|
37
|
+
// avoid the error. See https://github.com/facebook/docusaurus/issues/4922
|
|
38
|
+
__filename: '',
|
|
39
|
+
// This uses module.createRequire() instead of very old "require-like" lib
|
|
40
|
+
// See also: https://github.com/pierrec/node-eval/issues/33
|
|
41
|
+
require: (0, module_1.createRequire)(serverBundlePath),
|
|
42
|
+
};
|
|
43
|
+
const serverEntry = await utils_1.PerfLogger.async(`Evaluate server bundle`, () => (0, eval_1.default)(source,
|
|
44
|
+
/* filename: */ filename,
|
|
45
|
+
/* scope: */ globals,
|
|
46
|
+
/* includeGlobals: */ true));
|
|
47
|
+
if (!serverEntry?.default || typeof serverEntry.default !== 'function') {
|
|
48
|
+
throw new Error(`Server bundle export from "${filename}" must be a function that renders the Docusaurus React app.`);
|
|
49
|
+
}
|
|
50
|
+
return serverEntry.default;
|
|
51
|
+
}
|
|
52
|
+
exports.loadAppRenderer = loadAppRenderer;
|
|
53
|
+
function pathnameToFilename({ pathname, trailingSlash, }) {
|
|
54
|
+
const outputFileName = pathname.replace(/^[/\\]/, ''); // Remove leading slashes for webpack-dev-server
|
|
55
|
+
// Paths ending with .html are left untouched
|
|
56
|
+
if (/\.html?$/i.test(outputFileName)) {
|
|
57
|
+
return outputFileName;
|
|
58
|
+
}
|
|
59
|
+
// Legacy retro-compatible behavior
|
|
60
|
+
if (typeof trailingSlash === 'undefined') {
|
|
61
|
+
return path_1.default.join(outputFileName, 'index.html');
|
|
62
|
+
}
|
|
63
|
+
// New behavior: we can say if we prefer file/folder output
|
|
64
|
+
// Useful resource: https://github.com/slorber/trailing-slash-guide
|
|
65
|
+
if (pathname === '' || pathname.endsWith('/') || trailingSlash) {
|
|
66
|
+
return path_1.default.join(outputFileName, 'index.html');
|
|
67
|
+
}
|
|
68
|
+
return `${outputFileName}.html`;
|
|
69
|
+
}
|
|
70
|
+
async function generateStaticFiles({ pathnames, renderer, params, }) {
|
|
71
|
+
// Note that we catch all async errors on purpose
|
|
72
|
+
// Docusaurus presents all the SSG errors to the user, not just the first one
|
|
73
|
+
const results = await (0, p_map_1.default)(pathnames, async (pathname) => generateStaticFile({
|
|
74
|
+
pathname,
|
|
75
|
+
renderer,
|
|
76
|
+
params,
|
|
77
|
+
}).then((result) => ({ pathname, result, error: null }), (error) => ({ pathname, result: null, error: error })), { concurrency: Concurrency });
|
|
78
|
+
const [allSSGErrors, allSSGSuccesses] = lodash_1.default.partition(results, (r) => !!r.error);
|
|
79
|
+
if (allSSGErrors.length > 0) {
|
|
80
|
+
const message = `Docusaurus static site generation failed for ${allSSGErrors.length} path${allSSGErrors.length ? 's' : ''}:\n- ${allSSGErrors
|
|
81
|
+
.map((ssgError) => logger_1.default.path(ssgError.pathname))
|
|
82
|
+
.join('\n- ')}`;
|
|
83
|
+
// Note logging this error properly require using inspect(error,{depth})
|
|
84
|
+
// See https://github.com/nodejs/node/issues/51637
|
|
85
|
+
throw new Error(message, {
|
|
86
|
+
cause: new AggregateError(allSSGErrors.map((ssgError) => ssgError.error)),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const collectedData = lodash_1.default.chain(allSSGSuccesses)
|
|
90
|
+
.keyBy((success) => success.pathname)
|
|
91
|
+
.mapValues((ssgSuccess) => ssgSuccess.result.collectedData)
|
|
92
|
+
.value();
|
|
93
|
+
return { collectedData };
|
|
94
|
+
}
|
|
95
|
+
exports.generateStaticFiles = generateStaticFiles;
|
|
96
|
+
async function generateStaticFile({ pathname, renderer, params, }) {
|
|
97
|
+
try {
|
|
98
|
+
// This only renders the app HTML
|
|
99
|
+
const result = await renderer({
|
|
100
|
+
pathname,
|
|
101
|
+
});
|
|
102
|
+
// This renders the full page HTML, including head tags...
|
|
103
|
+
const fullPageHtml = (0, templates_1.renderSSRTemplate)({
|
|
104
|
+
params,
|
|
105
|
+
result,
|
|
106
|
+
});
|
|
107
|
+
const content = await minifyHtml(fullPageHtml);
|
|
108
|
+
await writeStaticFile({
|
|
109
|
+
pathname,
|
|
110
|
+
content,
|
|
111
|
+
params,
|
|
112
|
+
});
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
catch (errorUnknown) {
|
|
116
|
+
const error = errorUnknown;
|
|
117
|
+
const tips = getSSGErrorTips(error);
|
|
118
|
+
const message = logger_1.default.interpolate `Can't render static file for pathname path=${pathname}${tips ? `\n\n${tips}` : ''}`;
|
|
119
|
+
throw new Error(message, {
|
|
120
|
+
cause: error,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function getSSGErrorTips(error) {
|
|
125
|
+
const parts = [];
|
|
126
|
+
const isNotDefinedErrorRegex = /(?:window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
|
|
127
|
+
if (isNotDefinedErrorRegex.test(error.message)) {
|
|
128
|
+
parts.push(`It looks like you are using code that should run on the client-side only.
|
|
129
|
+
To get around it, try using one of:
|
|
130
|
+
- ${logger_1.default.code('<BrowserOnly>')} (${logger_1.default.url('https://docusaurus.io/docs/docusaurus-core/#browseronly')})
|
|
131
|
+
- ${logger_1.default.code('ExecutionEnvironment')} (${logger_1.default.url('https://docusaurus.io/docs/docusaurus-core/#executionenvironment')}).
|
|
132
|
+
It might also require to wrap your client code in ${logger_1.default.code('useEffect')} hook and/or import a third-party library dynamically (if any).`);
|
|
133
|
+
}
|
|
134
|
+
return parts.join('\n');
|
|
135
|
+
}
|
|
136
|
+
async function writeStaticFile({ content, pathname, params, }) {
|
|
137
|
+
function removeBaseUrl(p, baseUrl) {
|
|
138
|
+
return baseUrl === '/' ? p : p.replace(new RegExp(`^${baseUrl}`), '/');
|
|
139
|
+
}
|
|
140
|
+
const filename = pathnameToFilename({
|
|
141
|
+
pathname: removeBaseUrl(pathname, params.baseUrl),
|
|
142
|
+
trailingSlash: params.trailingSlash,
|
|
143
|
+
});
|
|
144
|
+
const filePath = path_1.default.join(params.outDir, filename);
|
|
145
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
146
|
+
await fs_extra_1.default.writeFile(filePath, content);
|
|
147
|
+
}
|
|
148
|
+
async function minifyHtml(html) {
|
|
149
|
+
try {
|
|
150
|
+
if (process.env.SKIP_HTML_MINIFICATION === 'true') {
|
|
151
|
+
return html;
|
|
152
|
+
}
|
|
153
|
+
// Minify html with https://github.com/DanielRuf/html-minifier-terser
|
|
154
|
+
return await (0, html_minifier_terser_1.minify)(html, {
|
|
155
|
+
removeComments: false,
|
|
156
|
+
removeRedundantAttributes: true,
|
|
157
|
+
removeEmptyAttributes: true,
|
|
158
|
+
removeScriptTypeAttributes: true,
|
|
159
|
+
removeStyleLinkTypeAttributes: true,
|
|
160
|
+
useShortDoctype: true,
|
|
161
|
+
minifyJS: true,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
throw new Error('HTML minification failed', { cause: err });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { SSGParams } from '../ssg';
|
|
8
|
+
import type { AppRenderResult } from '../common';
|
|
9
|
+
export type SSRTemplateData = {
|
|
10
|
+
appHtml: string;
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
htmlAttributes: string;
|
|
13
|
+
bodyAttributes: string;
|
|
14
|
+
headTags: string;
|
|
15
|
+
preBodyTags: string;
|
|
16
|
+
postBodyTags: string;
|
|
17
|
+
metaAttributes: string[];
|
|
18
|
+
scripts: string[];
|
|
19
|
+
stylesheets: string[];
|
|
20
|
+
noIndex: boolean;
|
|
21
|
+
version: string;
|
|
22
|
+
};
|
|
23
|
+
export type SSRTemplateCompiled = (data: SSRTemplateData) => string;
|
|
24
|
+
export declare function compileSSRTemplate(template: string): Promise<SSRTemplateCompiled>;
|
|
25
|
+
export declare function renderSSRTemplate({ params, result, }: {
|
|
26
|
+
params: SSGParams;
|
|
27
|
+
result: AppRenderResult;
|
|
28
|
+
}): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.renderSSRTemplate = exports.compileSSRTemplate = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const eta = tslib_1.__importStar(require("eta"));
|
|
12
|
+
const react_loadable_ssr_addon_v5_slorber_1 = require("react-loadable-ssr-addon-v5-slorber");
|
|
13
|
+
async function compileSSRTemplate(template) {
|
|
14
|
+
const compiledTemplate = eta.compile(template.trim(), {
|
|
15
|
+
rmWhitespace: true,
|
|
16
|
+
});
|
|
17
|
+
return (data) => compiledTemplate(data, eta.defaultConfig);
|
|
18
|
+
}
|
|
19
|
+
exports.compileSSRTemplate = compileSSRTemplate;
|
|
20
|
+
/**
|
|
21
|
+
* Given a list of modules that were SSR an d
|
|
22
|
+
* @param modules
|
|
23
|
+
* @param manifest
|
|
24
|
+
*/
|
|
25
|
+
function getScriptsAndStylesheets({ modules, manifest, }) {
|
|
26
|
+
// Get all required assets for this particular page
|
|
27
|
+
// based on client manifest information.
|
|
28
|
+
const modulesToBeLoaded = [...manifest.entrypoints, ...Array.from(modules)];
|
|
29
|
+
const bundles = (0, react_loadable_ssr_addon_v5_slorber_1.getBundles)(manifest, modulesToBeLoaded);
|
|
30
|
+
const stylesheets = (bundles.css ?? []).map((b) => b.file);
|
|
31
|
+
const scripts = (bundles.js ?? []).map((b) => b.file);
|
|
32
|
+
return { scripts, stylesheets };
|
|
33
|
+
}
|
|
34
|
+
function renderSSRTemplate({ params, result, }) {
|
|
35
|
+
const { baseUrl, headTags, preBodyTags, postBodyTags, manifest, noIndex, DOCUSAURUS_VERSION, ssrTemplate, } = params;
|
|
36
|
+
const { html: appHtml, collectedData: { modules, helmet }, } = result;
|
|
37
|
+
const { scripts, stylesheets } = getScriptsAndStylesheets({ manifest, modules });
|
|
38
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
39
|
+
const bodyAttributes = helmet.bodyAttributes.toString();
|
|
40
|
+
const metaStrings = [
|
|
41
|
+
helmet.title.toString(),
|
|
42
|
+
helmet.meta.toString(),
|
|
43
|
+
helmet.link.toString(),
|
|
44
|
+
helmet.script.toString(),
|
|
45
|
+
];
|
|
46
|
+
const metaAttributes = metaStrings.filter(Boolean);
|
|
47
|
+
const data = {
|
|
48
|
+
appHtml,
|
|
49
|
+
baseUrl,
|
|
50
|
+
htmlAttributes,
|
|
51
|
+
bodyAttributes,
|
|
52
|
+
headTags,
|
|
53
|
+
preBodyTags,
|
|
54
|
+
postBodyTags,
|
|
55
|
+
metaAttributes,
|
|
56
|
+
scripts,
|
|
57
|
+
stylesheets,
|
|
58
|
+
noIndex,
|
|
59
|
+
version: DOCUSAURUS_VERSION,
|
|
60
|
+
};
|
|
61
|
+
return ssrTemplate(data);
|
|
62
|
+
}
|
|
63
|
+
exports.renderSSRTemplate = renderSSRTemplate;
|
package/lib/utils.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const PerfDebuggingEnabled: boolean;
|
|
2
|
+
type PerfLoggerAPI = {
|
|
3
|
+
start: (label: string) => void;
|
|
4
|
+
end: (label: string) => void;
|
|
5
|
+
log: (message: string) => void;
|
|
6
|
+
async: <Result>(label: string, asyncFn: () => Result | Promise<Result>) => Promise<Result>;
|
|
7
|
+
};
|
|
8
|
+
export declare const PerfLogger: PerfLoggerAPI;
|
|
9
|
+
export {};
|