@docusaurus/core 0.0.0-5857 → 0.0.0-5860
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/lib/commands/build.d.ts +2 -2
- package/lib/commands/build.js +6 -6
- package/lib/commands/deploy.d.ts +2 -2
- package/lib/commands/deploy.js +2 -2
- package/lib/commands/external.js +2 -2
- package/lib/commands/serve.d.ts +2 -2
- 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 +88 -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/context.js +2 -2
- package/lib/commands/writeHeadingIds.js +2 -2
- package/lib/commands/writeTranslations.d.ts +2 -2
- package/lib/commands/writeTranslations.js +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/server/brokenLinks.js +2 -2
- 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/i18n.d.ts +2 -2
- package/lib/server/plugins/{index.d.ts → plugins.d.ts} +15 -4
- package/lib/server/plugins/plugins.js +176 -0
- package/lib/server/plugins/routeConfig.d.ts +1 -1
- package/lib/server/plugins/routeConfig.js +4 -4
- package/lib/server/routes.d.ts +4 -45
- package/lib/server/routes.js +15 -166
- package/lib/server/{index.d.ts → site.d.ts} +12 -4
- package/lib/server/site.js +167 -0
- package/lib/server/translations/translations.d.ts +3 -0
- package/lib/server/translations/translations.js +7 -1
- package/lib/server/utils.d.ts +0 -2
- package/lib/server/utils.js +1 -9
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +14 -3
- package/package.json +10 -10
- package/lib/commands/start.js +0 -242
- package/lib/server/index.js +0 -154
- package/lib/server/plugins/index.js +0 -106
|
@@ -12,7 +12,7 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
|
12
12
|
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
13
13
|
const react_router_config_1 = require("react-router-config");
|
|
14
14
|
const utils_1 = require("@docusaurus/utils");
|
|
15
|
-
const
|
|
15
|
+
const routes_1 = require("./routes");
|
|
16
16
|
function matchRoutes(routeConfig, pathname) {
|
|
17
17
|
// @ts-expect-error: React router types RouteConfig with an actual React
|
|
18
18
|
// component, but we load route components with string paths.
|
|
@@ -127,7 +127,7 @@ function getBrokenLinksForPage({ pagePath, helper, }) {
|
|
|
127
127
|
*/
|
|
128
128
|
function filterIntermediateRoutes(routesInput) {
|
|
129
129
|
const routesWithout404 = routesInput.filter((route) => route.path !== '*');
|
|
130
|
-
return (0,
|
|
130
|
+
return (0, routes_1.getAllFinalRoutes)(routesWithout404);
|
|
131
131
|
}
|
|
132
132
|
function getBrokenLinks({ collectedLinks, routes, }) {
|
|
133
133
|
const filteredRoutes = filterIntermediateRoutes(routes);
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { CodeTranslations, DocusaurusConfig, GlobalData, I18n, RouteConfig, SiteMetadata } from '@docusaurus/types';
|
|
8
|
+
type CodegenParams = {
|
|
9
|
+
generatedFilesDir: string;
|
|
10
|
+
siteConfig: DocusaurusConfig;
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
clientModules: string[];
|
|
13
|
+
globalData: GlobalData;
|
|
14
|
+
i18n: I18n;
|
|
15
|
+
codeTranslations: CodeTranslations;
|
|
16
|
+
siteMetadata: SiteMetadata;
|
|
17
|
+
routes: RouteConfig[];
|
|
18
|
+
};
|
|
19
|
+
export declare function generateSiteFiles(params: CodegenParams): Promise<void>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
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.generateSiteFiles = void 0;
|
|
10
|
+
const utils_1 = require("@docusaurus/utils");
|
|
11
|
+
const codegenRoutes_1 = require("./codegenRoutes");
|
|
12
|
+
function genWarning({ generatedFilesDir }) {
|
|
13
|
+
return (0, utils_1.generate)(generatedFilesDir,
|
|
14
|
+
// cSpell:ignore DONT
|
|
15
|
+
'DONT-EDIT-THIS-FOLDER', `This folder stores temp files that Docusaurus' client bundler accesses.
|
|
16
|
+
|
|
17
|
+
DO NOT hand-modify files in this folder because they will be overwritten in the
|
|
18
|
+
next build. You can clear all build artifacts (including this folder) with the
|
|
19
|
+
\`docusaurus clear\` command.
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
function genSiteConfig({ generatedFilesDir, siteConfig, }) {
|
|
23
|
+
return (0, utils_1.generate)(generatedFilesDir, `${utils_1.DEFAULT_CONFIG_FILE_NAME}.mjs`, `/*
|
|
24
|
+
* AUTOGENERATED - DON'T EDIT
|
|
25
|
+
* Your edits in this file will be overwritten in the next build!
|
|
26
|
+
* Modify the docusaurus.config.js file at your site's root instead.
|
|
27
|
+
*/
|
|
28
|
+
export default ${JSON.stringify(siteConfig, null, 2)};
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
function genClientModules({ generatedFilesDir, clientModules, }) {
|
|
32
|
+
return (0, utils_1.generate)(generatedFilesDir, 'client-modules.js', `export default [
|
|
33
|
+
${clientModules
|
|
34
|
+
// Use `require()` because `import()` is async but client modules can have CSS
|
|
35
|
+
// and the order matters for loading CSS.
|
|
36
|
+
.map((clientModule) => ` require("${(0, utils_1.escapePath)(clientModule)}"),`)
|
|
37
|
+
.join('\n')}
|
|
38
|
+
];
|
|
39
|
+
`);
|
|
40
|
+
}
|
|
41
|
+
function genGlobalData({ generatedFilesDir, globalData, }) {
|
|
42
|
+
return (0, utils_1.generate)(generatedFilesDir, 'globalData.json', JSON.stringify(globalData, null, 2));
|
|
43
|
+
}
|
|
44
|
+
function genI18n({ generatedFilesDir, i18n, }) {
|
|
45
|
+
return (0, utils_1.generate)(generatedFilesDir, 'i18n.json', JSON.stringify(i18n, null, 2));
|
|
46
|
+
}
|
|
47
|
+
function genCodeTranslations({ generatedFilesDir, codeTranslations, }) {
|
|
48
|
+
return (0, utils_1.generate)(generatedFilesDir, 'codeTranslations.json', JSON.stringify(codeTranslations, null, 2));
|
|
49
|
+
}
|
|
50
|
+
function genSiteMetadata({ generatedFilesDir, siteMetadata, }) {
|
|
51
|
+
return (0, utils_1.generate)(generatedFilesDir, 'site-metadata.json', JSON.stringify(siteMetadata, null, 2));
|
|
52
|
+
}
|
|
53
|
+
async function generateSiteFiles(params) {
|
|
54
|
+
await Promise.all([
|
|
55
|
+
genWarning(params),
|
|
56
|
+
genClientModules(params),
|
|
57
|
+
genSiteConfig(params),
|
|
58
|
+
(0, codegenRoutes_1.generateRouteFiles)(params),
|
|
59
|
+
genGlobalData(params),
|
|
60
|
+
genSiteMetadata(params),
|
|
61
|
+
genI18n(params),
|
|
62
|
+
genCodeTranslations(params),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
exports.generateSiteFiles = generateSiteFiles;
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { RouteConfig, RouteChunkNames } from '@docusaurus/types';
|
|
8
|
+
type RoutesCode = {
|
|
9
|
+
/** Serialized routes config that can be directly emitted into temp file. */
|
|
10
|
+
routesConfig: string;
|
|
11
|
+
/** @see {ChunkNames} */
|
|
12
|
+
routesChunkNames: RouteChunkNames;
|
|
13
|
+
/**
|
|
14
|
+
* A map from chunk name to module paths. Module paths would have backslash
|
|
15
|
+
* escaped already, so they can be directly printed.
|
|
16
|
+
*/
|
|
17
|
+
registry: {
|
|
18
|
+
[chunkName: string]: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Generates a unique chunk name that can be used in the chunk registry.
|
|
23
|
+
*
|
|
24
|
+
* @param modulePath A path to generate chunk name from. The actual value has no
|
|
25
|
+
* semantic significance.
|
|
26
|
+
* @param prefix A prefix to append to the chunk name, to avoid name clash.
|
|
27
|
+
* @param preferredName Chunk names default to `modulePath`, and this can supply
|
|
28
|
+
* a more human-readable name.
|
|
29
|
+
* @param shortId When `true`, the chunk name would only be a hash without any
|
|
30
|
+
* other characters. Useful for bundle size. Defaults to `true` in production.
|
|
31
|
+
*/
|
|
32
|
+
export declare function genChunkName(modulePath: string, prefix?: string, preferredName?: string, shortId?: boolean): string;
|
|
33
|
+
/**
|
|
34
|
+
* Routes are prepared into three temp files:
|
|
35
|
+
*
|
|
36
|
+
* - `routesConfig`, the route config passed to react-router. This file is kept
|
|
37
|
+
* minimal, because it can't be code-splitted.
|
|
38
|
+
* - `routesChunkNames`, a mapping from route paths (hashed) to code-splitted
|
|
39
|
+
* chunk names.
|
|
40
|
+
* - `registry`, a mapping from chunk names to options for react-loadable.
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateRoutesCode(routeConfigs: RouteConfig[]): RoutesCode;
|
|
43
|
+
type GenerateRouteFilesParams = {
|
|
44
|
+
generatedFilesDir: string;
|
|
45
|
+
routes: RouteConfig[];
|
|
46
|
+
baseUrl: string;
|
|
47
|
+
};
|
|
48
|
+
export declare function generateRouteFiles({ generatedFilesDir, routes, }: GenerateRouteFilesParams): Promise<void>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
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.generateRouteFiles = exports.generateRoutesCode = exports.genChunkName = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const querystring_1 = tslib_1.__importDefault(require("querystring"));
|
|
12
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
13
|
+
const utils_1 = require("@docusaurus/utils");
|
|
14
|
+
/** Indents every line of `str` by one level. */
|
|
15
|
+
function indent(str) {
|
|
16
|
+
return ` ${str.replace(/\n/g, `\n `)}`;
|
|
17
|
+
}
|
|
18
|
+
const chunkNameCache = new Map();
|
|
19
|
+
const chunkNameCount = new Map();
|
|
20
|
+
/**
|
|
21
|
+
* Generates a unique chunk name that can be used in the chunk registry.
|
|
22
|
+
*
|
|
23
|
+
* @param modulePath A path to generate chunk name from. The actual value has no
|
|
24
|
+
* semantic significance.
|
|
25
|
+
* @param prefix A prefix to append to the chunk name, to avoid name clash.
|
|
26
|
+
* @param preferredName Chunk names default to `modulePath`, and this can supply
|
|
27
|
+
* a more human-readable name.
|
|
28
|
+
* @param shortId When `true`, the chunk name would only be a hash without any
|
|
29
|
+
* other characters. Useful for bundle size. Defaults to `true` in production.
|
|
30
|
+
*/
|
|
31
|
+
function genChunkName(modulePath, prefix, preferredName, shortId = process.env.NODE_ENV === 'production') {
|
|
32
|
+
let chunkName = chunkNameCache.get(modulePath);
|
|
33
|
+
if (!chunkName) {
|
|
34
|
+
if (shortId) {
|
|
35
|
+
chunkName = (0, utils_1.simpleHash)(modulePath, 8);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
let str = modulePath;
|
|
39
|
+
if (preferredName) {
|
|
40
|
+
const shortHash = (0, utils_1.simpleHash)(modulePath, 3);
|
|
41
|
+
str = `${preferredName}${shortHash}`;
|
|
42
|
+
}
|
|
43
|
+
const name = (0, utils_1.docuHash)(str);
|
|
44
|
+
chunkName = prefix ? `${prefix}---${name}` : name;
|
|
45
|
+
}
|
|
46
|
+
const seenCount = (chunkNameCount.get(chunkName) ?? 0) + 1;
|
|
47
|
+
if (seenCount > 1) {
|
|
48
|
+
chunkName += seenCount.toString(36);
|
|
49
|
+
}
|
|
50
|
+
chunkNameCache.set(modulePath, chunkName);
|
|
51
|
+
chunkNameCount.set(chunkName, seenCount);
|
|
52
|
+
}
|
|
53
|
+
return chunkName;
|
|
54
|
+
}
|
|
55
|
+
exports.genChunkName = genChunkName;
|
|
56
|
+
/**
|
|
57
|
+
* Takes a piece of route config, and serializes it into raw JS code. The shape
|
|
58
|
+
* is the same as react-router's `RouteConfig`. Formatting is similar to
|
|
59
|
+
* `JSON.stringify` but without all the quotes.
|
|
60
|
+
*/
|
|
61
|
+
function serializeRouteConfig({ routePath, routeHash, exact, subroutesCodeStrings, props, }) {
|
|
62
|
+
const parts = [
|
|
63
|
+
`path: '${routePath}'`,
|
|
64
|
+
`component: ComponentCreator('${routePath}', '${routeHash}')`,
|
|
65
|
+
];
|
|
66
|
+
if (exact) {
|
|
67
|
+
parts.push(`exact: true`);
|
|
68
|
+
}
|
|
69
|
+
if (subroutesCodeStrings) {
|
|
70
|
+
parts.push(`routes: [
|
|
71
|
+
${indent(subroutesCodeStrings.join(',\n'))}
|
|
72
|
+
]`);
|
|
73
|
+
}
|
|
74
|
+
Object.entries(props).forEach(([propName, propValue]) => {
|
|
75
|
+
const isIdentifier = /^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(propName);
|
|
76
|
+
const key = isIdentifier ? propName : JSON.stringify(propName);
|
|
77
|
+
parts.push(`${key}: ${JSON.stringify(propValue)}`);
|
|
78
|
+
});
|
|
79
|
+
return `{
|
|
80
|
+
${indent(parts.join(',\n'))}
|
|
81
|
+
}`;
|
|
82
|
+
}
|
|
83
|
+
const isModule = (value) => typeof value === 'string' ||
|
|
84
|
+
(typeof value === 'object' &&
|
|
85
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
86
|
+
!!value?.__import);
|
|
87
|
+
/**
|
|
88
|
+
* Takes a {@link Module} (which is nothing more than a path plus some metadata
|
|
89
|
+
* like query) and returns the string path it represents.
|
|
90
|
+
*/
|
|
91
|
+
function getModulePath(target) {
|
|
92
|
+
if (typeof target === 'string') {
|
|
93
|
+
return target;
|
|
94
|
+
}
|
|
95
|
+
const queryStr = target.query ? `?${querystring_1.default.stringify(target.query)}` : '';
|
|
96
|
+
return `${target.path}${queryStr}`;
|
|
97
|
+
}
|
|
98
|
+
function genChunkNames(routeModule, prefix, name, res) {
|
|
99
|
+
if (isModule(routeModule)) {
|
|
100
|
+
// This is a leaf node, no need to recurse
|
|
101
|
+
const modulePath = getModulePath(routeModule);
|
|
102
|
+
const chunkName = genChunkName(modulePath, prefix, name);
|
|
103
|
+
res.registry[chunkName] = (0, utils_1.escapePath)(modulePath);
|
|
104
|
+
return chunkName;
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(routeModule)) {
|
|
107
|
+
return routeModule.map((val, index) => genChunkNames(val, `${index}`, name, res));
|
|
108
|
+
}
|
|
109
|
+
return lodash_1.default.mapValues(routeModule, (v, key) => genChunkNames(v, key, name, res));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* This is the higher level overview of route code generation. For each route
|
|
113
|
+
* config node, it returns the node's serialized form, and mutates `registry`,
|
|
114
|
+
* `routesPaths`, and `routesChunkNames` accordingly.
|
|
115
|
+
*/
|
|
116
|
+
function genRouteCode(routeConfig, res) {
|
|
117
|
+
const { path: routePath, component, modules = {}, context, routes: subroutes, priority, exact, ...props } = routeConfig;
|
|
118
|
+
if (typeof routePath !== 'string' || !component) {
|
|
119
|
+
throw new Error(`Invalid route config: path must be a string and component is required.
|
|
120
|
+
${JSON.stringify(routeConfig)}`);
|
|
121
|
+
}
|
|
122
|
+
const routeHash = (0, utils_1.simpleHash)(JSON.stringify(routeConfig), 3);
|
|
123
|
+
res.routesChunkNames[`${routePath}-${routeHash}`] = {
|
|
124
|
+
// Avoid clash with a prop called "component"
|
|
125
|
+
...genChunkNames({ __comp: component }, 'component', component, res),
|
|
126
|
+
...(context &&
|
|
127
|
+
genChunkNames({ __context: context }, 'context', routePath, res)),
|
|
128
|
+
...genChunkNames(modules, 'module', routePath, res),
|
|
129
|
+
};
|
|
130
|
+
return serializeRouteConfig({
|
|
131
|
+
routePath: routePath.replace(/'/g, "\\'"),
|
|
132
|
+
routeHash,
|
|
133
|
+
subroutesCodeStrings: subroutes?.map((r) => genRouteCode(r, res)),
|
|
134
|
+
exact,
|
|
135
|
+
props,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Routes are prepared into three temp files:
|
|
140
|
+
*
|
|
141
|
+
* - `routesConfig`, the route config passed to react-router. This file is kept
|
|
142
|
+
* minimal, because it can't be code-splitted.
|
|
143
|
+
* - `routesChunkNames`, a mapping from route paths (hashed) to code-splitted
|
|
144
|
+
* chunk names.
|
|
145
|
+
* - `registry`, a mapping from chunk names to options for react-loadable.
|
|
146
|
+
*/
|
|
147
|
+
function generateRoutesCode(routeConfigs) {
|
|
148
|
+
const res = {
|
|
149
|
+
// To be written by `genRouteCode`
|
|
150
|
+
routesConfig: '',
|
|
151
|
+
routesChunkNames: {},
|
|
152
|
+
registry: {},
|
|
153
|
+
};
|
|
154
|
+
// `genRouteCode` would mutate `res`
|
|
155
|
+
const routeConfigSerialized = routeConfigs
|
|
156
|
+
.map((r) => genRouteCode(r, res))
|
|
157
|
+
.join(',\n');
|
|
158
|
+
res.routesConfig = `import React from 'react';
|
|
159
|
+
import ComponentCreator from '@docusaurus/ComponentCreator';
|
|
160
|
+
|
|
161
|
+
export default [
|
|
162
|
+
${indent(routeConfigSerialized)},
|
|
163
|
+
{
|
|
164
|
+
path: '*',
|
|
165
|
+
component: ComponentCreator('*'),
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
`;
|
|
169
|
+
return res;
|
|
170
|
+
}
|
|
171
|
+
exports.generateRoutesCode = generateRoutesCode;
|
|
172
|
+
const genRegistry = ({ generatedFilesDir, registry, }) => (0, utils_1.generate)(generatedFilesDir, 'registry.js', `export default {
|
|
173
|
+
${Object.entries(registry)
|
|
174
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
175
|
+
.map(([chunkName, modulePath]) =>
|
|
176
|
+
// modulePath is already escaped by escapePath
|
|
177
|
+
` "${chunkName}": [() => import(/* webpackChunkName: "${chunkName}" */ "${modulePath}"), "${modulePath}", require.resolveWeak("${modulePath}")],`)
|
|
178
|
+
.join('\n')}};
|
|
179
|
+
`);
|
|
180
|
+
const genRoutesChunkNames = ({ generatedFilesDir, routesChunkNames, }) => (0, utils_1.generate)(generatedFilesDir, 'routesChunkNames.json', JSON.stringify(routesChunkNames, null, 2));
|
|
181
|
+
const genRoutes = ({ generatedFilesDir, routesConfig, }) => (0, utils_1.generate)(generatedFilesDir, 'routes.js', routesConfig);
|
|
182
|
+
async function generateRouteFiles({ generatedFilesDir, routes, }) {
|
|
183
|
+
const { registry, routesChunkNames, routesConfig } = generateRoutesCode(routes);
|
|
184
|
+
await Promise.all([
|
|
185
|
+
genRegistry({ generatedFilesDir, registry }),
|
|
186
|
+
genRoutesChunkNames({ generatedFilesDir, routesChunkNames }),
|
|
187
|
+
genRoutes({ generatedFilesDir, routesConfig }),
|
|
188
|
+
]);
|
|
189
|
+
}
|
|
190
|
+
exports.generateRouteFiles = generateRouteFiles;
|
package/lib/server/i18n.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { I18n, DocusaurusConfig, I18nLocaleConfig } from '@docusaurus/types';
|
|
8
|
-
import type {
|
|
8
|
+
import type { LoadContextParams } from './site';
|
|
9
9
|
export declare function getDefaultLocaleConfig(locale: string): I18nLocaleConfig;
|
|
10
|
-
export declare function loadI18n(config: DocusaurusConfig, options: Pick<
|
|
10
|
+
export declare function loadI18n(config: DocusaurusConfig, options: Pick<LoadContextParams, 'locale'>): Promise<I18n>;
|
|
@@ -5,14 +5,25 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { LoadContext, RouteConfig, GlobalData, LoadedPlugin } from '@docusaurus/types';
|
|
8
|
+
import type { PluginIdentifier } from '@docusaurus/types/src/plugin';
|
|
9
|
+
export type LoadPluginsResult = {
|
|
10
|
+
plugins: LoadedPlugin[];
|
|
11
|
+
routes: RouteConfig[];
|
|
12
|
+
globalData: GlobalData;
|
|
13
|
+
};
|
|
8
14
|
/**
|
|
9
15
|
* Initializes the plugins, runs `loadContent`, `translateContent`,
|
|
10
16
|
* `contentLoaded`, and `translateThemeConfig`. Because `contentLoaded` is
|
|
11
17
|
* side-effect-ful (it generates temp files), so is this function. This function
|
|
12
18
|
* would also mutate `context.siteConfig.themeConfig` to translate it.
|
|
13
19
|
*/
|
|
14
|
-
export declare function loadPlugins(context: LoadContext): Promise<
|
|
20
|
+
export declare function loadPlugins(context: LoadContext): Promise<LoadPluginsResult>;
|
|
21
|
+
export declare function getPluginByIdentifier({ plugins, pluginIdentifier, }: {
|
|
22
|
+
pluginIdentifier: PluginIdentifier;
|
|
15
23
|
plugins: LoadedPlugin[];
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
}): LoadedPlugin;
|
|
25
|
+
export declare function reloadPlugin({ pluginIdentifier, plugins, context, }: {
|
|
26
|
+
pluginIdentifier: PluginIdentifier;
|
|
27
|
+
plugins: LoadedPlugin[];
|
|
28
|
+
context: LoadContext;
|
|
29
|
+
}): Promise<LoadPluginsResult>;
|
|
@@ -0,0 +1,176 @@
|
|
|
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.reloadPlugin = exports.getPluginByIdentifier = exports.loadPlugins = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
13
|
+
const utils_1 = require("@docusaurus/utils");
|
|
14
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
15
|
+
const init_1 = require("./init");
|
|
16
|
+
const synthetic_1 = require("./synthetic");
|
|
17
|
+
const translations_1 = require("../translations/translations");
|
|
18
|
+
const routeConfig_1 = require("./routeConfig");
|
|
19
|
+
const utils_2 = require("../../utils");
|
|
20
|
+
async function translatePlugin({ plugin, context, }) {
|
|
21
|
+
const { content } = plugin;
|
|
22
|
+
const rawTranslationFiles = (await plugin.getTranslationFiles?.({ content: plugin.content })) ?? [];
|
|
23
|
+
const translationFiles = await Promise.all(rawTranslationFiles.map((translationFile) => (0, translations_1.localizePluginTranslationFile)({
|
|
24
|
+
localizationDir: context.localizationDir,
|
|
25
|
+
translationFile,
|
|
26
|
+
plugin,
|
|
27
|
+
})));
|
|
28
|
+
const translatedContent = plugin.translateContent?.({ content, translationFiles }) ?? content;
|
|
29
|
+
const translatedThemeConfigSlice = plugin.translateThemeConfig?.({
|
|
30
|
+
themeConfig: context.siteConfig.themeConfig,
|
|
31
|
+
translationFiles,
|
|
32
|
+
});
|
|
33
|
+
// TODO dangerous legacy, need to be refactored!
|
|
34
|
+
// Side-effect to merge theme config translations. A plugin should only
|
|
35
|
+
// translate its own slice of theme config and should make no assumptions
|
|
36
|
+
// about other plugins' keys, so this is safe to run in parallel.
|
|
37
|
+
Object.assign(context.siteConfig.themeConfig, translatedThemeConfigSlice);
|
|
38
|
+
return { ...plugin, content: translatedContent };
|
|
39
|
+
}
|
|
40
|
+
async function executePluginLoadContent({ plugin, context, }) {
|
|
41
|
+
return utils_2.PerfLogger.async(`Plugin - loadContent - ${plugin.name}@${plugin.options.id}`, async () => {
|
|
42
|
+
const content = await plugin.loadContent?.();
|
|
43
|
+
const loadedPlugin = { ...plugin, content };
|
|
44
|
+
return translatePlugin({ plugin: loadedPlugin, context });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function executePluginsLoadContent({ plugins, context, }) {
|
|
48
|
+
return utils_2.PerfLogger.async(`Plugins - loadContent`, () => Promise.all(plugins.map((plugin) => executePluginLoadContent({ plugin, context }))));
|
|
49
|
+
}
|
|
50
|
+
function aggregateAllContent(loadedPlugins) {
|
|
51
|
+
return lodash_1.default.chain(loadedPlugins)
|
|
52
|
+
.groupBy((item) => item.name)
|
|
53
|
+
.mapValues((nameItems) => lodash_1.default.chain(nameItems)
|
|
54
|
+
.groupBy((item) => item.options.id)
|
|
55
|
+
.mapValues((idItems) => idItems[0].content)
|
|
56
|
+
.value())
|
|
57
|
+
.value();
|
|
58
|
+
}
|
|
59
|
+
// TODO refactor and make this side-effect-free
|
|
60
|
+
// If the function was pure, we could more easily compare previous/next values
|
|
61
|
+
// on site reloads, and bail-out of the reload process earlier
|
|
62
|
+
// createData() modules should rather be declarative
|
|
63
|
+
async function executePluginContentLoaded({ plugin, context, allContent, }) {
|
|
64
|
+
return utils_2.PerfLogger.async(`Plugins - contentLoaded - ${plugin.name}@${plugin.options.id}`, async () => {
|
|
65
|
+
if (!plugin.contentLoaded) {
|
|
66
|
+
return { routes: [], globalData: undefined };
|
|
67
|
+
}
|
|
68
|
+
const pluginId = plugin.options.id;
|
|
69
|
+
// Plugins data files are namespaced by pluginName/pluginId
|
|
70
|
+
const dataDir = path_1.default.join(context.generatedFilesDir, plugin.name, pluginId);
|
|
71
|
+
const pluginRouteContextModulePath = path_1.default.join(dataDir, `${(0, utils_1.docuHash)('pluginRouteContextModule')}.json`);
|
|
72
|
+
const pluginRouteContext = {
|
|
73
|
+
name: plugin.name,
|
|
74
|
+
id: pluginId,
|
|
75
|
+
};
|
|
76
|
+
await (0, utils_1.generate)('/', pluginRouteContextModulePath, JSON.stringify(pluginRouteContext, null, 2));
|
|
77
|
+
const routes = [];
|
|
78
|
+
let globalData;
|
|
79
|
+
const actions = {
|
|
80
|
+
addRoute(initialRouteConfig) {
|
|
81
|
+
// Trailing slash behavior is handled generically for all plugins
|
|
82
|
+
const finalRouteConfig = (0, routeConfig_1.applyRouteTrailingSlash)(initialRouteConfig, context.siteConfig);
|
|
83
|
+
routes.push({
|
|
84
|
+
...finalRouteConfig,
|
|
85
|
+
context: {
|
|
86
|
+
...(finalRouteConfig.context && { data: finalRouteConfig.context }),
|
|
87
|
+
plugin: pluginRouteContextModulePath,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
async createData(name, data) {
|
|
92
|
+
const modulePath = path_1.default.join(dataDir, name);
|
|
93
|
+
await (0, utils_1.generate)(dataDir, name, data);
|
|
94
|
+
return modulePath;
|
|
95
|
+
},
|
|
96
|
+
setGlobalData(data) {
|
|
97
|
+
globalData = data;
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
await plugin.contentLoaded({
|
|
101
|
+
content: plugin.content,
|
|
102
|
+
actions,
|
|
103
|
+
allContent,
|
|
104
|
+
});
|
|
105
|
+
return { routes, globalData };
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async function executePluginsContentLoaded({ plugins, context, }) {
|
|
109
|
+
return utils_2.PerfLogger.async(`Plugins - contentLoaded`, async () => {
|
|
110
|
+
const allContent = aggregateAllContent(plugins);
|
|
111
|
+
const routes = [];
|
|
112
|
+
const globalData = {};
|
|
113
|
+
await Promise.all(plugins.map(async (plugin) => {
|
|
114
|
+
var _a;
|
|
115
|
+
const { routes: pluginRoutes, globalData: pluginGlobalData } = await executePluginContentLoaded({
|
|
116
|
+
plugin,
|
|
117
|
+
context,
|
|
118
|
+
allContent,
|
|
119
|
+
});
|
|
120
|
+
routes.push(...pluginRoutes);
|
|
121
|
+
if (pluginGlobalData !== undefined) {
|
|
122
|
+
globalData[_a = plugin.name] ?? (globalData[_a] = {});
|
|
123
|
+
globalData[plugin.name][plugin.options.id] = pluginGlobalData;
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
// Sort the route config.
|
|
127
|
+
// This ensures that route with sub routes are always placed last.
|
|
128
|
+
(0, routeConfig_1.sortRoutes)(routes, context.siteConfig.baseUrl);
|
|
129
|
+
return { routes, globalData };
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Initializes the plugins, runs `loadContent`, `translateContent`,
|
|
134
|
+
* `contentLoaded`, and `translateThemeConfig`. Because `contentLoaded` is
|
|
135
|
+
* side-effect-ful (it generates temp files), so is this function. This function
|
|
136
|
+
* would also mutate `context.siteConfig.themeConfig` to translate it.
|
|
137
|
+
*/
|
|
138
|
+
async function loadPlugins(context) {
|
|
139
|
+
return utils_2.PerfLogger.async('Plugins - loadPlugins', async () => {
|
|
140
|
+
// 1. Plugin Lifecycle - Initialization/Constructor.
|
|
141
|
+
const plugins = await utils_2.PerfLogger.async('Plugins - initPlugins', () => (0, init_1.initPlugins)(context));
|
|
142
|
+
plugins.push((0, synthetic_1.createBootstrapPlugin)(context), (0, synthetic_1.createMDXFallbackPlugin)(context));
|
|
143
|
+
// 2. Plugin Lifecycle - loadContent.
|
|
144
|
+
const loadedPlugins = await executePluginsLoadContent({ plugins, context });
|
|
145
|
+
// 3. Plugin Lifecycle - contentLoaded.
|
|
146
|
+
const { routes, globalData } = await executePluginsContentLoaded({
|
|
147
|
+
plugins: loadedPlugins,
|
|
148
|
+
context,
|
|
149
|
+
});
|
|
150
|
+
return { plugins: loadedPlugins, routes, globalData };
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
exports.loadPlugins = loadPlugins;
|
|
154
|
+
function getPluginByIdentifier({ plugins, pluginIdentifier, }) {
|
|
155
|
+
const plugin = plugins.find((p) => p.name === pluginIdentifier.name && p.options.id === pluginIdentifier.id);
|
|
156
|
+
if (!plugin) {
|
|
157
|
+
throw new Error(logger_1.default.interpolate `Plugin not found for identifier ${pluginIdentifier.name}@${pluginIdentifier.id}`);
|
|
158
|
+
}
|
|
159
|
+
return plugin;
|
|
160
|
+
}
|
|
161
|
+
exports.getPluginByIdentifier = getPluginByIdentifier;
|
|
162
|
+
async function reloadPlugin({ pluginIdentifier, plugins, context, }) {
|
|
163
|
+
return utils_2.PerfLogger.async('Plugins - reloadPlugin', async () => {
|
|
164
|
+
const plugin = getPluginByIdentifier({ plugins, pluginIdentifier });
|
|
165
|
+
const reloadedPlugin = await executePluginLoadContent({ plugin, context });
|
|
166
|
+
const newPlugins = plugins.with(plugins.indexOf(plugin), reloadedPlugin);
|
|
167
|
+
// Unfortunately, due to the "AllContent" data we have to re-execute this
|
|
168
|
+
// for all plugins, not just the one to reload...
|
|
169
|
+
const { routes, globalData } = await executePluginsContentLoaded({
|
|
170
|
+
plugins: newPlugins,
|
|
171
|
+
context,
|
|
172
|
+
});
|
|
173
|
+
return { plugins: newPlugins, routes, globalData };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
exports.reloadPlugin = reloadPlugin;
|
|
@@ -8,4 +8,4 @@ import { type ApplyTrailingSlashParams } from '@docusaurus/utils-common';
|
|
|
8
8
|
import type { RouteConfig } from '@docusaurus/types';
|
|
9
9
|
/** Recursively applies trailing slash config to all nested routes. */
|
|
10
10
|
export declare function applyRouteTrailingSlash(route: RouteConfig, params: ApplyTrailingSlashParams): RouteConfig;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function sortRoutes(routeConfigs: RouteConfig[], baseUrl?: string): void;
|
|
@@ -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.
|
|
9
|
+
exports.sortRoutes = exports.applyRouteTrailingSlash = void 0;
|
|
10
10
|
const utils_common_1 = require("@docusaurus/utils-common");
|
|
11
11
|
/** Recursively applies trailing slash config to all nested routes. */
|
|
12
12
|
function applyRouteTrailingSlash(route, params) {
|
|
@@ -19,7 +19,7 @@ function applyRouteTrailingSlash(route, params) {
|
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
exports.applyRouteTrailingSlash = applyRouteTrailingSlash;
|
|
22
|
-
function
|
|
22
|
+
function sortRoutes(routeConfigs, baseUrl = '/') {
|
|
23
23
|
// Sort the route config. This ensures that route with nested
|
|
24
24
|
// routes is always placed last.
|
|
25
25
|
routeConfigs.sort((a, b) => {
|
|
@@ -49,8 +49,8 @@ function sortConfig(routeConfigs, baseUrl = '/') {
|
|
|
49
49
|
});
|
|
50
50
|
routeConfigs.forEach((routeConfig) => {
|
|
51
51
|
if (routeConfig.routes) {
|
|
52
|
-
|
|
52
|
+
sortRoutes(routeConfig.routes, baseUrl);
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
-
exports.
|
|
56
|
+
exports.sortRoutes = sortRoutes;
|
package/lib/server/routes.d.ts
CHANGED
|
@@ -4,48 +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 { RouteConfig,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/** @see {ChunkNames} */
|
|
12
|
-
routesChunkNames: RouteChunkNames;
|
|
13
|
-
/**
|
|
14
|
-
* A map from chunk name to module paths. Module paths would have backslash
|
|
15
|
-
* escaped already, so they can be directly printed.
|
|
16
|
-
*/
|
|
17
|
-
registry: {
|
|
18
|
-
[chunkName: string]: string;
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Collect all page paths for injecting it later in the plugin lifecycle.
|
|
22
|
-
* This is useful for plugins like sitemaps, redirects etc... Only collects
|
|
23
|
-
* "actual" pages, i.e. those without subroutes, because if a route has
|
|
24
|
-
* subroutes, it is probably a wrapper.
|
|
25
|
-
*/
|
|
26
|
-
routesPaths: string[];
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Generates a unique chunk name that can be used in the chunk registry.
|
|
30
|
-
*
|
|
31
|
-
* @param modulePath A path to generate chunk name from. The actual value has no
|
|
32
|
-
* semantic significance.
|
|
33
|
-
* @param prefix A prefix to append to the chunk name, to avoid name clash.
|
|
34
|
-
* @param preferredName Chunk names default to `modulePath`, and this can supply
|
|
35
|
-
* a more human-readable name.
|
|
36
|
-
* @param shortId When `true`, the chunk name would only be a hash without any
|
|
37
|
-
* other characters. Useful for bundle size. Defaults to `true` in production.
|
|
38
|
-
*/
|
|
39
|
-
export declare function genChunkName(modulePath: string, prefix?: string, preferredName?: string, shortId?: boolean): string;
|
|
40
|
-
export declare function handleDuplicateRoutes(pluginsRouteConfigs: RouteConfig[], onDuplicateRoutes: ReportingSeverity): void;
|
|
41
|
-
/**
|
|
42
|
-
* Routes are prepared into three temp files:
|
|
43
|
-
*
|
|
44
|
-
* - `routesConfig`, the route config passed to react-router. This file is kept
|
|
45
|
-
* minimal, because it can't be code-splitted.
|
|
46
|
-
* - `routesChunkNames`, a mapping from route paths (hashed) to code-splitted
|
|
47
|
-
* chunk names.
|
|
48
|
-
* - `registry`, a mapping from chunk names to options for react-loadable.
|
|
49
|
-
*/
|
|
50
|
-
export declare function loadRoutes(routeConfigs: RouteConfig[], baseUrl: string, onDuplicateRoutes: ReportingSeverity): LoadedRoutes;
|
|
51
|
-
export {};
|
|
7
|
+
import type { RouteConfig, ReportingSeverity } from '@docusaurus/types';
|
|
8
|
+
export declare function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[];
|
|
9
|
+
export declare function handleDuplicateRoutes(routes: RouteConfig[], onDuplicateRoutes: ReportingSeverity): void;
|
|
10
|
+
export declare function getRoutesPaths(routeConfigs: RouteConfig[], baseUrl: string): string[];
|