diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts
index 7bc1f119a2..7d24b70a47 100644
--- a/packages/docusaurus-types/src/index.d.ts
+++ b/packages/docusaurus-types/src/index.d.ts
@@ -227,7 +227,6 @@ export type LoadContext = {
*/
baseUrl: string;
i18n: I18n;
- ssrTemplate: string;
codeTranslations: CodeTranslations;
};
diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx
index 01d74bb1cd..206dfb27bd 100644
--- a/packages/docusaurus/src/client/App.tsx
+++ b/packages/docusaurus/src/client/App.tsx
@@ -12,7 +12,7 @@ import renderRoutes from './exports/renderRoutes';
import {BrowserContextProvider} from './browserContext';
import {DocusaurusContextProvider} from './docusaurusContext';
import PendingNavigation from './PendingNavigation';
-import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner';
+import BaseUrlIssueBanner from './BaseUrlIssueBanner';
import SiteMetadataDefaults from './SiteMetadataDefaults';
import Root from '@theme/Root';
import SiteMetadata from '@theme/SiteMetadata';
diff --git a/packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx b/packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx
similarity index 87%
rename from packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx
rename to packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx
index 59f693931a..3ddfaa5ed9 100644
--- a/packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx
+++ b/packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx
@@ -74,11 +74,11 @@ function insertBanner() {
declare global {
interface Window {
- __DOCUSAURUS_INSERT_BASEURL_BANNER: boolean;
+ [InsertBannerWindowAttribute]: boolean;
}
}
-function BaseUrlIssueBannerEnabled() {
+function BaseUrlIssueBanner() {
const {
siteConfig: {baseUrl},
} = useDocusaurusContext();
@@ -92,6 +92,8 @@ function BaseUrlIssueBannerEnabled() {
return (
<>
{!ExecutionEnvironment.canUseDOM && (
+ // Safe to use `ExecutionEnvironment`, because `Head` is purely
+ // side-effect and doesn't affect hydration
@@ -103,22 +105,22 @@ function BaseUrlIssueBannerEnabled() {
/**
* We want to help the users with a bad baseUrl configuration (very common
- * error) Help message is inlined, and hidden if JS or CSS is able to load
+ * error). Help message is inlined, and hidden if JS or CSS is able to load.
+ *
+ * This component only inserts the base URL banner for the homepage, to avoid
+ * polluting every statically rendered page.
+ *
* Note: it might create false positives (ie network failures): not a big deal
- * Note: we only inline this for the homepage to avoid polluting all the site's
- * pages
+ *
* @see https://github.com/facebook/docusaurus/pull/3621
*/
-export default function BaseUrlIssueBanner(): JSX.Element | null {
+export default function MaybeBaseUrlIssueBanner(): JSX.Element | null {
const {
siteConfig: {baseUrl, baseUrlIssueBanner},
} = useDocusaurusContext();
const {pathname} = useLocation();
-
- // returns true for the homepage during SRR
+ // returns true for the homepage during SSR
const isHomePage = pathname === baseUrl;
-
const enabled = baseUrlIssueBanner && isHomePage;
-
- return enabled ? : null;
+ return enabled ? : null;
}
diff --git a/packages/docusaurus/src/client/baseUrlIssueBanner/styles.module.css b/packages/docusaurus/src/client/BaseUrlIssueBanner/styles.module.css
similarity index 100%
rename from packages/docusaurus/src/client/baseUrlIssueBanner/styles.module.css
rename to packages/docusaurus/src/client/BaseUrlIssueBanner/styles.module.css
diff --git a/packages/docusaurus/src/client/exports/BrowserOnly.tsx b/packages/docusaurus/src/client/exports/BrowserOnly.tsx
index 025049b782..16e64ef06d 100644
--- a/packages/docusaurus/src/client/exports/BrowserOnly.tsx
+++ b/packages/docusaurus/src/client/exports/BrowserOnly.tsx
@@ -7,16 +7,14 @@
import React, {isValidElement} from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser';
+import type {Props} from '@docusaurus/BrowserOnly';
// Similar comp to the one described here:
// https://www.joshwcomeau.com/react/the-perils-of-rehydration/#abstractions
export default function BrowserOnly({
children,
fallback,
-}: {
- children: () => JSX.Element;
- fallback?: JSX.Element;
-}): JSX.Element | null {
+}: Props): JSX.Element | null {
const isBrowser = useIsBrowser();
if (isBrowser) {
@@ -27,7 +25,7 @@ export default function BrowserOnly({
throw new Error(`Docusaurus error: The children of must be a "render function", e.g. {() => {window.location.href}}.
Current type: ${isValidElement(children) ? 'React element' : typeof children}`);
}
- return <>{children()}>;
+ return <>{children?.()}>;
}
return fallback ?? null;
diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx
index 076c7b1abc..99f0b76e1f 100644
--- a/packages/docusaurus/src/client/exports/Interpolate.tsx
+++ b/packages/docusaurus/src/client/exports/Interpolate.tsx
@@ -18,7 +18,6 @@ We don't ship a markdown parser nor a feature-complete i18n library on purpose.
More details here: https://github.com/facebook/docusaurus/pull/4295
*/
-const ValueRegexp = /\{\w+\}/g;
const ValueFoundMarker = '{}'; // does not care much
// If all the values are plain strings, then interpolate returns a simple string
@@ -39,51 +38,44 @@ export function interpolate(
): ReactNode {
const elements: (Value | string)[] = [];
- const processedText = text.replace(ValueRegexp, (match: string) => {
- // remove {{ and }} around the placeholder
- const key = match.substring(
- 1,
- match.length - 1,
- ) as ExtractInterpolatePlaceholders;
+ const processedText = text.replace(
+ // eslint-disable-next-line prefer-named-capture-group
+ /\{(\w+)\}/g,
+ (match, key: ExtractInterpolatePlaceholders) => {
+ const value = values?.[key];
- const value = values?.[key];
-
- if (typeof value !== 'undefined') {
- const element = isValidElement(value)
- ? value
- : // For non-React elements: basic primitive->string conversion
- String(value);
- elements.push(element);
- return ValueFoundMarker;
- }
- return match; // no match? add warning?
- });
+ if (typeof value !== 'undefined') {
+ const element = isValidElement(value)
+ ? value
+ : // For non-React elements: basic primitive->string conversion
+ String(value);
+ elements.push(element);
+ return ValueFoundMarker;
+ }
+ return match; // no match? add warning?
+ },
+ );
// No interpolation to be done: just return the text
if (elements.length === 0) {
return text;
}
// Basic string interpolation: returns interpolated string
- if (elements.every((el) => typeof el === 'string')) {
+ if (elements.every((el): el is string => typeof el === 'string')) {
return processedText
.split(ValueFoundMarker)
.reduce(
- (str, value, index) =>
- str.concat(value).concat((elements[index] as string) ?? ''),
+ (str, value, index) => str.concat(value).concat(elements[index] ?? ''),
'',
);
}
// JSX interpolation: returns ReactNode
- return processedText.split(ValueFoundMarker).reduce(
- (array, value, index) => [
- ...array,
-
- {value}
- {elements[index]}
- ,
- ],
- [],
- );
+ return processedText.split(ValueFoundMarker).map((value, index) => (
+
+ {value}
+ {elements[index]}
+
+ ));
}
export default function Interpolate({
diff --git a/packages/docusaurus/src/client/exports/Link.tsx b/packages/docusaurus/src/client/exports/Link.tsx
index 6850f23761..53da88a791 100644
--- a/packages/docusaurus/src/client/exports/Link.tsx
+++ b/packages/docusaurus/src/client/exports/Link.tsx
@@ -103,35 +103,29 @@ function Link(
const IOSupported = ExecutionEnvironment.canUseIntersectionObserver;
const ioRef = useRef();
- const handleIntersection = (el: HTMLAnchorElement, cb: () => void) => {
- ioRef.current = new window.IntersectionObserver((entries) => {
- entries.forEach((entry) => {
- if (el === entry.target) {
- // If element is in viewport, stop observing and run callback.
- // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
- if (entry.isIntersecting || entry.intersectionRatio > 0) {
- ioRef.current!.unobserve(el);
- ioRef.current!.disconnect();
- cb();
- }
- }
- });
- });
- // Add element to the observer.
- ioRef.current!.observe(el);
- };
+ const handleRef = (el: HTMLAnchorElement | null) => {
+ innerRef.current = el;
- const handleRef = (ref: HTMLAnchorElement | null) => {
- innerRef.current = ref;
-
- if (IOSupported && ref && isInternal) {
+ if (IOSupported && el && isInternal) {
// If IO supported and element reference found, set up Observer.
- handleIntersection(ref, () => {
- if (targetLink != null) {
- window.docusaurus.prefetch(targetLink);
- }
+ ioRef.current = new window.IntersectionObserver((entries) => {
+ entries.forEach((entry) => {
+ if (el === entry.target) {
+ // If element is in viewport, stop observing and run callback.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
+ if (entry.isIntersecting || entry.intersectionRatio > 0) {
+ ioRef.current!.unobserve(el);
+ ioRef.current!.disconnect();
+ if (targetLink != null) {
+ window.docusaurus.prefetch(targetLink);
+ }
+ }
+ }
+ });
});
+ // Add element to the observer.
+ ioRef.current.observe(el);
}
};
@@ -161,8 +155,8 @@ function Link(
const isAnchorLink = targetLink?.startsWith('#') ?? false;
const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
- if (targetLink && isInternal && !isAnchorLink && !noBrokenLinkCheck) {
- linksCollector.collectLink(targetLink);
+ if (!isRegularHtmlLink && !noBrokenLinkCheck) {
+ linksCollector.collectLink(targetLink!);
}
return isRegularHtmlLink ? (
diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts
index 7faa5c74c9..0f55edac83 100644
--- a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts
+++ b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts
@@ -91,7 +91,7 @@ async function createTestSite() {
const siteThemePathPosix = posixPath(siteThemePath);
expect(tree(siteThemePathPosix)).toMatchSnapshot('theme dir tree');
- const files = Globby.sync(siteThemePathPosix)
+ const files = (await Globby(siteThemePathPosix))
.map((file) => path.posix.relative(siteThemePathPosix, file))
.sort();
diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap
index b895467529..80de4e006f 100644
--- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap
+++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap
@@ -12,22 +12,10 @@ This could lead to non-deterministic routing behavior."
exports[`loadRoutes loads flat route config 1`] = `
{
"registry": {
- "__comp---theme-blog-list-pagea-6-a-7ba": {
- "loader": "() => import(/* webpackChunkName: '__comp---theme-blog-list-pagea-6-a-7ba' */ '@theme/BlogListPage')",
- "modulePath": "@theme/BlogListPage",
- },
- "content---blog-0-b-4-09e": {
- "loader": "() => import(/* webpackChunkName: 'content---blog-0-b-4-09e' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true')",
- "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true",
- },
- "content---blog-7-b-8-fd9": {
- "loader": "() => import(/* webpackChunkName: 'content---blog-7-b-8-fd9' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md')",
- "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md",
- },
- "metadata---blog-0-b-6-74c": {
- "loader": "() => import(/* webpackChunkName: 'metadata---blog-0-b-6-74c' */ 'blog-2018-12-14-happy-first-birthday-slash-d2c.json')",
- "modulePath": "blog-2018-12-14-happy-first-birthday-slash-d2c.json",
- },
+ "__comp---theme-blog-list-pagea-6-a-7ba": "@theme/BlogListPage",
+ "content---blog-0-b-4-09e": "blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true",
+ "content---blog-7-b-8-fd9": "blog/2018-12-14-Happy-First-Birthday-Slash.md",
+ "metadata---blog-0-b-6-74c": "blog-2018-12-14-happy-first-birthday-slash-d2c.json",
},
"routesChunkNames": {
"/blog-599": {
@@ -71,34 +59,13 @@ export default [
exports[`loadRoutes loads nested route config 1`] = `
{
"registry": {
- "__comp---theme-doc-item-178-a40": {
- "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-item-178-a40' */ '@theme/DocItem')",
- "modulePath": "@theme/DocItem",
- },
- "__comp---theme-doc-page-1-be-9be": {
- "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-page-1-be-9be' */ '@theme/DocPage')",
- "modulePath": "@theme/DocPage",
- },
- "content---docs-foo-baz-8-ce-61e": {
- "loader": "() => import(/* webpackChunkName: 'content---docs-foo-baz-8-ce-61e' */ 'docs/foo/baz.md')",
- "modulePath": "docs/foo/baz.md",
- },
- "content---docs-helloaff-811": {
- "loader": "() => import(/* webpackChunkName: 'content---docs-helloaff-811' */ 'docs/hello.md')",
- "modulePath": "docs/hello.md",
- },
- "docsMetadata---docs-routef-34-881": {
- "loader": "() => import(/* webpackChunkName: 'docsMetadata---docs-routef-34-881' */ 'docs-b5f.json')",
- "modulePath": "docs-b5f.json",
- },
- "metadata---docs-foo-baz-2-cf-fa7": {
- "loader": "() => import(/* webpackChunkName: 'metadata---docs-foo-baz-2-cf-fa7' */ 'docs-foo-baz-dd9.json')",
- "modulePath": "docs-foo-baz-dd9.json",
- },
- "metadata---docs-hello-956-741": {
- "loader": "() => import(/* webpackChunkName: 'metadata---docs-hello-956-741' */ 'docs-hello-da2.json')",
- "modulePath": "docs-hello-da2.json",
- },
+ "__comp---theme-doc-item-178-a40": "@theme/DocItem",
+ "__comp---theme-doc-page-1-be-9be": "@theme/DocPage",
+ "content---docs-foo-baz-8-ce-61e": "docs/foo/baz.md",
+ "content---docs-helloaff-811": "docs/hello.md",
+ "docsMetadata---docs-routef-34-881": "docs-b5f.json",
+ "metadata---docs-foo-baz-2-cf-fa7": "docs-foo-baz-dd9.json",
+ "metadata---docs-hello-956-741": "docs-hello-da2.json",
},
"routesChunkNames": {
"/docs/hello-44b": {
@@ -159,10 +126,7 @@ export default [
exports[`loadRoutes loads route config with empty (but valid) path string 1`] = `
{
"registry": {
- "__comp---hello-world-jse-0-f-b6c": {
- "loader": "() => import(/* webpackChunkName: '__comp---hello-world-jse-0-f-b6c' */ 'hello/world.js')",
- "modulePath": "hello/world.js",
- },
+ "__comp---hello-world-jse-0-f-b6c": "hello/world.js",
},
"routesChunkNames": {
"-b2a": {
diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts
index faf37563fd..1e8062a696 100644
--- a/packages/docusaurus/src/server/__tests__/routes.test.ts
+++ b/packages/docusaurus/src/server/__tests__/routes.test.ts
@@ -101,7 +101,7 @@ describe('handleDuplicateRoutes', () => {
});
describe('loadRoutes', () => {
- it('loads nested route config', async () => {
+ it('loads nested route config', () => {
const nestedRouteConfig: RouteConfig = {
component: '@theme/DocPage',
path: '/docs:route',
@@ -135,12 +135,10 @@ describe('loadRoutes', () => {
},
],
};
- await expect(
- loadRoutes([nestedRouteConfig], '/', 'ignore'),
- ).resolves.toMatchSnapshot();
+ expect(loadRoutes([nestedRouteConfig], '/', 'ignore')).toMatchSnapshot();
});
- it('loads flat route config', async () => {
+ it('loads flat route config', () => {
const flatRouteConfig: RouteConfig = {
path: '/blog',
component: '@theme/BlogListPage',
@@ -169,17 +167,15 @@ describe('loadRoutes', () => {
],
},
};
- await expect(
- loadRoutes([flatRouteConfig], '/', 'ignore'),
- ).resolves.toMatchSnapshot();
+ expect(loadRoutes([flatRouteConfig], '/', 'ignore')).toMatchSnapshot();
});
- it('rejects invalid route config', async () => {
+ it('rejects invalid route config', () => {
const routeConfigWithoutPath = {
component: 'hello/world.js',
} as RouteConfig;
- await expect(loadRoutes([routeConfigWithoutPath], '/', 'ignore')).rejects
+ expect(() => loadRoutes([routeConfigWithoutPath], '/', 'ignore'))
.toThrowErrorMatchingInlineSnapshot(`
"Invalid route config: path must be a string and component is required.
{\\"component\\":\\"hello/world.js\\"}"
@@ -189,21 +185,19 @@ describe('loadRoutes', () => {
path: '/hello/world',
} as RouteConfig;
- await expect(loadRoutes([routeConfigWithoutComponent], '/', 'ignore'))
- .rejects.toThrowErrorMatchingInlineSnapshot(`
+ expect(() => loadRoutes([routeConfigWithoutComponent], '/', 'ignore'))
+ .toThrowErrorMatchingInlineSnapshot(`
"Invalid route config: path must be a string and component is required.
{\\"path\\":\\"/hello/world\\"}"
`);
});
- it('loads route config with empty (but valid) path string', async () => {
+ it('loads route config with empty (but valid) path string', () => {
const routeConfig = {
path: '',
component: 'hello/world.js',
} as RouteConfig;
- await expect(
- loadRoutes([routeConfig], '/', 'ignore'),
- ).resolves.toMatchSnapshot();
+ expect(loadRoutes([routeConfig], '/', 'ignore')).toMatchSnapshot();
});
});
diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts
index c213ca19ef..c8806fa842 100644
--- a/packages/docusaurus/src/server/brokenLinks.ts
+++ b/packages/docusaurus/src/server/brokenLinks.ts
@@ -53,7 +53,7 @@ function getPageBrokenLinks({
// component, but we load route components with string paths.
// We don't actually access component here, so it's fine.
.map((l) => matchRoutes(routes, l))
- .reduce((prev, cur) => prev.concat(cur));
+ .flat();
return matchedRoutes.length === 0;
}
diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts
index e171b21f78..b2d5dfe570 100644
--- a/packages/docusaurus/src/server/i18n.ts
+++ b/packages/docusaurus/src/server/i18n.ts
@@ -51,9 +51,8 @@ Note: Docusaurus only support running one locale at a time.`;
};
}
- const localeConfigs = locales.reduce(
- (acc, locale) => ({...acc, [locale]: getLocaleConfig(locale)}),
- {},
+ const localeConfigs = Object.fromEntries(
+ locales.map((locale) => [locale, getLocaleConfig(locale)]),
);
return {
diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts
index fecb98e311..e971d13263 100644
--- a/packages/docusaurus/src/server/index.ts
+++ b/packages/docusaurus/src/server/index.ts
@@ -16,7 +16,6 @@ import {
import _ from 'lodash';
import path from 'path';
import {loadSiteConfig} from './config';
-import ssrDefaultTemplate from '../webpack/templates/ssr.html.template';
import {loadClientModules} from './clientModules';
import {loadPlugins} from './plugins';
import {loadRoutes} from './routes';
@@ -101,7 +100,6 @@ export async function loadContext(
outDir,
baseUrl,
i18n,
- ssrTemplate: siteConfig.ssrTemplate ?? ssrDefaultTemplate,
codeTranslations,
};
}
@@ -122,18 +120,16 @@ export async function load(options: LoadContextOptions): Promise {
outDir,
baseUrl,
i18n,
- ssrTemplate,
codeTranslations: siteCodeTranslations,
} = context;
const {plugins, pluginsRouteConfigs, globalData} = await loadPlugins(context);
const clientModules = loadClientModules(plugins);
const {headTags, preBodyTags, postBodyTags} = loadHtmlTags(plugins);
- const {registry, routesChunkNames, routesConfig, routesPaths} =
- await loadRoutes(
- pluginsRouteConfigs,
- baseUrl,
- siteConfig.onDuplicateRoutes,
- );
+ const {registry, routesChunkNames, routesConfig, routesPaths} = loadRoutes(
+ pluginsRouteConfigs,
+ baseUrl,
+ siteConfig.onDuplicateRoutes,
+ );
const codeTranslations = {
...(await getPluginsDefaultCodeTranslationMessages(plugins)),
...siteCodeTranslations,
@@ -153,8 +149,6 @@ next build. You can clear all build artifacts (including this folder) with the
`,
);
- // Site config must be generated after plugins
- // We want the generated config to have been normalized by the plugins!
const genSiteConfig = generate(
generatedFilesDir,
DEFAULT_CONFIG_FILE_NAME,
@@ -174,7 +168,7 @@ export default ${JSON.stringify(siteConfig, null, 2)};
${clientModules
// import() is async so we use require() because client modules can have
// CSS and the order matters for loading CSS.
- .map((module) => ` require('${escapePath(module)}'),`)
+ .map((clientModule) => ` require('${escapePath(clientModule)}'),`)
.join('\n')}
];
`,
@@ -187,10 +181,8 @@ ${clientModules
${Object.entries(registry)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(
- ([key, chunk]) =>
- ` '${key}': [${chunk.loader}, '${escapePath(
- chunk.modulePath,
- )}', require.resolveWeak('${escapePath(chunk.modulePath)}')],`,
+ ([chunkName, modulePath]) =>
+ ` '${chunkName}': [() => import(/* webpackChunkName: '${chunkName}' */ '${modulePath}'), '${modulePath}', require.resolveWeak('${modulePath}')],`,
)
.join('\n')}};
`,
@@ -256,7 +248,6 @@ ${Object.entries(registry)
headTags,
preBodyTags,
postBodyTags,
- ssrTemplate,
codeTranslations,
};
}
diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts
index 22fb44bbd7..6350e21660 100644
--- a/packages/docusaurus/src/server/routes.ts
+++ b/packages/docusaurus/src/server/routes.ts
@@ -29,9 +29,12 @@ type LoadedRoutes = {
routesConfig: string;
/** @see {ChunkNames} */
routesChunkNames: RouteChunkNames;
- /** A map from chunk name to module loaders. */
+ /**
+ * A map from chunk name to module paths. Module paths would have backslash
+ * escaped already, so they can be directly printed.
+ */
registry: {
- [chunkName: string]: {loader: string; modulePath: string};
+ [chunkName: string]: string;
};
/**
* Collect all page paths for injecting it later in the plugin lifecycle.
@@ -195,12 +198,7 @@ function genChunkNames(
// This is a leaf node, no need to recurse
const modulePath = getModulePath(routeModule);
const chunkName = genChunkName(modulePath, prefix, name);
- res.registry[chunkName] = {
- loader: `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath(
- modulePath,
- )}')`,
- modulePath,
- };
+ res.registry[chunkName] = escapePath(modulePath);
return chunkName;
}
if (Array.isArray(routeModule)) {
@@ -294,11 +292,11 @@ ${JSON.stringify(routeConfig)}`,
* chunk names.
* - `registry`, a mapping from chunk names to options for react-loadable.
*/
-export async function loadRoutes(
+export function loadRoutes(
routeConfigs: RouteConfig[],
baseUrl: string,
onDuplicateRoutes: ReportingSeverity,
-): Promise {
+): LoadedRoutes {
handleDuplicateRoutes(routeConfigs, onDuplicateRoutes);
const res: LoadedRoutes = {
// To be written by `genRouteCode`
@@ -308,11 +306,16 @@ export async function loadRoutes(
routesPaths: [normalizeUrl([baseUrl, '404.html'])],
};
+ // `genRouteCode` would mutate `res`
+ const routeConfigSerialized = routeConfigs
+ .map((r) => genRouteCode(r, res))
+ .join(',\n');
+
res.routesConfig = `import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator';
export default [
-${indent(`${routeConfigs.map((r) => genRouteCode(r, res)).join(',\n')},`)}
+${indent(routeConfigSerialized)},
{
path: '*',
component: ComponentCreator('*'),
diff --git a/packages/docusaurus/src/server/siteMetadata.ts b/packages/docusaurus/src/server/siteMetadata.ts
index 199dbc034a..ec855f94d5 100644
--- a/packages/docusaurus/src/server/siteMetadata.ts
+++ b/packages/docusaurus/src/server/siteMetadata.ts
@@ -81,8 +81,7 @@ function checkDocusaurusPackagesVersion(siteMetadata: SiteMetadata) {
versionInfo.version &&
versionInfo.version !== docusaurusVersion
) {
- // should we throw instead?
- // It still could work with different versions
+ // Should we throw instead? It still could work with different versions
logger.error`Invalid name=${plugin} version number=${versionInfo.version}.
All official @docusaurus/* packages should have the exact same version as @docusaurus/core (number=${docusaurusVersion}).
Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`;
diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts
index 3adc362a41..93cb258c34 100644
--- a/packages/docusaurus/src/webpack/server.ts
+++ b/packages/docusaurus/src/webpack/server.ts
@@ -14,6 +14,7 @@ import {createBaseConfig} from './base';
import WaitPlugin from './plugins/WaitPlugin';
import LogPlugin from './plugins/LogPlugin';
import {NODE_MAJOR_VERSION, NODE_MINOR_VERSION} from '@docusaurus/utils';
+import ssrDefaultTemplate from './templates/ssr.html.template';
// Forked for Docusaurus: https://github.com/slorber/static-site-generator-webpack-plugin
import StaticSiteGeneratorPlugin from '@slorber/static-site-generator-webpack-plugin';
@@ -32,8 +33,7 @@ export default async function createServerConfig({
headTags,
preBodyTags,
postBodyTags,
- ssrTemplate,
- siteConfig: {noIndex, trailingSlash},
+ siteConfig: {noIndex, trailingSlash, ssrTemplate},
} = props;
const config = await createBaseConfig(props, true);
@@ -73,7 +73,7 @@ export default async function createServerConfig({
preBodyTags,
postBodyTags,
onLinksCollected,
- ssrTemplate,
+ ssrTemplate: ssrTemplate ?? ssrDefaultTemplate,
noIndex,
},
paths: ssgPaths,