@docusaurus/core 0.0.0-4523 → 0.0.0-4527
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/babel/preset.js +5 -4
- package/lib/client/PendingNavigation.d.ts +3 -3
- package/lib/client/PendingNavigation.js +2 -2
- package/lib/client/baseUrlIssueBanner/BaseUrlIssueBanner.d.ts +8 -0
- package/lib/client/baseUrlIssueBanner/BaseUrlIssueBanner.js +8 -5
- package/lib/client/clientEntry.js +5 -3
- package/lib/client/docusaurus.js +6 -4
- package/lib/client/exports/ComponentCreator.js +4 -1
- package/lib/client/exports/Interpolate.js +9 -13
- package/lib/client/exports/Link.js +4 -3
- package/lib/client/exports/Translate.js +2 -1
- package/lib/client/exports/browserContext.js +2 -1
- package/lib/client/exports/isInternalUrl.js +1 -1
- package/lib/client/preload.d.ts +2 -1
- package/lib/client/preload.js +2 -1
- package/lib/client/serverEntry.js +2 -2
- package/lib/client/theme-fallback/Error/index.js +5 -3
- package/lib/commands/build.js +15 -17
- package/lib/commands/deploy.js +4 -4
- package/lib/commands/external.js +1 -1
- package/lib/commands/serve.js +2 -2
- package/lib/commands/swizzle.js +7 -5
- package/lib/commands/writeHeadingIds.js +12 -13
- package/lib/commands/writeTranslations.js +8 -5
- package/lib/server/brokenLinks.js +14 -9
- package/lib/server/duplicateRoutes.js +2 -4
- package/lib/server/i18n.js +11 -15
- package/lib/server/index.d.ts +1 -1
- package/lib/server/index.js +13 -11
- package/lib/server/moduleShorthand.js +1 -1
- package/lib/server/plugins/index.js +6 -6
- package/lib/server/plugins/init.js +14 -24
- package/lib/server/presets/index.d.ts +2 -2
- package/lib/server/presets/index.js +3 -3
- package/lib/server/routes.js +3 -2
- package/lib/server/themes/index.js +3 -2
- package/lib/server/translations/translations.js +2 -4
- package/lib/server/translations/translationsExtractor.js +17 -14
- package/lib/server/versions/index.js +4 -2
- package/lib/webpack/base.js +23 -15
- package/lib/webpack/client.js +5 -2
- package/lib/webpack/plugins/ChunkAssetPlugin.d.ts +11 -0
- package/lib/webpack/plugins/ChunkAssetPlugin.js +17 -10
- package/lib/webpack/plugins/CleanWebpackPlugin.d.ts +4 -3
- package/lib/webpack/plugins/CleanWebpackPlugin.js +2 -1
- package/lib/webpack/server.js +4 -3
- package/lib/webpack/utils.js +8 -9
- package/package.json +10 -10
package/lib/babel/preset.js
CHANGED
|
@@ -11,7 +11,8 @@ const path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
|
11
11
|
function getTransformOptions(isServer) {
|
|
12
12
|
const absoluteRuntimePath = path_1.default.dirname(require.resolve(`@babel/runtime/package.json`));
|
|
13
13
|
return {
|
|
14
|
-
// All optional newlines and whitespace will be omitted when generating code
|
|
14
|
+
// All optional newlines and whitespace will be omitted when generating code
|
|
15
|
+
// in compact mode
|
|
15
16
|
compact: true,
|
|
16
17
|
presets: [
|
|
17
18
|
isServer
|
|
@@ -46,9 +47,9 @@ function getTransformOptions(isServer) {
|
|
|
46
47
|
{
|
|
47
48
|
corejs: false,
|
|
48
49
|
helpers: true,
|
|
49
|
-
// By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0,
|
|
50
|
-
// explicitly specify the version so that it can reuse the
|
|
51
|
-
// See https://github.com/babel/babel/issues/10261
|
|
50
|
+
// By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0,
|
|
51
|
+
// better to explicitly specify the version so that it can reuse the
|
|
52
|
+
// helper better. See https://github.com/babel/babel/issues/10261
|
|
52
53
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
53
54
|
version: require('@babel/runtime/package.json').version,
|
|
54
55
|
regenerator: true,
|
|
@@ -23,9 +23,9 @@ declare class PendingNavigation extends React.Component<Props, State> {
|
|
|
23
23
|
progressBarTimeout: NodeJS.Timeout | null;
|
|
24
24
|
constructor(props: Props);
|
|
25
25
|
shouldComponentUpdate(nextProps: Props, nextState: State): boolean;
|
|
26
|
-
clearProgressBarTimeout
|
|
27
|
-
startProgressBar
|
|
28
|
-
stopProgressBar
|
|
26
|
+
private clearProgressBarTimeout;
|
|
27
|
+
private startProgressBar;
|
|
28
|
+
private stopProgressBar;
|
|
29
29
|
render(): JSX.Element;
|
|
30
30
|
}
|
|
31
31
|
declare const _default: React.ComponentClass<Pick<Props, "routes" | "delay">, any> & import("react-router").WithRouterStatics<typeof PendingNavigation>;
|
|
@@ -27,8 +27,8 @@ class PendingNavigation extends React.Component {
|
|
|
27
27
|
shouldComponentUpdate(nextProps, nextState) {
|
|
28
28
|
const routeDidChange = nextProps.location !== this.props.location;
|
|
29
29
|
const { routes, delay } = this.props;
|
|
30
|
-
// If `routeDidChange` is true, means the router is trying to navigate to a
|
|
31
|
-
// route. We will preload the new route.
|
|
30
|
+
// If `routeDidChange` is true, means the router is trying to navigate to a
|
|
31
|
+
// new route. We will preload the new route.
|
|
32
32
|
if (routeDidChange) {
|
|
33
33
|
const nextLocation = normalizeLocation(nextProps.location);
|
|
34
34
|
this.startProgressBar(delay);
|
|
@@ -11,4 +11,12 @@ declare global {
|
|
|
11
11
|
__DOCUSAURUS_INSERT_BASEURL_BANNER: boolean;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* We want to help the users with a bad baseUrl configuration (very common
|
|
16
|
+
* error) Help message is inlined, and hidden if JS or CSS is able to load
|
|
17
|
+
* Note: it might create false positives (ie network failures): not a big deal
|
|
18
|
+
* Note: we only inline this for the homepage to avoid polluting all the site's
|
|
19
|
+
* pages
|
|
20
|
+
* @see https://github.com/facebook/docusaurus/pull/3621
|
|
21
|
+
*/
|
|
14
22
|
export default function BaseUrlIssueBanner(): JSX.Element | null;
|
|
@@ -74,11 +74,14 @@ function BaseUrlIssueBannerEnabled() {
|
|
|
74
74
|
<div id={BannerContainerId}/>
|
|
75
75
|
</>);
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
/**
|
|
78
|
+
* We want to help the users with a bad baseUrl configuration (very common
|
|
79
|
+
* error) Help message is inlined, and hidden if JS or CSS is able to load
|
|
80
|
+
* Note: it might create false positives (ie network failures): not a big deal
|
|
81
|
+
* Note: we only inline this for the homepage to avoid polluting all the site's
|
|
82
|
+
* pages
|
|
83
|
+
* @see https://github.com/facebook/docusaurus/pull/3621
|
|
84
|
+
*/
|
|
82
85
|
export default function BaseUrlIssueBanner() {
|
|
83
86
|
const { siteConfig: { baseUrl, baseUrlIssueBanner }, } = useDocusaurusContext();
|
|
84
87
|
const { pathname } = useLocation();
|
|
@@ -12,12 +12,14 @@ import ExecutionEnvironment from './exports/ExecutionEnvironment';
|
|
|
12
12
|
import App from './App';
|
|
13
13
|
import preload from './preload';
|
|
14
14
|
import docusaurus from './docusaurus';
|
|
15
|
-
// Client-side render (e.g: running in browser) to become single-page
|
|
15
|
+
// Client-side render (e.g: running in browser) to become single-page
|
|
16
|
+
// application (SPA).
|
|
16
17
|
if (ExecutionEnvironment.canUseDOM) {
|
|
17
18
|
window.docusaurus = docusaurus;
|
|
18
|
-
// For production, attempt to hydrate existing markup for performant
|
|
19
|
+
// For production, attempt to hydrate existing markup for performant
|
|
20
|
+
// first-load experience.
|
|
19
21
|
// For development, there is no existing markup so we had to render it.
|
|
20
|
-
//
|
|
22
|
+
// We also preload async component to avoid first-load loading screen.
|
|
21
23
|
const renderMethod = process.env.NODE_ENV === 'production' ? hydrate : render;
|
|
22
24
|
preload(routes, window.location.pathname).then(() => {
|
|
23
25
|
renderMethod(<BrowserRouter>
|
package/lib/client/docusaurus.js
CHANGED
|
@@ -23,7 +23,7 @@ const canPreload = (routePath) => !isSlowConnection() && !loaded[routePath];
|
|
|
23
23
|
// Remove the last part containing the route hash
|
|
24
24
|
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
|
|
25
25
|
// output: /blog/2018/12/14/Happy-First-Birthday-Slash
|
|
26
|
-
const removeRouteNameHash = (str) => str.replace(
|
|
26
|
+
const removeRouteNameHash = (str) => str.replace(/-[^-]+$/, '');
|
|
27
27
|
const getChunkNamesToLoad = (path) => Object.entries(routesChunkNames)
|
|
28
28
|
.filter(([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path)
|
|
29
29
|
.flatMap(([, routeChunks]) =>
|
|
@@ -41,11 +41,13 @@ const docusaurus = {
|
|
|
41
41
|
const chunkNamesNeeded = matches.flatMap((match) => getChunkNamesToLoad(match.route.path));
|
|
42
42
|
// Prefetch all webpack chunk assets file needed.
|
|
43
43
|
chunkNamesNeeded.forEach((chunkName) => {
|
|
44
|
-
// "__webpack_require__.gca" is a custom function provided by
|
|
45
|
-
// Pass it the chunkName or chunkId you want to load and
|
|
44
|
+
// "__webpack_require__.gca" is a custom function provided by
|
|
45
|
+
// ChunkAssetPlugin. Pass it the chunkName or chunkId you want to load and
|
|
46
|
+
// it will return the URL for that chunk.
|
|
46
47
|
// eslint-disable-next-line camelcase
|
|
47
48
|
const chunkAsset = __webpack_require__.gca(chunkName);
|
|
48
|
-
// In some cases, webpack might decide to optimize further & hence the
|
|
49
|
+
// In some cases, webpack might decide to optimize further & hence the
|
|
50
|
+
// chunk assets are merged to another chunk/previous chunk.
|
|
49
51
|
// Hence, we can safely filter it out/don't need to load it.
|
|
50
52
|
if (chunkAsset && !/undefined/.test(chunkAsset)) {
|
|
51
53
|
prefetchHelper(chunkAsset);
|
|
@@ -32,7 +32,10 @@ function ComponentCreator(path, hash) {
|
|
|
32
32
|
content.foo: () => import('./doc1.md'),
|
|
33
33
|
}
|
|
34
34
|
- optsModules: ['./Pages.js', './doc1.md']
|
|
35
|
-
- optsWebpack: [
|
|
35
|
+
- optsWebpack: [
|
|
36
|
+
require.resolveWeak('./Pages.js'),
|
|
37
|
+
require.resolveWeak('./doc1.md'),
|
|
38
|
+
]
|
|
36
39
|
*/
|
|
37
40
|
const flatChunkNames = flat(chunkNames);
|
|
38
41
|
Object.keys(flatChunkNames).forEach((key) => {
|
|
@@ -26,30 +26,26 @@ export function interpolate(text, values) {
|
|
|
26
26
|
elements.push(element);
|
|
27
27
|
return ValueFoundMarker;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
return match; // no match? add warning?
|
|
31
|
-
}
|
|
29
|
+
return match; // no match? add warning?
|
|
32
30
|
});
|
|
33
31
|
// No interpolation to be done: just return the text
|
|
34
32
|
if (elements.length === 0) {
|
|
35
33
|
return text;
|
|
36
34
|
}
|
|
37
35
|
// Basic string interpolation: returns interpolated string
|
|
38
|
-
|
|
36
|
+
if (elements.every((el) => typeof el === 'string')) {
|
|
39
37
|
return processedText
|
|
40
38
|
.split(ValueFoundMarker)
|
|
41
39
|
.reduce((str, value, index) => { var _a; return str.concat(value).concat((_a = elements[index]) !== null && _a !== void 0 ? _a : ''); }, '');
|
|
42
40
|
}
|
|
43
41
|
// JSX interpolation: returns ReactNode
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
], []);
|
|
52
|
-
}
|
|
42
|
+
return processedText.split(ValueFoundMarker).reduce((array, value, index) => [
|
|
43
|
+
...array,
|
|
44
|
+
<React.Fragment key={index}>
|
|
45
|
+
{value}
|
|
46
|
+
{elements[index]}
|
|
47
|
+
</React.Fragment>,
|
|
48
|
+
], []);
|
|
53
49
|
}
|
|
54
50
|
export default function Interpolate({ children, values, }) {
|
|
55
51
|
if (typeof children !== 'string') {
|
|
@@ -57,7 +57,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
57
57
|
ioRef.current = new window.IntersectionObserver((entries) => {
|
|
58
58
|
entries.forEach((entry) => {
|
|
59
59
|
if (el === entry.target) {
|
|
60
|
-
// If element is in viewport, stop
|
|
60
|
+
// If element is in viewport, stop observing and run callback.
|
|
61
61
|
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
|
|
62
62
|
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
63
63
|
ioRef.current.unobserve(el);
|
|
@@ -72,7 +72,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
72
72
|
};
|
|
73
73
|
const handleRef = (ref) => {
|
|
74
74
|
if (IOSupported && ref && isInternal) {
|
|
75
|
-
// If IO supported and element reference found,
|
|
75
|
+
// If IO supported and element reference found, set up Observer.
|
|
76
76
|
handleIntersection(ref, () => {
|
|
77
77
|
if (targetLink != null) {
|
|
78
78
|
window.docusaurus.prefetch(targetLink);
|
|
@@ -109,7 +109,8 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
109
109
|
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
110
110
|
<a href={targetLink} {...(targetLinkUnprefixed &&
|
|
111
111
|
!isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink || ''}
|
|
112
|
-
// avoid "React does not recognize the `activeClassName` prop on a DOM
|
|
112
|
+
// avoid "React does not recognize the `activeClassName` prop on a DOM
|
|
113
|
+
// element"
|
|
113
114
|
{...(isNavLink && { isActive, activeClassName })}/>);
|
|
114
115
|
}
|
|
115
116
|
export default Link;
|
|
@@ -22,7 +22,8 @@ export function translate({ message, id }, values) {
|
|
|
22
22
|
return interpolate(localizedMessage, values);
|
|
23
23
|
}
|
|
24
24
|
// Maybe we'll want to improve this component with additional features
|
|
25
|
-
// Like toggling a translation mode that adds a little translation button near
|
|
25
|
+
// Like toggling a translation mode that adds a little translation button near
|
|
26
|
+
// the text?
|
|
26
27
|
export default function Translate({ children, id, values, }) {
|
|
27
28
|
if (children && typeof children !== 'string') {
|
|
28
29
|
console.warn('Illegal <Translate> children', children);
|
|
@@ -10,7 +10,8 @@ import React, { useEffect, useState } from 'react';
|
|
|
10
10
|
// On first client-side render, we need to render exactly as the server rendered
|
|
11
11
|
// isBrowser is set to true only after a successful hydration
|
|
12
12
|
// Note, isBrowser is not part of useDocusaurusContext() for perf reasons
|
|
13
|
-
// Using useDocusaurusContext() (much more common need) should not trigger
|
|
13
|
+
// Using useDocusaurusContext() (much more common need) should not trigger
|
|
14
|
+
// re-rendering after a successful hydration
|
|
14
15
|
export const Context = React.createContext(false);
|
|
15
16
|
export function BrowserContextProvider({ children, }) {
|
|
16
17
|
const [isBrowser, setIsBrowser] = useState(false);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
export function hasProtocol(url) {
|
|
8
|
-
return /^(
|
|
8
|
+
return /^(?:\w*:|\/\/)/.test(url) === true;
|
|
9
9
|
}
|
|
10
10
|
export default function isInternalUrl(url) {
|
|
11
11
|
return typeof url !== 'undefined' && !hasProtocol(url);
|
package/lib/client/preload.d.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
import { type RouteConfig } from 'react-router-config';
|
|
8
8
|
/**
|
|
9
9
|
* Helper function to make sure all async components for that particular route
|
|
10
|
-
* is preloaded before rendering. This is especially useful to avoid loading
|
|
10
|
+
* is preloaded before rendering. This is especially useful to avoid loading
|
|
11
|
+
* screens.
|
|
11
12
|
*
|
|
12
13
|
* @param routes react-router-config
|
|
13
14
|
* @param pathname the route pathname, example: /docs/installation
|
package/lib/client/preload.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
import { matchRoutes } from 'react-router-config';
|
|
8
8
|
/**
|
|
9
9
|
* Helper function to make sure all async components for that particular route
|
|
10
|
-
* is preloaded before rendering. This is especially useful to avoid loading
|
|
10
|
+
* is preloaded before rendering. This is especially useful to avoid loading
|
|
11
|
+
* screens.
|
|
11
12
|
*
|
|
12
13
|
* @param routes react-router-config
|
|
13
14
|
* @param pathname the route pathname, example: /docs/installation
|
|
@@ -37,7 +37,7 @@ export default async function render(locals) {
|
|
|
37
37
|
catch (e) {
|
|
38
38
|
logger.error `Docusaurus Node/SSR could not render static page with path path=${locals.path} because of following error:
|
|
39
39
|
${e.stack}`;
|
|
40
|
-
const isNotDefinedErrorRegex = /(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
|
|
40
|
+
const isNotDefinedErrorRegex = /(?:window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
|
|
41
41
|
if (isNotDefinedErrorRegex.test(e.message)) {
|
|
42
42
|
logger.info `It looks like you are using code that should run on the client-side only.
|
|
43
43
|
To get around it, try using code=${'<BrowserOnly>'} (path=${'https://docusaurus.io/docs/docusaurus-core/#browseronly'}) or code=${'ExecutionEnvironment'} (path=${'https://docusaurus.io/docs/docusaurus-core/#executionenvironment'}).
|
|
@@ -46,7 +46,7 @@ It might also require to wrap your client code in code=${'useEffect'} hook and/o
|
|
|
46
46
|
throw new Error('Server-side rendering fails due to the error above.');
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
// Renderer for static-site-generator-webpack-plugin (async rendering
|
|
49
|
+
// Renderer for static-site-generator-webpack-plugin (async rendering).
|
|
50
50
|
async function doRender(locals) {
|
|
51
51
|
const { routesLocation, headTags, preBodyTags, postBodyTags, onLinksCollected, baseUrl, ssrTemplate, noIndex, } = locals;
|
|
52
52
|
const location = routesLocation[locals.path];
|
|
@@ -25,10 +25,12 @@ function ErrorDisplay({ error, tryAgain }) {
|
|
|
25
25
|
</div>);
|
|
26
26
|
}
|
|
27
27
|
function Error({ error, tryAgain }) {
|
|
28
|
-
// We wrap the error in its own error boundary because the layout can actually
|
|
29
|
-
// Only the ErrorDisplay component is simple enough to be
|
|
28
|
+
// We wrap the error in its own error boundary because the layout can actually
|
|
29
|
+
// throw too... Only the ErrorDisplay component is simple enough to be
|
|
30
|
+
// considered safe to never throw
|
|
30
31
|
return (<ErrorBoundary
|
|
31
|
-
// Note: we display the original error here, not the error that we
|
|
32
|
+
// Note: we display the original error here, not the error that we
|
|
33
|
+
// captured in this extra error boundary
|
|
32
34
|
fallback={() => <ErrorDisplay error={error} tryAgain={tryAgain}/>}>
|
|
33
35
|
<Layout title="Page Error">
|
|
34
36
|
<ErrorDisplay error={error} tryAgain={tryAgain}/>
|
package/lib/commands/build.js
CHANGED
|
@@ -58,22 +58,20 @@ forceTerminate = true) {
|
|
|
58
58
|
if (cliOptions.locale) {
|
|
59
59
|
return tryToBuildLocale({ locale: cliOptions.locale, isLastLocale: true });
|
|
60
60
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
logger_1.default.info `Website will be built for all these locales: ${i18n.locales}`;
|
|
64
|
-
}
|
|
65
|
-
// We need the default locale to always be the 1st in the list
|
|
66
|
-
// If we build it last, it would "erase" the localized sites built in sub-folders
|
|
67
|
-
const orderedLocales = [
|
|
68
|
-
i18n.defaultLocale,
|
|
69
|
-
...i18n.locales.filter((locale) => locale !== i18n.defaultLocale),
|
|
70
|
-
];
|
|
71
|
-
const results = await (0, utils_2.mapAsyncSequential)(orderedLocales, (locale) => {
|
|
72
|
-
const isLastLocale = orderedLocales.indexOf(locale) === orderedLocales.length - 1;
|
|
73
|
-
return tryToBuildLocale({ locale, isLastLocale });
|
|
74
|
-
});
|
|
75
|
-
return results[0];
|
|
61
|
+
if (i18n.locales.length > 1) {
|
|
62
|
+
logger_1.default.info `Website will be built for all these locales: ${i18n.locales}`;
|
|
76
63
|
}
|
|
64
|
+
// We need the default locale to always be the 1st in the list. If we build it
|
|
65
|
+
// last, it would "erase" the localized sites built in sub-folders
|
|
66
|
+
const orderedLocales = [
|
|
67
|
+
i18n.defaultLocale,
|
|
68
|
+
...i18n.locales.filter((locale) => locale !== i18n.defaultLocale),
|
|
69
|
+
];
|
|
70
|
+
const results = await (0, utils_2.mapAsyncSequential)(orderedLocales, (locale) => {
|
|
71
|
+
const isLastLocale = orderedLocales.indexOf(locale) === orderedLocales.length - 1;
|
|
72
|
+
return tryToBuildLocale({ locale, isLastLocale });
|
|
73
|
+
});
|
|
74
|
+
return results[0];
|
|
77
75
|
}
|
|
78
76
|
exports.default = build;
|
|
79
77
|
async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLastLocale, }) {
|
|
@@ -93,7 +91,8 @@ async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLast
|
|
|
93
91
|
plugins: [
|
|
94
92
|
// Remove/clean build folders before building bundles.
|
|
95
93
|
new CleanWebpackPlugin_1.default({ verbose: false }),
|
|
96
|
-
// Visualize size of webpack output files with an interactive zoomable
|
|
94
|
+
// Visualize size of webpack output files with an interactive zoomable
|
|
95
|
+
// tree map.
|
|
97
96
|
cliOptions.bundleAnalyzer && new webpack_bundle_analyzer_1.BundleAnalyzerPlugin(),
|
|
98
97
|
// Generate client manifests file that will be used for server bundle.
|
|
99
98
|
new react_loadable_ssr_addon_v5_slorber_1.default({
|
|
@@ -153,7 +152,6 @@ async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLast
|
|
|
153
152
|
if (!plugin.postBuild) {
|
|
154
153
|
return;
|
|
155
154
|
}
|
|
156
|
-
// The plugin may reference `this`. We manually bind it again to prevent any bugs.
|
|
157
155
|
await plugin.postBuild({ ...props, content: plugin.content });
|
|
158
156
|
}));
|
|
159
157
|
await (0, brokenLinks_1.handleBrokenLinks)({
|
package/lib/commands/deploy.js
CHANGED
|
@@ -56,7 +56,7 @@ function hasSSHProtocol(sourceRepoUrl) {
|
|
|
56
56
|
}
|
|
57
57
|
catch {
|
|
58
58
|
// Fails when there isn't a protocol
|
|
59
|
-
return /^([\w-]+@)?[\w.-]+:[\w./_-]
|
|
59
|
+
return /^(?:[\w-]+@)?[\w.-]+:[\w./_-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
exports.hasSSHProtocol = hasSSHProtocol;
|
|
@@ -114,8 +114,8 @@ This behavior can have SEO impacts and create relative link issues.
|
|
|
114
114
|
shelljs_1.default.echo('Skipping deploy on a pull request.');
|
|
115
115
|
shelljs_1.default.exit(0);
|
|
116
116
|
}
|
|
117
|
-
// github.io indicates organization repos that deploy via default branch.
|
|
118
|
-
// Organization deploys looks like:
|
|
117
|
+
// github.io indicates organization repos that deploy via default branch.
|
|
118
|
+
// All others use gh-pages. Organization deploys looks like:
|
|
119
119
|
// - Git repo: https://github.com/<organization>/<organization>.github.io
|
|
120
120
|
// - Site url: https://<organization>.github.io
|
|
121
121
|
const isGitHubPagesOrganizationDeploy = projectName.includes('.github.io');
|
|
@@ -196,7 +196,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
|
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
198
|
if (!cliOptions.skipBuild) {
|
|
199
|
-
// Build
|
|
199
|
+
// Build site, then push to deploymentBranch branch of specified repo.
|
|
200
200
|
try {
|
|
201
201
|
await runDeploy(await (0, build_1.default)(siteDir, cliOptions, false));
|
|
202
202
|
}
|
package/lib/commands/external.js
CHANGED
|
@@ -11,7 +11,7 @@ const server_1 = require("../server");
|
|
|
11
11
|
const init_1 = (0, tslib_1.__importDefault)(require("../server/plugins/init"));
|
|
12
12
|
async function externalCommand(cli, siteDir) {
|
|
13
13
|
const context = await (0, server_1.loadContext)(siteDir);
|
|
14
|
-
const pluginConfigs = (0, server_1.loadPluginConfigs)(context);
|
|
14
|
+
const pluginConfigs = await (0, server_1.loadPluginConfigs)(context);
|
|
15
15
|
const plugins = await (0, init_1.default)({ pluginConfigs, context });
|
|
16
16
|
// Plugin Lifecycle - extendCli.
|
|
17
17
|
plugins.forEach((plugin) => {
|
package/lib/commands/serve.js
CHANGED
|
@@ -44,8 +44,8 @@ async function serve(siteDir, cliOptions) {
|
|
|
44
44
|
res.end();
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
// Remove baseUrl before calling serveHandler
|
|
48
|
-
//
|
|
47
|
+
// Remove baseUrl before calling serveHandler, because /baseUrl/ should
|
|
48
|
+
// serve /build/index.html, not /build/baseUrl/index.html (does not exist)
|
|
49
49
|
req.url = (_b = req.url) === null || _b === void 0 ? void 0 : _b.replace(baseUrl, '/');
|
|
50
50
|
(0, serve_handler_1.default)(req, res, {
|
|
51
51
|
cleanUrls: true,
|
package/lib/commands/swizzle.js
CHANGED
|
@@ -45,8 +45,8 @@ function getPluginNames(plugins) {
|
|
|
45
45
|
}
|
|
46
46
|
exports.getPluginNames = getPluginNames;
|
|
47
47
|
const formatComponentName = (componentName) => componentName
|
|
48
|
-
.replace(/
|
|
49
|
-
.replace(/\.(
|
|
48
|
+
.replace(/[\\/]index\.(?:jsx?|tsx?)/, '')
|
|
49
|
+
.replace(/\.(?:jsx?|tsx?)/, '');
|
|
50
50
|
function readComponent(themePath) {
|
|
51
51
|
function walk(dir) {
|
|
52
52
|
let results = [];
|
|
@@ -109,7 +109,7 @@ function colorCode(themePath, plugin) {
|
|
|
109
109
|
async function swizzle(siteDir, themeName, componentName, typescript, danger) {
|
|
110
110
|
var _a, _b, _c, _d, _e;
|
|
111
111
|
const context = await (0, server_1.loadContext)(siteDir);
|
|
112
|
-
const pluginConfigs = (0, server_1.loadPluginConfigs)(context);
|
|
112
|
+
const pluginConfigs = await (0, server_1.loadPluginConfigs)(context);
|
|
113
113
|
const pluginNames = getPluginNames(pluginConfigs);
|
|
114
114
|
const plugins = await (0, init_1.default)({
|
|
115
115
|
pluginConfigs,
|
|
@@ -185,7 +185,8 @@ async function swizzle(siteDir, themeName, componentName, typescript, danger) {
|
|
|
185
185
|
let score = formattedComponentName.length;
|
|
186
186
|
components.forEach((component) => {
|
|
187
187
|
if (component.toLowerCase() === formattedComponentName.toLowerCase()) {
|
|
188
|
-
// may be components with same lowercase key, try to match closest
|
|
188
|
+
// may be components with same lowercase key, try to match closest
|
|
189
|
+
// component
|
|
189
190
|
const currentScore = (0, leven_1.default)(formattedComponentName, component);
|
|
190
191
|
if (currentScore < score) {
|
|
191
192
|
score = currentScore;
|
|
@@ -202,7 +203,8 @@ async function swizzle(siteDir, themeName, componentName, typescript, danger) {
|
|
|
202
203
|
let fromPath = path_1.default.join(themePath, mostSuitableComponent);
|
|
203
204
|
let toPath = path_1.default.resolve(siteDir, utils_1.THEME_PATH, mostSuitableComponent);
|
|
204
205
|
// Handle single TypeScript/JavaScript file only.
|
|
205
|
-
// E.g: if <fromPath> does not exist, we try to swizzle
|
|
206
|
+
// E.g: if <fromPath> does not exist, we try to swizzle
|
|
207
|
+
// <fromPath>.(ts|tsx|js) instead
|
|
206
208
|
if (!fs_extra_1.default.existsSync(fromPath)) {
|
|
207
209
|
if (fs_extra_1.default.existsSync(`${fromPath}.ts`)) {
|
|
208
210
|
[fromPath, toPath] = [`${fromPath}.ts`, `${toPath}.ts`];
|
|
@@ -15,7 +15,7 @@ const init_1 = (0, tslib_1.__importDefault)(require("../server/plugins/init"));
|
|
|
15
15
|
const utils_1 = require("@docusaurus/utils");
|
|
16
16
|
const utils_2 = require("../server/utils");
|
|
17
17
|
function unwrapMarkdownLinks(line) {
|
|
18
|
-
return line.replace(/\[([^\]]+)\]\([^)]+\)/g, (match, p1) => p1);
|
|
18
|
+
return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1);
|
|
19
19
|
}
|
|
20
20
|
function addHeadingId(line, slugger, maintainCase) {
|
|
21
21
|
let headingLevel = 0;
|
|
@@ -48,9 +48,7 @@ function transformMarkdownLine(line, slugger, options) {
|
|
|
48
48
|
if (line.startsWith('##')) {
|
|
49
49
|
return transformMarkdownHeadingLine(line, slugger, options);
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
return line;
|
|
53
|
-
}
|
|
51
|
+
return line;
|
|
54
52
|
}
|
|
55
53
|
function transformMarkdownLines(lines, options) {
|
|
56
54
|
let inCode = false;
|
|
@@ -60,12 +58,10 @@ function transformMarkdownLines(lines, options) {
|
|
|
60
58
|
inCode = !inCode;
|
|
61
59
|
return line;
|
|
62
60
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return line;
|
|
66
|
-
}
|
|
67
|
-
return transformMarkdownLine(line, slugger, options);
|
|
61
|
+
if (inCode) {
|
|
62
|
+
return line;
|
|
68
63
|
}
|
|
64
|
+
return transformMarkdownLine(line, slugger, options);
|
|
69
65
|
});
|
|
70
66
|
}
|
|
71
67
|
function transformMarkdownContent(content, options) {
|
|
@@ -81,12 +77,15 @@ async function transformMarkdownFile(filepath, options) {
|
|
|
81
77
|
}
|
|
82
78
|
return undefined;
|
|
83
79
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
/**
|
|
81
|
+
* We only handle the "paths to watch" because these are the paths where the
|
|
82
|
+
* markdown files are. Also we don't want to transform the site md docs that do
|
|
83
|
+
* not belong to a content plugin. For example ./README.md should not be
|
|
84
|
+
* transformed
|
|
85
|
+
*/
|
|
87
86
|
async function getPathsToWatch(siteDir) {
|
|
88
87
|
const context = await (0, server_1.loadContext)(siteDir);
|
|
89
|
-
const pluginConfigs = (0, server_1.loadPluginConfigs)(context);
|
|
88
|
+
const pluginConfigs = await (0, server_1.loadPluginConfigs)(context);
|
|
90
89
|
const plugins = await (0, init_1.default)({
|
|
91
90
|
pluginConfigs,
|
|
92
91
|
context,
|
|
@@ -13,10 +13,13 @@ const init_1 = (0, tslib_1.__importDefault)(require("../server/plugins/init"));
|
|
|
13
13
|
const translations_1 = require("../server/translations/translations");
|
|
14
14
|
const translationsExtractor_1 = require("../server/translations/translationsExtractor");
|
|
15
15
|
const utils_1 = require("../webpack/utils");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
/**
|
|
17
|
+
* This is a hack, so that @docusaurus/theme-common translations are extracted!
|
|
18
|
+
* A theme doesn't have a way to express that one of its dependency (like
|
|
19
|
+
* @docusaurus/theme-common) also has translations to extract.
|
|
20
|
+
* Instead of introducing a new lifecycle (like `getThemeTranslationPaths()`?)
|
|
21
|
+
* We just make an exception and assume that user is using an official theme
|
|
22
|
+
*/
|
|
20
23
|
async function getExtraSourceCodeFilePaths() {
|
|
21
24
|
try {
|
|
22
25
|
const themeCommonSourceDir = path_1.default.dirname(require.resolve('@docusaurus/theme-common/lib'));
|
|
@@ -50,7 +53,7 @@ async function writeTranslations(siteDir, options) {
|
|
|
50
53
|
customConfigFilePath: options.config,
|
|
51
54
|
locale: options.locale,
|
|
52
55
|
});
|
|
53
|
-
const pluginConfigs = (0, server_1.loadPluginConfigs)(context);
|
|
56
|
+
const pluginConfigs = await (0, server_1.loadPluginConfigs)(context);
|
|
54
57
|
const plugins = await (0, init_1.default)({
|
|
55
58
|
pluginConfigs,
|
|
56
59
|
context,
|
|
@@ -39,10 +39,12 @@ function getPageBrokenLinks({ pagePath, pageLinks, routes, }) {
|
|
|
39
39
|
}
|
|
40
40
|
return pageLinks.map(resolveLink).filter((l) => isBrokenLink(l.resolvedLink));
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
/**
|
|
43
|
+
* The route defs can be recursive, and have a parent match-all route. We don't
|
|
44
|
+
* want to match broken links like /docs/brokenLink against /docs/*. For this
|
|
45
|
+
* reason, we only consider the "final routes", that do not have subroutes.
|
|
46
|
+
* We also need to remove the match all 404 route
|
|
47
|
+
*/
|
|
46
48
|
function filterIntermediateRoutes(routesInput) {
|
|
47
49
|
const routesWithout404 = routesInput.filter((route) => route.path !== '*');
|
|
48
50
|
return (0, utils_2.getAllFinalRoutes)(routesWithout404);
|
|
@@ -67,9 +69,11 @@ function getBrokenLinksErrorMessage(allBrokenLinks) {
|
|
|
67
69
|
.map(brokenLinkMessage)
|
|
68
70
|
.join('\n -> linking to ')}`;
|
|
69
71
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* If there's a broken link appearing very often, it is probably a broken link
|
|
74
|
+
* on the layout. Add an additional message in such case to help user figure
|
|
75
|
+
* this out. See https://github.com/facebook/docusaurus/issues/3567#issuecomment-706973805
|
|
76
|
+
*/
|
|
73
77
|
function getLayoutBrokenLinksHelpMessage() {
|
|
74
78
|
const flatList = Object.entries(allBrokenLinks).flatMap(([pagePage, brokenLinks]) => brokenLinks.map((brokenLink) => ({ pagePage, brokenLink })));
|
|
75
79
|
const countedBrokenLinks = (0, lodash_1.countBy)(flatList, (item) => item.brokenLink.link);
|
|
@@ -121,8 +125,9 @@ async function handleBrokenLinks({ allCollectedLinks, onBrokenLinks, routes, bas
|
|
|
121
125
|
if (onBrokenLinks === 'ignore') {
|
|
122
126
|
return;
|
|
123
127
|
}
|
|
124
|
-
// If we link to a file like /myFile.zip, and the file actually exist for the
|
|
125
|
-
//
|
|
128
|
+
// If we link to a file like /myFile.zip, and the file actually exist for the
|
|
129
|
+
// file system. It is not a broken link, it may simply be a link to an
|
|
130
|
+
// existing static file...
|
|
126
131
|
const allCollectedLinksFiltered = await filterExistingFileLinks({
|
|
127
132
|
allCollectedLinks,
|
|
128
133
|
baseUrl,
|
|
@@ -16,10 +16,8 @@ function getAllDuplicateRoutes(pluginsRouteConfigs) {
|
|
|
16
16
|
if (Object.prototype.hasOwnProperty.call(seenRoutes, route)) {
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
19
|
+
seenRoutes[route] = true;
|
|
20
|
+
return false;
|
|
23
21
|
});
|
|
24
22
|
}
|
|
25
23
|
exports.getAllDuplicateRoutes = getAllDuplicateRoutes;
|
package/lib/server/i18n.js
CHANGED
|
@@ -61,22 +61,18 @@ function localizePath({ pathType, path: originalPath, i18n, options = {}, }) {
|
|
|
61
61
|
? // By default, we don't localize the path of defaultLocale
|
|
62
62
|
i18n.currentLocale !== i18n.defaultLocale
|
|
63
63
|
: options.localizePath;
|
|
64
|
-
if (shouldLocalizePath) {
|
|
65
|
-
// FS paths need special care, for Windows support
|
|
66
|
-
if (pathType === 'fs') {
|
|
67
|
-
return path_1.default.join(originalPath, path_1.default.sep, i18n.currentLocale, path_1.default.sep);
|
|
68
|
-
}
|
|
69
|
-
// Url paths
|
|
70
|
-
else if (pathType === 'url') {
|
|
71
|
-
return (0, utils_1.normalizeUrl)([originalPath, '/', i18n.currentLocale, '/']);
|
|
72
|
-
}
|
|
73
|
-
// should never happen
|
|
74
|
-
else {
|
|
75
|
-
throw new Error(`Unhandled path type "${pathType}".`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
64
|
+
if (!shouldLocalizePath) {
|
|
79
65
|
return originalPath;
|
|
80
66
|
}
|
|
67
|
+
// FS paths need special care, for Windows support
|
|
68
|
+
if (pathType === 'fs') {
|
|
69
|
+
return path_1.default.join(originalPath, path_1.default.sep, i18n.currentLocale, path_1.default.sep);
|
|
70
|
+
}
|
|
71
|
+
// Url paths
|
|
72
|
+
if (pathType === 'url') {
|
|
73
|
+
return (0, utils_1.normalizeUrl)([originalPath, '/', i18n.currentLocale, '/']);
|
|
74
|
+
}
|
|
75
|
+
// should never happen
|
|
76
|
+
throw new Error(`Unhandled path type "${pathType}".`);
|
|
81
77
|
}
|
|
82
78
|
exports.localizePath = localizePath;
|