@docusaurus/core 0.0.0-5945 → 0.0.0-5953
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/client/clientEntry.js +7 -3
- package/lib/client/exports/Link.js +12 -2
- package/lib/client/exports/useBaseUrl.d.ts +8 -0
- package/lib/client/exports/useBaseUrl.js +11 -3
- package/lib/commands/build.js +32 -15
- package/lib/commands/start/utils.d.ts +3 -2
- package/lib/commands/start/utils.js +7 -2
- package/lib/commands/start/webpack.js +1 -1
- package/lib/server/configValidation.js +4 -0
- package/lib/server/htmlTags.d.ts +5 -2
- package/lib/server/htmlTags.js +15 -6
- package/lib/server/site.js +4 -1
- package/lib/ssg.d.ts +4 -0
- package/lib/ssg.js +9 -1
- package/lib/templates/templates.d.ts +3 -0
- package/lib/templates/templates.js +26 -1
- package/lib/webpack/base.js +1 -1
- package/lib/webpack/client.js +10 -18
- package/lib/webpack/plugins/ForceTerminatePlugin.d.ts +10 -0
- package/lib/webpack/plugins/ForceTerminatePlugin.js +25 -0
- package/lib/webpack/plugins/StaticDirectoriesCopyPlugin.d.ts +11 -0
- package/lib/webpack/plugins/StaticDirectoriesCopyPlugin.js +39 -0
- package/lib/webpack/server.js +0 -28
- package/package.json +10 -10
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React, { startTransition } from 'react';
|
|
8
8
|
import ReactDOM from 'react-dom/client';
|
|
9
|
-
import { BrowserRouter } from 'react-router-dom';
|
|
10
9
|
import { HelmetProvider } from 'react-helmet-async';
|
|
10
|
+
import { BrowserRouter, HashRouter } from 'react-router-dom';
|
|
11
|
+
import siteConfig from '@generated/docusaurus.config';
|
|
11
12
|
import ExecutionEnvironment from './exports/ExecutionEnvironment';
|
|
12
13
|
import App from './App';
|
|
13
14
|
import preload from './preload';
|
|
14
15
|
import docusaurus from './docusaurus';
|
|
16
|
+
function Router({ children }) {
|
|
17
|
+
return siteConfig.future.experimental_router === 'hash' ? (<HashRouter>{children}</HashRouter>) : (<BrowserRouter>{children}</BrowserRouter>);
|
|
18
|
+
}
|
|
15
19
|
const hydrate = Boolean(process.env.HYDRATE_CLIENT_ENTRY);
|
|
16
20
|
// Client-side render (e.g: running in browser) to become single-page
|
|
17
21
|
// application (SPA).
|
|
@@ -19,9 +23,9 @@ if (ExecutionEnvironment.canUseDOM) {
|
|
|
19
23
|
window.docusaurus = docusaurus;
|
|
20
24
|
const container = document.getElementById('__docusaurus');
|
|
21
25
|
const app = (<HelmetProvider>
|
|
22
|
-
<
|
|
26
|
+
<Router>
|
|
23
27
|
<App />
|
|
24
|
-
</
|
|
28
|
+
</Router>
|
|
25
29
|
</HelmetProvider>);
|
|
26
30
|
const onRecoverableError = (error, errorInfo) => {
|
|
27
31
|
console.error('Docusaurus React Root onRecoverableError:', error, errorInfo);
|
|
@@ -19,7 +19,9 @@ import { useBaseUrlUtils } from './useBaseUrl';
|
|
|
19
19
|
// like "introduction" to "/baseUrl/introduction" => bad behavior to fix
|
|
20
20
|
const shouldAddBaseUrlAutomatically = (to) => to.startsWith('/');
|
|
21
21
|
function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLinkCheck': noBrokenLinkCheck, autoAddBaseUrl = true, ...props }, forwardedRef) {
|
|
22
|
-
const { siteConfig
|
|
22
|
+
const { siteConfig } = useDocusaurusContext();
|
|
23
|
+
const { trailingSlash, baseUrl } = siteConfig;
|
|
24
|
+
const router = siteConfig.future.experimental_router;
|
|
23
25
|
const { withBaseUrl } = useBaseUrlUtils();
|
|
24
26
|
const brokenLinks = useBrokenLinks();
|
|
25
27
|
const innerRef = useRef(null);
|
|
@@ -47,6 +49,14 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
47
49
|
let targetLink = typeof targetLinkWithoutPathnameProtocol !== 'undefined'
|
|
48
50
|
? maybeAddBaseUrl(targetLinkWithoutPathnameProtocol)
|
|
49
51
|
: undefined;
|
|
52
|
+
// TODO find a way to solve this problem properly
|
|
53
|
+
// Fix edge case when useBaseUrl is used on a link
|
|
54
|
+
// "./" is useful for images and other resources
|
|
55
|
+
// But we don't need it for <Link>
|
|
56
|
+
// unfortunately we can't really make the difference :/
|
|
57
|
+
if (router === 'hash' && targetLink?.startsWith('./')) {
|
|
58
|
+
targetLink = targetLink?.slice(1);
|
|
59
|
+
}
|
|
50
60
|
if (targetLink && isInternal) {
|
|
51
61
|
targetLink = applyTrailingSlash(targetLink, { trailingSlash, baseUrl });
|
|
52
62
|
}
|
|
@@ -103,7 +113,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
103
113
|
// https://github.com/remix-run/react-router/blob/v5/packages/react-router-dom/modules/Link.js#L47
|
|
104
114
|
const hasInternalTarget = !props.target || props.target === '_self';
|
|
105
115
|
// Should we use a regular <a> tag instead of React-Router Link component?
|
|
106
|
-
const isRegularHtmlLink = !targetLink || !isInternal || !hasInternalTarget
|
|
116
|
+
const isRegularHtmlLink = !targetLink || !isInternal || !hasInternalTarget;
|
|
107
117
|
if (!noBrokenLinkCheck && (isAnchorLink || !isRegularHtmlLink)) {
|
|
108
118
|
brokenLinks.collectLink(targetLink);
|
|
109
119
|
}
|
|
@@ -6,5 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/// <reference types="@docusaurus/module-type-aliases" />
|
|
8
8
|
import type { BaseUrlOptions, BaseUrlUtils } from '@docusaurus/useBaseUrl';
|
|
9
|
+
import type { RouterType } from '@docusaurus/types';
|
|
10
|
+
export declare function addBaseUrl({ siteUrl, baseUrl, url, options: { forcePrependBaseUrl, absolute }, router, }: {
|
|
11
|
+
siteUrl: string;
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
url: string;
|
|
14
|
+
router: RouterType;
|
|
15
|
+
options?: BaseUrlOptions;
|
|
16
|
+
}): string;
|
|
9
17
|
export declare function useBaseUrlUtils(): BaseUrlUtils;
|
|
10
18
|
export default function useBaseUrl(url: string, options?: BaseUrlOptions): string;
|
|
@@ -7,12 +7,18 @@
|
|
|
7
7
|
import { useCallback } from 'react';
|
|
8
8
|
import useDocusaurusContext from './useDocusaurusContext';
|
|
9
9
|
import { hasProtocol } from './isInternalUrl';
|
|
10
|
-
function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolute = false } = {}) {
|
|
10
|
+
export function addBaseUrl({ siteUrl, baseUrl, url, options: { forcePrependBaseUrl = false, absolute = false } = {}, router, }) {
|
|
11
11
|
// It never makes sense to add base url to a local anchor url, or one with a
|
|
12
12
|
// protocol
|
|
13
13
|
if (!url || url.startsWith('#') || hasProtocol(url)) {
|
|
14
14
|
return url;
|
|
15
15
|
}
|
|
16
|
+
// TODO hash router + /baseUrl/ is unlikely to work well in all situations
|
|
17
|
+
// This will support most cases, but not all
|
|
18
|
+
// See https://github.com/facebook/docusaurus/pull/9859
|
|
19
|
+
if (router === 'hash') {
|
|
20
|
+
return url.startsWith('/') ? `.${url}` : `./${url}`;
|
|
21
|
+
}
|
|
16
22
|
if (forcePrependBaseUrl) {
|
|
17
23
|
return baseUrl + url.replace(/^\//, '');
|
|
18
24
|
}
|
|
@@ -27,8 +33,10 @@ function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolu
|
|
|
27
33
|
return absolute ? siteUrl + basePath : basePath;
|
|
28
34
|
}
|
|
29
35
|
export function useBaseUrlUtils() {
|
|
30
|
-
const { siteConfig
|
|
31
|
-
const
|
|
36
|
+
const { siteConfig } = useDocusaurusContext();
|
|
37
|
+
const { baseUrl, url: siteUrl } = siteConfig;
|
|
38
|
+
const router = siteConfig.future.experimental_router;
|
|
39
|
+
const withBaseUrl = useCallback((url, options) => addBaseUrl({ siteUrl, baseUrl, url, options, router }), [siteUrl, baseUrl, router]);
|
|
32
40
|
return {
|
|
33
41
|
withBaseUrl,
|
|
34
42
|
};
|
package/lib/commands/build.js
CHANGED
|
@@ -111,7 +111,8 @@ async function buildLocale({ siteDir, locale, cliOptions, }) {
|
|
|
111
111
|
localizePath: cliOptions.locale ? false : undefined,
|
|
112
112
|
}));
|
|
113
113
|
const { props } = site;
|
|
114
|
-
const { outDir, plugins } = props;
|
|
114
|
+
const { outDir, plugins, siteConfig } = props;
|
|
115
|
+
const router = siteConfig.future.experimental_router;
|
|
115
116
|
// We can build the 2 configs in parallel
|
|
116
117
|
const [{ clientConfig, clientManifestPath }, { serverConfig, serverBundlePath }] = await utils_3.PerfLogger.async('Creating webpack configs', () => Promise.all([
|
|
117
118
|
getBuildClientConfig({
|
|
@@ -123,11 +124,19 @@ async function buildLocale({ siteDir, locale, cliOptions, }) {
|
|
|
123
124
|
}),
|
|
124
125
|
]));
|
|
125
126
|
// Run webpack to build JS bundle (client) and static html files (server).
|
|
126
|
-
await utils_3.PerfLogger.async('Bundling with Webpack', () =>
|
|
127
|
+
await utils_3.PerfLogger.async('Bundling with Webpack', () => {
|
|
128
|
+
if (router === 'hash') {
|
|
129
|
+
return (0, utils_2.compile)([clientConfig]);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
return (0, utils_2.compile)([clientConfig, serverConfig]);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
127
135
|
const { collectedData } = await utils_3.PerfLogger.async('SSG', () => executeSSG({
|
|
128
136
|
props,
|
|
129
137
|
serverBundlePath,
|
|
130
138
|
clientManifestPath,
|
|
139
|
+
router,
|
|
131
140
|
}));
|
|
132
141
|
// Remove server.bundle.js because it is not needed.
|
|
133
142
|
await utils_3.PerfLogger.async('Deleting server bundle', () => ensureUnlink(serverBundlePath));
|
|
@@ -138,27 +147,35 @@ async function buildLocale({ siteDir, locale, cliOptions, }) {
|
|
|
138
147
|
logger_1.default.success `Generated static files in path=${path_1.default.relative(process.cwd(), outDir)}.`;
|
|
139
148
|
return outDir;
|
|
140
149
|
}
|
|
141
|
-
async function executeSSG({ props, serverBundlePath, clientManifestPath, }) {
|
|
150
|
+
async function executeSSG({ props, serverBundlePath, clientManifestPath, router, }) {
|
|
142
151
|
const manifest = await utils_3.PerfLogger.async('Read client manifest', () => fs_extra_1.default.readJSON(clientManifestPath, 'utf-8'));
|
|
143
152
|
const ssrTemplate = await utils_3.PerfLogger.async('Compile SSR template', () => (0, templates_1.compileSSRTemplate)(props.siteConfig.ssrTemplate ?? ssr_html_template_1.default));
|
|
153
|
+
const params = {
|
|
154
|
+
trailingSlash: props.siteConfig.trailingSlash,
|
|
155
|
+
outDir: props.outDir,
|
|
156
|
+
baseUrl: props.baseUrl,
|
|
157
|
+
manifest,
|
|
158
|
+
headTags: props.headTags,
|
|
159
|
+
preBodyTags: props.preBodyTags,
|
|
160
|
+
postBodyTags: props.postBodyTags,
|
|
161
|
+
ssrTemplate,
|
|
162
|
+
noIndex: props.siteConfig.noIndex,
|
|
163
|
+
DOCUSAURUS_VERSION: utils_1.DOCUSAURUS_VERSION,
|
|
164
|
+
};
|
|
165
|
+
if (router === 'hash') {
|
|
166
|
+
utils_3.PerfLogger.start('Generate Hash Router entry point');
|
|
167
|
+
const content = (0, templates_1.renderHashRouterTemplate)({ params });
|
|
168
|
+
await (0, ssg_1.generateHashRouterEntrypoint)({ content, params });
|
|
169
|
+
utils_3.PerfLogger.end('Generate Hash Router entry point');
|
|
170
|
+
return { collectedData: {} };
|
|
171
|
+
}
|
|
144
172
|
const renderer = await utils_3.PerfLogger.async('Load App renderer', () => (0, ssg_1.loadAppRenderer)({
|
|
145
173
|
serverBundlePath,
|
|
146
174
|
}));
|
|
147
175
|
const ssgResult = await utils_3.PerfLogger.async('Generate static files', () => (0, ssg_1.generateStaticFiles)({
|
|
148
176
|
pathnames: props.routesPaths,
|
|
149
177
|
renderer,
|
|
150
|
-
params
|
|
151
|
-
trailingSlash: props.siteConfig.trailingSlash,
|
|
152
|
-
outDir: props.outDir,
|
|
153
|
-
baseUrl: props.baseUrl,
|
|
154
|
-
manifest,
|
|
155
|
-
headTags: props.headTags,
|
|
156
|
-
preBodyTags: props.preBodyTags,
|
|
157
|
-
postBodyTags: props.postBodyTags,
|
|
158
|
-
ssrTemplate,
|
|
159
|
-
noIndex: props.siteConfig.noIndex,
|
|
160
|
-
DOCUSAURUS_VERSION: utils_1.DOCUSAURUS_VERSION,
|
|
161
|
-
},
|
|
178
|
+
params,
|
|
162
179
|
}));
|
|
163
180
|
return ssgResult;
|
|
164
181
|
}
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import _ from 'lodash';
|
|
8
8
|
import type { StartCLIOptions } from './start';
|
|
9
|
-
import type { LoadedPlugin } from '@docusaurus/types';
|
|
9
|
+
import type { LoadedPlugin, RouterType } from '@docusaurus/types';
|
|
10
10
|
export type OpenUrlContext = {
|
|
11
11
|
host: string;
|
|
12
12
|
port: number;
|
|
13
|
-
getOpenUrl: ({ baseUrl }: {
|
|
13
|
+
getOpenUrl: ({ baseUrl, router, }: {
|
|
14
14
|
baseUrl: string;
|
|
15
|
+
router: RouterType;
|
|
15
16
|
}) => string;
|
|
16
17
|
};
|
|
17
18
|
export declare function createOpenUrlContext({ cliOptions, }: {
|
|
@@ -23,9 +23,13 @@ async function createOpenUrlContext({ cliOptions, }) {
|
|
|
23
23
|
if (port === null) {
|
|
24
24
|
return process.exit();
|
|
25
25
|
}
|
|
26
|
-
const getOpenUrl = ({ baseUrl }) => {
|
|
26
|
+
const getOpenUrl = ({ baseUrl, router }) => {
|
|
27
27
|
const urls = (0, WebpackDevServerUtils_1.prepareUrls)(protocol, host, port);
|
|
28
|
-
return (0, utils_1.normalizeUrl)([
|
|
28
|
+
return (0, utils_1.normalizeUrl)([
|
|
29
|
+
urls.localUrlForBrowser,
|
|
30
|
+
router === 'hash' ? '/#/' : '',
|
|
31
|
+
baseUrl,
|
|
32
|
+
]);
|
|
29
33
|
};
|
|
30
34
|
return { host, port, getOpenUrl };
|
|
31
35
|
}
|
|
@@ -47,6 +51,7 @@ async function createReloadableSite(startParams) {
|
|
|
47
51
|
const get = () => site;
|
|
48
52
|
const getOpenUrl = () => openUrlContext.getOpenUrl({
|
|
49
53
|
baseUrl: site.props.baseUrl,
|
|
54
|
+
router: site.props.siteConfig.future.experimental_router,
|
|
50
55
|
});
|
|
51
56
|
const printOpenUrlMessage = () => {
|
|
52
57
|
logger_1.default.success `Docusaurus website is running at: url=${getOpenUrl()}`;
|
|
@@ -61,7 +61,7 @@ async function createDevServerConfig({ cliOptions, props, host, port, }) {
|
|
|
61
61
|
'access-control-allow-origin': '*',
|
|
62
62
|
},
|
|
63
63
|
devMiddleware: {
|
|
64
|
-
publicPath: baseUrl,
|
|
64
|
+
publicPath: siteConfig.future.experimental_router === 'hash' ? 'auto' : baseUrl,
|
|
65
65
|
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
|
|
66
66
|
stats: 'summary',
|
|
67
67
|
},
|
|
@@ -23,6 +23,7 @@ exports.DEFAULT_STORAGE_CONFIG = {
|
|
|
23
23
|
};
|
|
24
24
|
exports.DEFAULT_FUTURE_CONFIG = {
|
|
25
25
|
experimental_storage: exports.DEFAULT_STORAGE_CONFIG,
|
|
26
|
+
experimental_router: 'browser',
|
|
26
27
|
};
|
|
27
28
|
exports.DEFAULT_MARKDOWN_CONFIG = {
|
|
28
29
|
format: 'mdx', // TODO change this to "detect" in Docusaurus v4?
|
|
@@ -140,6 +141,9 @@ const STORAGE_CONFIG_SCHEMA = utils_validation_1.Joi.object({
|
|
|
140
141
|
.default(exports.DEFAULT_STORAGE_CONFIG);
|
|
141
142
|
const FUTURE_CONFIG_SCHEMA = utils_validation_1.Joi.object({
|
|
142
143
|
experimental_storage: STORAGE_CONFIG_SCHEMA,
|
|
144
|
+
experimental_router: utils_validation_1.Joi.string()
|
|
145
|
+
.equal('browser', 'hash')
|
|
146
|
+
.default(exports.DEFAULT_FUTURE_CONFIG.experimental_router),
|
|
143
147
|
})
|
|
144
148
|
.optional()
|
|
145
149
|
.default(exports.DEFAULT_FUTURE_CONFIG);
|
package/lib/server/htmlTags.d.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
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 { Props, LoadedPlugin } from '@docusaurus/types';
|
|
7
|
+
import type { Props, LoadedPlugin, RouterType } from '@docusaurus/types';
|
|
8
8
|
/**
|
|
9
9
|
* Runs the `injectHtmlTags` lifecycle, and aggregates all plugins' tags into
|
|
10
10
|
* directly render-able HTML markup.
|
|
11
11
|
*/
|
|
12
|
-
export declare function loadHtmlTags(plugins
|
|
12
|
+
export declare function loadHtmlTags({ plugins, router, }: {
|
|
13
|
+
plugins: LoadedPlugin[];
|
|
14
|
+
router: RouterType;
|
|
15
|
+
}): Pick<Props, 'headTags' | 'preBodyTags' | 'postBodyTags'>;
|
package/lib/server/htmlTags.js
CHANGED
|
@@ -23,16 +23,25 @@ function assertIsHtmlTagObject(val) {
|
|
|
23
23
|
throw new Error(`Error loading ${JSON.stringify(val)}, "${val.tagName}" is not a valid HTML tag.`);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
function
|
|
26
|
+
function hashRouterAbsoluteToRelativeTagAttribute(name, value) {
|
|
27
|
+
if ((name === 'src' || name === 'href') && value.startsWith('/')) {
|
|
28
|
+
return `.${value}`;
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
function htmlTagObjectToString({ tag, router, }) {
|
|
27
33
|
assertIsHtmlTagObject(tag);
|
|
28
34
|
const isVoidTag = void_1.default.includes(tag.tagName);
|
|
29
35
|
const tagAttributes = tag.attributes ?? {};
|
|
30
36
|
const attributes = Object.keys(tagAttributes)
|
|
31
37
|
.map((attr) => {
|
|
32
|
-
|
|
38
|
+
let value = tagAttributes[attr];
|
|
33
39
|
if (typeof value === 'boolean') {
|
|
34
40
|
return value ? attr : undefined;
|
|
35
41
|
}
|
|
42
|
+
if (router === 'hash') {
|
|
43
|
+
value = hashRouterAbsoluteToRelativeTagAttribute(attr, value);
|
|
44
|
+
}
|
|
36
45
|
return `${attr}="${(0, escape_html_1.default)(value)}"`;
|
|
37
46
|
})
|
|
38
47
|
.filter((str) => Boolean(str));
|
|
@@ -41,21 +50,21 @@ function htmlTagObjectToString(tag) {
|
|
|
41
50
|
const closingTag = isVoidTag ? '' : `</${tag.tagName}>`;
|
|
42
51
|
return openingTag + innerHTML + closingTag;
|
|
43
52
|
}
|
|
44
|
-
function createHtmlTagsString(tags) {
|
|
53
|
+
function createHtmlTagsString({ tags, router, }) {
|
|
45
54
|
return (Array.isArray(tags) ? tags : [tags])
|
|
46
55
|
.filter(Boolean)
|
|
47
|
-
.map((val) =>
|
|
56
|
+
.map((val) => typeof val === 'string' ? val : htmlTagObjectToString({ tag: val, router }))
|
|
48
57
|
.join('\n');
|
|
49
58
|
}
|
|
50
59
|
/**
|
|
51
60
|
* Runs the `injectHtmlTags` lifecycle, and aggregates all plugins' tags into
|
|
52
61
|
* directly render-able HTML markup.
|
|
53
62
|
*/
|
|
54
|
-
function loadHtmlTags(plugins) {
|
|
63
|
+
function loadHtmlTags({ plugins, router, }) {
|
|
55
64
|
const pluginHtmlTags = plugins.map((plugin) => plugin.injectHtmlTags?.({ content: plugin.content }) ?? {});
|
|
56
65
|
const tagTypes = ['headTags', 'preBodyTags', 'postBodyTags'];
|
|
57
66
|
return Object.fromEntries(lodash_1.default.zip(tagTypes, tagTypes.map((type) => pluginHtmlTags
|
|
58
|
-
.map((tags) => createHtmlTagsString(tags[type]))
|
|
67
|
+
.map((tags) => createHtmlTagsString({ tags: tags[type], router }))
|
|
59
68
|
.join('\n')
|
|
60
69
|
.trim())));
|
|
61
70
|
}
|
package/lib/server/site.js
CHANGED
|
@@ -73,7 +73,10 @@ exports.loadContext = loadContext;
|
|
|
73
73
|
function createSiteProps(params) {
|
|
74
74
|
const { plugins, routes, context } = params;
|
|
75
75
|
const { generatedFilesDir, siteDir, siteVersion, siteConfig, siteConfigPath, siteStorage, outDir, baseUrl, i18n, localizationDir, codeTranslations: siteCodeTranslations, } = context;
|
|
76
|
-
const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)(
|
|
76
|
+
const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)({
|
|
77
|
+
plugins,
|
|
78
|
+
router: siteConfig.future.experimental_router,
|
|
79
|
+
});
|
|
77
80
|
const siteMetadata = (0, siteMetadata_1.createSiteMetadata)({ plugins, siteVersion });
|
|
78
81
|
const codeTranslations = {
|
|
79
82
|
...(0, translations_1.getPluginsDefaultCodeTranslations)({ plugins }),
|
package/lib/ssg.d.ts
CHANGED
|
@@ -30,3 +30,7 @@ export declare function generateStaticFiles({ pathnames, renderer, params, }: {
|
|
|
30
30
|
}): Promise<{
|
|
31
31
|
collectedData: SiteCollectedData;
|
|
32
32
|
}>;
|
|
33
|
+
export declare function generateHashRouterEntrypoint({ content, params, }: {
|
|
34
|
+
content: string;
|
|
35
|
+
params: SSGParams;
|
|
36
|
+
}): Promise<void>;
|
package/lib/ssg.js
CHANGED
|
@@ -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.generateStaticFiles = exports.loadAppRenderer = void 0;
|
|
9
|
+
exports.generateHashRouterEntrypoint = exports.generateStaticFiles = exports.loadAppRenderer = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
12
|
const module_1 = require("module");
|
|
@@ -133,6 +133,14 @@ It might also require to wrap your client code in ${logger_1.default.code('useEf
|
|
|
133
133
|
}
|
|
134
134
|
return parts.join('\n');
|
|
135
135
|
}
|
|
136
|
+
async function generateHashRouterEntrypoint({ content, params, }) {
|
|
137
|
+
await writeStaticFile({
|
|
138
|
+
pathname: '/',
|
|
139
|
+
content,
|
|
140
|
+
params,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
exports.generateHashRouterEntrypoint = generateHashRouterEntrypoint;
|
|
136
144
|
async function writeStaticFile({ content, pathname, params, }) {
|
|
137
145
|
function removeBaseUrl(p, baseUrl) {
|
|
138
146
|
return baseUrl === '/' ? p : p.replace(new RegExp(`^${baseUrl}`), '/');
|
|
@@ -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.renderSSRTemplate = exports.compileSSRTemplate = void 0;
|
|
9
|
+
exports.renderHashRouterTemplate = exports.renderSSRTemplate = exports.compileSSRTemplate = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const eta = tslib_1.__importStar(require("eta"));
|
|
12
12
|
const react_loadable_ssr_addon_v5_slorber_1 = require("react-loadable-ssr-addon-v5-slorber");
|
|
@@ -61,3 +61,28 @@ function renderSSRTemplate({ params, result, }) {
|
|
|
61
61
|
return ssrTemplate(data);
|
|
62
62
|
}
|
|
63
63
|
exports.renderSSRTemplate = renderSSRTemplate;
|
|
64
|
+
function renderHashRouterTemplate({ params, }) {
|
|
65
|
+
const {
|
|
66
|
+
// baseUrl,
|
|
67
|
+
headTags, preBodyTags, postBodyTags, manifest, DOCUSAURUS_VERSION, ssrTemplate, } = params;
|
|
68
|
+
const { scripts, stylesheets } = getScriptsAndStylesheets({
|
|
69
|
+
manifest,
|
|
70
|
+
modules: [],
|
|
71
|
+
});
|
|
72
|
+
const data = {
|
|
73
|
+
appHtml: '',
|
|
74
|
+
baseUrl: './',
|
|
75
|
+
htmlAttributes: '',
|
|
76
|
+
bodyAttributes: '',
|
|
77
|
+
headTags,
|
|
78
|
+
preBodyTags,
|
|
79
|
+
postBodyTags,
|
|
80
|
+
metaAttributes: [],
|
|
81
|
+
scripts,
|
|
82
|
+
stylesheets,
|
|
83
|
+
noIndex: false,
|
|
84
|
+
version: DOCUSAURUS_VERSION,
|
|
85
|
+
};
|
|
86
|
+
return ssrTemplate(data);
|
|
87
|
+
}
|
|
88
|
+
exports.renderHashRouterTemplate = renderHashRouterTemplate;
|
package/lib/webpack/base.js
CHANGED
|
@@ -79,7 +79,7 @@ async function createBaseConfig({ props, isServer, minify, }) {
|
|
|
79
79
|
chunkFilename: isProd
|
|
80
80
|
? 'assets/js/[name].[contenthash:8].js'
|
|
81
81
|
: '[name].js',
|
|
82
|
-
publicPath: baseUrl,
|
|
82
|
+
publicPath: siteConfig.future.experimental_router === 'hash' ? 'auto' : baseUrl,
|
|
83
83
|
hashFunction: 'xxhash64',
|
|
84
84
|
},
|
|
85
85
|
// Don't throw warning when asset created is over 250kb
|
package/lib/webpack/client.js
CHANGED
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.createBuildClientConfig = exports.createStartClientConfig = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
|
-
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
13
12
|
const webpack_merge_1 = tslib_1.__importDefault(require("webpack-merge"));
|
|
14
13
|
const webpackbar_1 = tslib_1.__importDefault(require("webpackbar"));
|
|
15
14
|
const webpack_1 = tslib_1.__importDefault(require("webpack"));
|
|
@@ -18,21 +17,9 @@ const react_loadable_ssr_addon_v5_slorber_1 = tslib_1.__importDefault(require("r
|
|
|
18
17
|
const html_webpack_plugin_1 = tslib_1.__importDefault(require("html-webpack-plugin"));
|
|
19
18
|
const base_1 = require("./base");
|
|
20
19
|
const ChunkAssetPlugin_1 = tslib_1.__importDefault(require("./plugins/ChunkAssetPlugin"));
|
|
21
|
-
const utils_1 = require("./utils");
|
|
22
20
|
const CleanWebpackPlugin_1 = tslib_1.__importDefault(require("./plugins/CleanWebpackPlugin"));
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class ForceTerminatePlugin {
|
|
26
|
-
apply(compiler) {
|
|
27
|
-
compiler.hooks.done.tap('client:done', (stats) => {
|
|
28
|
-
if (stats.hasErrors()) {
|
|
29
|
-
const errorsWarnings = stats.toJson('errors-warnings');
|
|
30
|
-
logger_1.default.error(`Client bundle compiled with errors therefore further build is impossible.\n${(0, utils_1.formatStatsErrorMessage)(errorsWarnings)}`);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
21
|
+
const ForceTerminatePlugin_1 = tslib_1.__importDefault(require("./plugins/ForceTerminatePlugin"));
|
|
22
|
+
const StaticDirectoriesCopyPlugin_1 = require("./plugins/StaticDirectoriesCopyPlugin");
|
|
36
23
|
async function createBaseClientConfig({ props, hydrate, minify, }) {
|
|
37
24
|
const baseConfig = await (0, base_1.createBaseConfig)({ props, isServer: false, minify });
|
|
38
25
|
return (0, webpack_merge_1.default)(baseConfig, {
|
|
@@ -54,6 +41,7 @@ async function createBaseClientConfig({ props, hydrate, minify, }) {
|
|
|
54
41
|
new webpackbar_1.default({
|
|
55
42
|
name: 'Client',
|
|
56
43
|
}),
|
|
44
|
+
await (0, StaticDirectoriesCopyPlugin_1.createStaticDirectoriesCopyPlugin)({ props }),
|
|
57
45
|
],
|
|
58
46
|
});
|
|
59
47
|
}
|
|
@@ -93,11 +81,15 @@ exports.createStartClientConfig = createStartClientConfig;
|
|
|
93
81
|
// client config when running "docusaurus build"
|
|
94
82
|
async function createBuildClientConfig({ props, minify, bundleAnalyzer, }) {
|
|
95
83
|
// Apply user webpack config.
|
|
96
|
-
const { generatedFilesDir } = props;
|
|
84
|
+
const { generatedFilesDir, siteConfig } = props;
|
|
85
|
+
const router = siteConfig.future.experimental_router;
|
|
86
|
+
// With the hash router, we don't hydrate the React app, even in build mode!
|
|
87
|
+
// This is because it will always be a client-rendered React app
|
|
88
|
+
const hydrate = router !== 'hash';
|
|
97
89
|
const clientManifestPath = path_1.default.join(generatedFilesDir, 'client-manifest.json');
|
|
98
|
-
const config = (0, webpack_merge_1.default)(await createBaseClientConfig({ props, minify, hydrate
|
|
90
|
+
const config = (0, webpack_merge_1.default)(await createBaseClientConfig({ props, minify, hydrate }), {
|
|
99
91
|
plugins: [
|
|
100
|
-
new
|
|
92
|
+
new ForceTerminatePlugin_1.default(),
|
|
101
93
|
// Remove/clean build folders before building bundles.
|
|
102
94
|
new CleanWebpackPlugin_1.default({ verbose: false }),
|
|
103
95
|
// Visualize size of webpack output files with an interactive zoomable
|
|
@@ -0,0 +1,10 @@
|
|
|
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 webpack from 'webpack';
|
|
8
|
+
export default class ForceTerminatePlugin implements webpack.WebpackPluginInstance {
|
|
9
|
+
apply(compiler: webpack.Compiler): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
11
|
+
const utils_1 = require("../utils");
|
|
12
|
+
// When building, include the plugin to force terminate building if errors
|
|
13
|
+
// happened in the client bundle.
|
|
14
|
+
class ForceTerminatePlugin {
|
|
15
|
+
apply(compiler) {
|
|
16
|
+
compiler.hooks.done.tap('client:done', (stats) => {
|
|
17
|
+
if (stats.hasErrors()) {
|
|
18
|
+
const errorsWarnings = stats.toJson('errors-warnings');
|
|
19
|
+
logger_1.default.error(`Client bundle compiled with errors therefore further build is impossible.\n${(0, utils_1.formatStatsErrorMessage)(errorsWarnings)}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = ForceTerminatePlugin;
|
|
@@ -0,0 +1,11 @@
|
|
|
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 CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
8
|
+
import type { Props } from '@docusaurus/types';
|
|
9
|
+
export declare function createStaticDirectoriesCopyPlugin({ props, }: {
|
|
10
|
+
props: Props;
|
|
11
|
+
}): Promise<CopyWebpackPlugin | undefined>;
|
|
@@ -0,0 +1,39 @@
|
|
|
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.createStaticDirectoriesCopyPlugin = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
13
|
+
const copy_webpack_plugin_1 = tslib_1.__importDefault(require("copy-webpack-plugin"));
|
|
14
|
+
async function createStaticDirectoriesCopyPlugin({ props, }) {
|
|
15
|
+
const { outDir, siteDir, siteConfig: { staticDirectories: staticDirectoriesOption }, } = props;
|
|
16
|
+
// The staticDirectories option can contain empty directories, or non-existent
|
|
17
|
+
// directories (e.g. user deleted `static`). Instead of issuing an error, we
|
|
18
|
+
// just silently filter them out, because user could have never configured it
|
|
19
|
+
// in the first place (the default option should always "work").
|
|
20
|
+
const staticDirectories = (await Promise.all(staticDirectoriesOption.map(async (dir) => {
|
|
21
|
+
const staticDir = path_1.default.resolve(siteDir, dir);
|
|
22
|
+
if ((await fs_extra_1.default.pathExists(staticDir)) &&
|
|
23
|
+
(await fs_extra_1.default.readdir(staticDir)).length > 0) {
|
|
24
|
+
return staticDir;
|
|
25
|
+
}
|
|
26
|
+
return '';
|
|
27
|
+
}))).filter(Boolean);
|
|
28
|
+
if (staticDirectories.length === 0) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return new copy_webpack_plugin_1.default({
|
|
32
|
+
patterns: staticDirectories.map((dir) => ({
|
|
33
|
+
from: dir,
|
|
34
|
+
to: outDir,
|
|
35
|
+
toType: 'dir',
|
|
36
|
+
})),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
exports.createStaticDirectoriesCopyPlugin = createStaticDirectoriesCopyPlugin;
|
package/lib/webpack/server.js
CHANGED
|
@@ -8,11 +8,9 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
const tslib_1 = require("tslib");
|
|
10
10
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
11
|
-
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
11
|
const webpack_merge_1 = tslib_1.__importDefault(require("webpack-merge"));
|
|
13
12
|
const utils_1 = require("@docusaurus/utils");
|
|
14
13
|
const webpackbar_1 = tslib_1.__importDefault(require("webpackbar"));
|
|
15
|
-
const copy_webpack_plugin_1 = tslib_1.__importDefault(require("copy-webpack-plugin"));
|
|
16
14
|
const base_1 = require("./base");
|
|
17
15
|
async function createServerConfig(params) {
|
|
18
16
|
const { props } = params;
|
|
@@ -41,34 +39,8 @@ async function createServerConfig(params) {
|
|
|
41
39
|
name: 'Server',
|
|
42
40
|
color: 'yellow',
|
|
43
41
|
}),
|
|
44
|
-
await createStaticDirectoriesCopyPlugin(params),
|
|
45
42
|
].filter(Boolean),
|
|
46
43
|
});
|
|
47
44
|
return { config, serverBundlePath };
|
|
48
45
|
}
|
|
49
46
|
exports.default = createServerConfig;
|
|
50
|
-
async function createStaticDirectoriesCopyPlugin({ props }) {
|
|
51
|
-
const { outDir, siteDir, siteConfig: { staticDirectories: staticDirectoriesOption }, } = props;
|
|
52
|
-
// The staticDirectories option can contain empty directories, or non-existent
|
|
53
|
-
// directories (e.g. user deleted `static`). Instead of issuing an error, we
|
|
54
|
-
// just silently filter them out, because user could have never configured it
|
|
55
|
-
// in the first place (the default option should always "work").
|
|
56
|
-
const staticDirectories = (await Promise.all(staticDirectoriesOption.map(async (dir) => {
|
|
57
|
-
const staticDir = path_1.default.resolve(siteDir, dir);
|
|
58
|
-
if ((await fs_extra_1.default.pathExists(staticDir)) &&
|
|
59
|
-
(await fs_extra_1.default.readdir(staticDir)).length > 0) {
|
|
60
|
-
return staticDir;
|
|
61
|
-
}
|
|
62
|
-
return '';
|
|
63
|
-
}))).filter(Boolean);
|
|
64
|
-
if (staticDirectories.length === 0) {
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
return new copy_webpack_plugin_1.default({
|
|
68
|
-
patterns: staticDirectories.map((dir) => ({
|
|
69
|
-
from: dir,
|
|
70
|
-
to: outDir,
|
|
71
|
-
toType: 'dir',
|
|
72
|
-
})),
|
|
73
|
-
});
|
|
74
|
-
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/core",
|
|
3
3
|
"description": "Easy to Maintain Open Source Documentation Websites",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-5953",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"@babel/runtime": "^7.22.6",
|
|
44
44
|
"@babel/runtime-corejs3": "^7.22.6",
|
|
45
45
|
"@babel/traverse": "^7.22.8",
|
|
46
|
-
"@docusaurus/cssnano-preset": "0.0.0-
|
|
47
|
-
"@docusaurus/logger": "0.0.0-
|
|
48
|
-
"@docusaurus/mdx-loader": "0.0.0-
|
|
49
|
-
"@docusaurus/utils": "0.0.0-
|
|
50
|
-
"@docusaurus/utils-common": "0.0.0-
|
|
51
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
46
|
+
"@docusaurus/cssnano-preset": "0.0.0-5953",
|
|
47
|
+
"@docusaurus/logger": "0.0.0-5953",
|
|
48
|
+
"@docusaurus/mdx-loader": "0.0.0-5953",
|
|
49
|
+
"@docusaurus/utils": "0.0.0-5953",
|
|
50
|
+
"@docusaurus/utils-common": "0.0.0-5953",
|
|
51
|
+
"@docusaurus/utils-validation": "0.0.0-5953",
|
|
52
52
|
"autoprefixer": "^10.4.14",
|
|
53
53
|
"babel-loader": "^9.1.3",
|
|
54
54
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
@@ -103,8 +103,8 @@
|
|
|
103
103
|
"webpackbar": "^5.0.2"
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
|
-
"@docusaurus/module-type-aliases": "0.0.0-
|
|
107
|
-
"@docusaurus/types": "0.0.0-
|
|
106
|
+
"@docusaurus/module-type-aliases": "0.0.0-5953",
|
|
107
|
+
"@docusaurus/types": "0.0.0-5953",
|
|
108
108
|
"@total-typescript/shoehorn": "^0.1.2",
|
|
109
109
|
"@types/detect-port": "^1.3.3",
|
|
110
110
|
"@types/react-dom": "^18.2.7",
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"engines": {
|
|
125
125
|
"node": ">=18.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "dcfda109529e5e3bd7e1360fcc421e243d7e569b"
|
|
128
128
|
}
|