@docusaurus/core 2.0.0-beta.16 → 2.0.0-beta.19

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.
Files changed (171) hide show
  1. package/bin/beforeCli.mjs +14 -12
  2. package/bin/docusaurus.mjs +41 -93
  3. package/lib/babel/preset.js +2 -2
  4. package/lib/client/.eslintrc.js +2 -3
  5. package/lib/client/App.d.ts +1 -1
  6. package/lib/client/App.js +15 -7
  7. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.d.ts → BaseUrlIssueBanner/index.d.ts} +10 -5
  8. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.js → BaseUrlIssueBanner/index.js} +14 -9
  9. package/lib/client/{baseUrlIssueBanner → BaseUrlIssueBanner}/styles.module.css +0 -0
  10. package/lib/client/ClientLifecyclesDispatcher.d.ts +16 -0
  11. package/lib/client/ClientLifecyclesDispatcher.js +34 -0
  12. package/lib/client/LinksCollector.d.ts +1 -1
  13. package/lib/client/LinksCollector.js +4 -5
  14. package/lib/client/PendingNavigation.d.ts +8 -17
  15. package/lib/client/PendingNavigation.js +39 -70
  16. package/lib/{server/loadSetup.d.ts → client/SiteMetadataDefaults.d.ts} +2 -2
  17. package/lib/client/SiteMetadataDefaults.js +19 -0
  18. package/lib/client/{exports/browserContext.d.ts → browserContext.d.ts} +0 -0
  19. package/lib/client/{exports/browserContext.js → browserContext.js} +0 -0
  20. package/lib/client/clientEntry.js +3 -4
  21. package/lib/client/docusaurus.d.ts +5 -5
  22. package/lib/client/docusaurus.js +26 -33
  23. package/lib/client/{exports/docusaurusContext.d.ts → docusaurusContext.d.ts} +0 -0
  24. package/lib/client/{exports/docusaurusContext.js → docusaurusContext.js} +0 -0
  25. package/lib/client/exports/BrowserOnly.d.ts +3 -4
  26. package/lib/client/exports/BrowserOnly.js +2 -2
  27. package/lib/client/exports/ComponentCreator.js +65 -40
  28. package/lib/client/exports/ErrorBoundary.d.ts +2 -2
  29. package/lib/client/exports/ErrorBoundary.js +4 -5
  30. package/lib/client/exports/Interpolate.d.ts +1 -1
  31. package/lib/client/exports/Interpolate.js +18 -41
  32. package/lib/client/exports/Link.d.ts +3 -15
  33. package/lib/client/exports/Link.js +24 -30
  34. package/lib/client/exports/Translate.d.ts +2 -2
  35. package/lib/client/exports/Translate.js +3 -3
  36. package/lib/client/exports/useBaseUrl.js +8 -9
  37. package/lib/client/exports/useDocusaurusContext.js +1 -1
  38. package/lib/client/exports/useGlobalData.d.ts +4 -3
  39. package/lib/client/exports/useGlobalData.js +5 -5
  40. package/lib/client/exports/useIsBrowser.js +1 -1
  41. package/lib/{server/client-modules/index.d.ts → client/exports/useRouteContext.d.ts} +2 -2
  42. package/lib/client/exports/useRouteContext.js +15 -0
  43. package/lib/client/flat.d.ts +12 -2
  44. package/lib/client/flat.js +12 -5
  45. package/lib/client/normalizeLocation.js +13 -8
  46. package/lib/client/prefetch.js +10 -28
  47. package/lib/client/preload.d.ts +1 -3
  48. package/lib/client/preload.js +5 -11
  49. package/lib/client/routeContext.d.ts +13 -0
  50. package/lib/client/routeContext.js +31 -0
  51. package/lib/client/serverEntry.js +19 -18
  52. package/lib/client/theme-fallback/Error/index.js +7 -1
  53. package/lib/client/theme-fallback/Layout/index.d.ts +1 -1
  54. package/lib/client/theme-fallback/Layout/index.js +2 -17
  55. package/lib/client/theme-fallback/Loading/index.js +2 -0
  56. package/lib/client/theme-fallback/NotFound/index.js +13 -5
  57. package/lib/client/theme-fallback/Root/index.d.ts +4 -4
  58. package/lib/client/theme-fallback/Root/index.js +2 -1
  59. package/lib/{server/html-tags/htmlTags.d.ts → client/theme-fallback/SiteMetadata/index.d.ts} +2 -1
  60. package/lib/client/theme-fallback/SiteMetadata/index.js +10 -0
  61. package/lib/commands/build.d.ts +6 -2
  62. package/lib/commands/build.js +48 -30
  63. package/lib/commands/clear.d.ts +1 -1
  64. package/lib/commands/clear.js +6 -5
  65. package/lib/commands/deploy.d.ts +5 -5
  66. package/lib/commands/deploy.js +21 -45
  67. package/lib/commands/external.d.ts +1 -1
  68. package/lib/commands/external.js +6 -11
  69. package/lib/commands/serve.d.ts +7 -2
  70. package/lib/commands/serve.js +18 -19
  71. package/lib/commands/start.d.ts +8 -2
  72. package/lib/commands/start.js +33 -30
  73. package/lib/commands/swizzle/actions.d.ts +2 -2
  74. package/lib/commands/swizzle/actions.js +10 -10
  75. package/lib/commands/swizzle/common.d.ts +3 -3
  76. package/lib/commands/swizzle/common.js +8 -9
  77. package/lib/commands/swizzle/components.js +48 -13
  78. package/lib/commands/swizzle/config.js +21 -15
  79. package/lib/commands/swizzle/context.js +6 -12
  80. package/lib/commands/swizzle/index.d.ts +2 -2
  81. package/lib/commands/swizzle/index.js +5 -4
  82. package/lib/commands/swizzle/prompts.js +2 -2
  83. package/lib/commands/swizzle/tables.js +10 -13
  84. package/lib/commands/swizzle/themes.js +9 -8
  85. package/lib/commands/writeHeadingIds.d.ts +2 -9
  86. package/lib/commands/writeHeadingIds.js +11 -69
  87. package/lib/commands/writeTranslations.d.ts +3 -4
  88. package/lib/commands/writeTranslations.js +10 -14
  89. package/lib/index.d.ts +9 -10
  90. package/lib/index.js +18 -19
  91. package/lib/server/brokenLinks.d.ts +3 -16
  92. package/lib/server/brokenLinks.js +37 -31
  93. package/lib/server/clientModules.d.ts +12 -0
  94. package/lib/server/clientModules.js +20 -0
  95. package/lib/server/config.d.ts +5 -2
  96. package/lib/server/config.js +14 -9
  97. package/lib/server/configValidation.d.ts +1 -1
  98. package/lib/server/configValidation.js +39 -13
  99. package/lib/server/getHostPort.d.ts +14 -0
  100. package/lib/{choosePort.js → server/getHostPort.js} +24 -41
  101. package/lib/server/htmlTags.d.ts +12 -0
  102. package/lib/server/htmlTags.js +62 -0
  103. package/lib/server/i18n.d.ts +2 -11
  104. package/lib/server/i18n.js +7 -28
  105. package/lib/server/index.d.ts +28 -13
  106. package/lib/server/index.js +62 -229
  107. package/lib/server/plugins/configs.d.ts +51 -0
  108. package/lib/server/plugins/configs.js +101 -0
  109. package/lib/server/plugins/index.d.ts +9 -8
  110. package/lib/server/plugins/index.js +65 -132
  111. package/lib/server/plugins/init.d.ts +6 -15
  112. package/lib/server/plugins/init.js +25 -83
  113. package/lib/server/{moduleShorthand.d.ts → plugins/moduleShorthand.d.ts} +0 -0
  114. package/lib/server/{moduleShorthand.js → plugins/moduleShorthand.js} +0 -0
  115. package/lib/server/plugins/pluginIds.d.ts +4 -0
  116. package/lib/server/plugins/pluginIds.js +6 -4
  117. package/lib/server/plugins/presets.d.ts +12 -0
  118. package/lib/server/{presets/index.js → plugins/presets.js} +21 -20
  119. package/lib/server/plugins/{applyRouteTrailingSlash.d.ts → routeConfig.d.ts} +3 -1
  120. package/lib/server/plugins/routeConfig.js +54 -0
  121. package/lib/server/plugins/synthetic.d.ts +20 -0
  122. package/lib/server/plugins/synthetic.js +112 -0
  123. package/lib/server/routes.d.ts +39 -7
  124. package/lib/server/routes.js +169 -102
  125. package/lib/server/siteMetadata.d.ts +12 -0
  126. package/lib/server/siteMetadata.js +81 -0
  127. package/lib/server/translations/translations.d.ts +5 -14
  128. package/lib/server/translations/translations.js +23 -39
  129. package/lib/server/translations/translationsExtractor.d.ts +2 -2
  130. package/lib/server/translations/translationsExtractor.js +16 -19
  131. package/lib/server/utils.js +1 -1
  132. package/lib/webpack/aliases/index.d.ts +34 -0
  133. package/lib/webpack/aliases/index.js +106 -0
  134. package/lib/webpack/base.d.ts +0 -1
  135. package/lib/webpack/base.js +12 -30
  136. package/lib/webpack/client.js +7 -8
  137. package/lib/webpack/plugins/ChunkAssetPlugin.js +7 -7
  138. package/lib/webpack/plugins/CleanWebpackPlugin.d.ts +2 -2
  139. package/lib/webpack/plugins/CleanWebpackPlugin.js +2 -2
  140. package/lib/webpack/plugins/LogPlugin.js +2 -2
  141. package/lib/webpack/plugins/WaitPlugin.d.ts +2 -2
  142. package/lib/webpack/plugins/WaitPlugin.js +3 -3
  143. package/lib/webpack/server.d.ts +2 -2
  144. package/lib/webpack/server.js +10 -8
  145. package/lib/webpack/utils.d.ts +9 -3
  146. package/lib/webpack/utils.js +20 -25
  147. package/package.json +38 -41
  148. package/lib/choosePort.d.ts +0 -11
  149. package/lib/client/client-lifecycles-dispatcher.d.ts +0 -9
  150. package/lib/client/client-lifecycles-dispatcher.js +0 -23
  151. package/lib/client/nprogress.css +0 -36
  152. package/lib/commands/commandUtils.d.ts +0 -9
  153. package/lib/commands/commandUtils.js +0 -21
  154. package/lib/server/client-modules/index.js +0 -12
  155. package/lib/server/duplicateRoutes.d.ts +0 -10
  156. package/lib/server/duplicateRoutes.js +0 -42
  157. package/lib/server/html-tags/htmlTags.js +0 -38
  158. package/lib/server/html-tags/index.d.ts +0 -9
  159. package/lib/server/html-tags/index.js +0 -43
  160. package/lib/server/loadSetup.js +0 -25
  161. package/lib/server/plugins/applyRouteTrailingSlash.js +0 -19
  162. package/lib/server/presets/index.d.ts +0 -11
  163. package/lib/server/themes/alias.d.ts +0 -9
  164. package/lib/server/themes/alias.js +0 -48
  165. package/lib/server/themes/index.d.ts +0 -12
  166. package/lib/server/themes/index.js +0 -47
  167. package/lib/server/versions/__fixtures__/dummy-plugin.d.ts +0 -0
  168. package/lib/server/versions/__fixtures__/dummy-plugin.js +0 -0
  169. package/lib/server/versions/__fixtures__/package.json +0 -3
  170. package/lib/server/versions/index.d.ts +0 -9
  171. package/lib/server/versions/index.js +0 -51
@@ -5,19 +5,21 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import { Route, withRouter } from 'react-router-dom';
9
- import nprogress from 'nprogress';
10
- import clientLifecyclesDispatcher from './client-lifecycles-dispatcher';
8
+ import { Route } from 'react-router-dom';
9
+ import ClientLifecyclesDispatcher, { dispatchLifecycleAction, } from './ClientLifecyclesDispatcher';
10
+ import ExecutionEnvironment from './exports/ExecutionEnvironment';
11
11
  import preload from './preload';
12
- import normalizeLocation from './normalizeLocation';
13
- import './nprogress.css';
14
- nprogress.configure({ showSpinner: false });
15
12
  class PendingNavigation extends React.Component {
16
13
  constructor(props) {
17
14
  super(props);
18
15
  // previousLocation doesn't affect rendering, hence not stored in state.
19
16
  this.previousLocation = null;
20
- this.progressBarTimeout = null;
17
+ this.routeUpdateCleanupCb = ExecutionEnvironment.canUseDOM
18
+ ? dispatchLifecycleAction('onRouteUpdate', {
19
+ previousLocation: null,
20
+ location: this.props.location,
21
+ })
22
+ : () => { };
21
23
  this.state = {
22
24
  nextRouteHasLoaded: true,
23
25
  };
@@ -25,72 +27,39 @@ class PendingNavigation extends React.Component {
25
27
  // Intercept location update and still show current route until next route
26
28
  // is done loading.
27
29
  shouldComponentUpdate(nextProps, nextState) {
28
- const routeDidChange = nextProps.location !== this.props.location;
29
- const { routes, delay } = this.props;
30
- // If `routeDidChange` is true, means the router is trying to navigate to a
31
- // new route. We will preload the new route.
32
- if (routeDidChange) {
33
- const nextLocation = normalizeLocation(nextProps.location);
34
- this.startProgressBar(delay);
35
- // Save the location first.
36
- this.previousLocation = normalizeLocation(this.props.location);
37
- this.setState({
38
- nextRouteHasLoaded: false,
39
- });
40
- // Load data while the old screen remains.
41
- preload(routes, nextLocation.pathname)
42
- .then(() => {
43
- clientLifecyclesDispatcher.onRouteUpdate({
44
- previousLocation: this.previousLocation,
45
- location: nextLocation,
46
- });
47
- // Route has loaded, we can reset previousLocation.
48
- this.previousLocation = null;
49
- this.setState({ nextRouteHasLoaded: true }, this.stopProgressBar);
50
- const { hash } = nextLocation;
51
- if (!hash) {
52
- window.scrollTo(0, 0);
53
- }
54
- else {
55
- const id = decodeURIComponent(hash.substring(1));
56
- const element = document.getElementById(id);
57
- if (element) {
58
- element.scrollIntoView();
59
- }
60
- }
61
- })
62
- .catch((e) => console.warn(e));
63
- return false;
30
+ if (nextProps.location === this.props.location) {
31
+ // `nextRouteHasLoaded` is false means there's a pending route transition.
32
+ // Don't update until it's done.
33
+ return nextState.nextRouteHasLoaded;
64
34
  }
65
- // There's a pending route transition. Don't update until it's done.
66
- if (!nextState.nextRouteHasLoaded) {
67
- return false;
68
- }
69
- // Route has loaded, we can update now.
70
- return true;
71
- }
72
- clearProgressBarTimeout() {
73
- if (this.progressBarTimeout) {
74
- clearTimeout(this.progressBarTimeout);
75
- this.progressBarTimeout = null;
76
- }
77
- }
78
- startProgressBar(delay) {
79
- this.clearProgressBarTimeout();
80
- this.progressBarTimeout = setTimeout(() => {
81
- clientLifecyclesDispatcher.onRouteUpdateDelayed({
82
- location: normalizeLocation(this.props.location),
83
- });
84
- nprogress.start();
85
- }, delay);
86
- }
87
- stopProgressBar() {
88
- this.clearProgressBarTimeout();
89
- nprogress.done();
35
+ // props.location being different means the router is trying to navigate to
36
+ // a new route. We will preload the new route.
37
+ const nextLocation = nextProps.location;
38
+ // Save the location first.
39
+ this.previousLocation = this.props.location;
40
+ this.setState({ nextRouteHasLoaded: false });
41
+ this.routeUpdateCleanupCb = dispatchLifecycleAction('onRouteUpdate', {
42
+ previousLocation: this.previousLocation,
43
+ location: nextLocation,
44
+ });
45
+ // Load data while the old screen remains. Force preload instead of using
46
+ // `window.docusaurus`, because we want to avoid loading screen even when
47
+ // user is on saveData
48
+ preload(nextLocation.pathname)
49
+ .then(() => {
50
+ this.routeUpdateCleanupCb?.();
51
+ this.setState({ nextRouteHasLoaded: true });
52
+ })
53
+ .catch((e) => console.warn(e));
54
+ return false;
90
55
  }
91
56
  render() {
92
57
  const { children, location } = this.props;
93
- return (<Route location={normalizeLocation(location)} render={() => children}/>);
58
+ // Use a controlled <Route> to trick all descendants into rendering the old
59
+ // location.
60
+ return (<ClientLifecyclesDispatcher previousLocation={this.previousLocation} location={location}>
61
+ <Route location={location} render={() => children}/>
62
+ </ClientLifecyclesDispatcher>);
94
63
  }
95
64
  }
96
- export default withRouter(PendingNavigation);
65
+ export default PendingNavigation;
@@ -4,5 +4,5 @@
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 } from '@docusaurus/types';
8
- export default function loadSetup(name: string): Promise<Props>;
7
+ /// <reference types="react" />
8
+ export default function SiteMetadataDefaults(): JSX.Element;
@@ -0,0 +1,19 @@
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 React from 'react';
8
+ import Head from '@docusaurus/Head';
9
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
10
+ import useBaseUrl from '@docusaurus/useBaseUrl';
11
+ export default function SiteMetadataDefaults() {
12
+ const { siteConfig: { favicon, tagline, title }, i18n: { currentLocale, localeConfigs }, } = useDocusaurusContext();
13
+ const faviconUrl = useBaseUrl(favicon);
14
+ const { htmlLang, direction: htmlDir } = localeConfigs[currentLocale];
15
+ return (<Head defaultTitle={`${title}${tagline ? ` · ${tagline}` : ''}`}>
16
+ <html lang={htmlLang} dir={htmlDir}/>
17
+ {favicon && <link rel="icon" href={faviconUrl}/>}
18
+ </Head>);
19
+ }
@@ -5,10 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import { hydrate, render } from 'react-dom';
8
+ import ReactDOM from 'react-dom';
9
9
  import { BrowserRouter } from 'react-router-dom';
10
10
  import { HelmetProvider } from 'react-helmet-async';
11
- import routes from '@generated/routes';
12
11
  import ExecutionEnvironment from './exports/ExecutionEnvironment';
13
12
  import App from './App';
14
13
  import preload from './preload';
@@ -21,8 +20,8 @@ if (ExecutionEnvironment.canUseDOM) {
21
20
  // first-load experience.
22
21
  // For development, there is no existing markup so we had to render it.
23
22
  // We also preload async component to avoid first-load loading screen.
24
- const renderMethod = process.env.NODE_ENV === 'production' ? hydrate : render;
25
- preload(routes, window.location.pathname).then(() => {
23
+ const renderMethod = process.env.NODE_ENV === 'production' ? ReactDOM.hydrate : ReactDOM.render;
24
+ preload(window.location.pathname).then(() => {
26
25
  renderMethod(<HelmetProvider>
27
26
  <BrowserRouter>
28
27
  <App />
@@ -15,8 +15,8 @@ declare global {
15
15
  };
16
16
  }
17
17
  }
18
- declare const docusaurus: {
19
- prefetch: (routePath: string) => boolean;
20
- preload: (routePath: string) => boolean;
21
- };
22
- export default docusaurus;
18
+ declare const _default: Readonly<{
19
+ prefetch(routePath: string): false | Promise<void[]>;
20
+ preload(routePath: string): false | Promise<void[]>;
21
+ }>;
22
+ export default _default;
@@ -10,58 +10,51 @@ import routes from '@generated/routes';
10
10
  import prefetchHelper from './prefetch';
11
11
  import preloadHelper from './preload';
12
12
  import flat from './flat';
13
- const fetched = {};
14
- const loaded = {};
13
+ const fetched = new Set();
14
+ const loaded = new Set();
15
15
  // If user is on slow or constrained connection.
16
- const isSlowConnection = () => {
17
- var _a, _b;
18
- return ((_a = navigator.connection) === null || _a === void 0 ? void 0 : _a.effectiveType.includes('2g')) &&
19
- ((_b = navigator.connection) === null || _b === void 0 ? void 0 : _b.saveData);
20
- };
21
- const canPrefetch = (routePath) => !isSlowConnection() && !loaded[routePath] && !fetched[routePath];
22
- const canPreload = (routePath) => !isSlowConnection() && !loaded[routePath];
16
+ const isSlowConnection = () => navigator.connection?.effectiveType.includes('2g') ||
17
+ navigator.connection?.saveData;
18
+ const canPrefetch = (routePath) => !isSlowConnection() && !loaded.has(routePath) && !fetched.has(routePath);
19
+ const canPreload = (routePath) => !isSlowConnection() && !loaded.has(routePath);
20
+ const getChunkNamesToLoad = (path) => Object.entries(routesChunkNames)
21
+ .filter(
23
22
  // Remove the last part containing the route hash
24
23
  // input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
25
24
  // output: /blog/2018/12/14/Happy-First-Birthday-Slash
26
- const removeRouteNameHash = (str) => str.replace(/-[^-]+$/, '');
27
- const getChunkNamesToLoad = (path) => Object.entries(routesChunkNames)
28
- .filter(([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path)
29
- .flatMap(([, routeChunks]) =>
30
- // flat() is useful for nested chunk names, it's not like array.flat()
31
- Object.values(flat(routeChunks)));
25
+ ([routeNameWithHash]) => routeNameWithHash.replace(/-[^-]+$/, '') === path)
26
+ .flatMap(([, routeChunks]) => Object.values(flat(routeChunks)));
32
27
  const docusaurus = {
33
- prefetch: (routePath) => {
28
+ prefetch(routePath) {
34
29
  if (!canPrefetch(routePath)) {
35
30
  return false;
36
31
  }
37
- // Prevent future duplicate prefetch of routePath.
38
- fetched[routePath] = true;
32
+ fetched.add(routePath);
39
33
  // Find all webpack chunk names needed.
40
34
  const matches = matchRoutes(routes, routePath);
41
35
  const chunkNamesNeeded = matches.flatMap((match) => getChunkNamesToLoad(match.route.path));
42
36
  // Prefetch all webpack chunk assets file needed.
43
- chunkNamesNeeded.forEach((chunkName) => {
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.
37
+ return Promise.all(chunkNamesNeeded.map((chunkName) => {
38
+ // "__webpack_require__.gca" is injected by ChunkAssetPlugin. Pass it
39
+ // the name of the chunk you want to load and it will return its URL.
47
40
  // eslint-disable-next-line camelcase
48
41
  const chunkAsset = __webpack_require__.gca(chunkName);
49
- // In some cases, webpack might decide to optimize further & hence the
50
- // chunk assets are merged to another chunk/previous chunk.
51
- // Hence, we can safely filter it out/don't need to load it.
42
+ // In some cases, webpack might decide to optimize further, leading to
43
+ // the chunk assets being merged to another chunk. In this case, we can
44
+ // safely filter it out and don't need to load it.
52
45
  if (chunkAsset && !/undefined/.test(chunkAsset)) {
53
- prefetchHelper(chunkAsset);
46
+ return prefetchHelper(chunkAsset);
54
47
  }
55
- });
56
- return true;
48
+ return Promise.resolve();
49
+ }));
57
50
  },
58
- preload: (routePath) => {
51
+ preload(routePath) {
59
52
  if (!canPreload(routePath)) {
60
53
  return false;
61
54
  }
62
- loaded[routePath] = true;
63
- preloadHelper(routes, routePath);
64
- return true;
55
+ loaded.add(routePath);
56
+ return preloadHelper(routePath);
65
57
  },
66
58
  };
67
- export default docusaurus;
59
+ // This object is directly mounted onto window, better freeze it
60
+ export default Object.freeze(docusaurus);
@@ -4,8 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
+ /// <reference types="@docusaurus/module-type-aliases" />
7
8
  /// <reference types="react" />
8
- export default function BrowserOnly({ children, fallback, }: {
9
- children: () => JSX.Element;
10
- fallback?: JSX.Element;
11
- }): JSX.Element | null;
9
+ import type { Props } from '@docusaurus/BrowserOnly';
10
+ export default function BrowserOnly({ children, fallback, }: Props): JSX.Element | null;
@@ -16,7 +16,7 @@ export default function BrowserOnly({ children, fallback, }) {
16
16
  throw new Error(`Docusaurus error: The children of <BrowserOnly> must be a "render function", e.g. <BrowserOnly>{() => <span>{window.location.href}</span>}</BrowserOnly>.
17
17
  Current type: ${isValidElement(children) ? 'React element' : typeof children}`);
18
18
  }
19
- return <>{children()}</>;
19
+ return <>{children?.()}</>;
20
20
  }
21
- return fallback || null;
21
+ return fallback ?? null;
22
22
  }
@@ -10,69 +10,94 @@ import Loading from '@theme/Loading';
10
10
  import routesChunkNames from '@generated/routesChunkNames';
11
11
  import registry from '@generated/registry';
12
12
  import flat from '../flat';
13
+ import { RouteContextProvider } from '../routeContext';
13
14
  export default function ComponentCreator(path, hash) {
14
15
  // 404 page
15
16
  if (path === '*') {
16
17
  return Loadable({
17
18
  loading: Loading,
18
- loader: () => import('@theme/NotFound'),
19
+ loader: () => import('@theme/NotFound').then(({ default: NotFound }) => (props) => (<RouteContextProvider
20
+ // Do we want a better name than native-default?
21
+ value={{ plugin: { name: 'native', id: 'default' } }}>
22
+ <NotFound {...props}/>
23
+ </RouteContextProvider>)),
19
24
  });
20
25
  }
21
- const chunkNamesKey = `${path}-${hash}`;
22
- const chunkNames = routesChunkNames[chunkNamesKey];
23
- const optsModules = [];
26
+ const chunkNames = routesChunkNames[`${path}-${hash}`];
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ const loader = {};
29
+ const modules = [];
24
30
  const optsWebpack = [];
25
- const optsLoader = {};
26
- /* Prepare opts data that react-loadable needs
27
- https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded
28
- Example:
29
- - optsLoader:
30
- {
31
- component: () => import('./Pages.js'),
32
- content.foo: () => import('./doc1.md'),
33
- }
34
- - optsModules: ['./Pages.js', './doc1.md']
35
- - optsWebpack: [
36
- require.resolveWeak('./Pages.js'),
37
- require.resolveWeak('./doc1.md'),
38
- ]
39
- */
31
+ // A map from prop names to chunk names.
32
+ // e.g. Suppose the plugin added this as route:
33
+ // { __comp: "...", prop: { foo: "..." }, items: ["...", "..."] }
34
+ // It will become:
35
+ // { __comp: "...", "prop.foo": "...", "items.0": "...", "items.1": ... }
36
+ // Loadable.Map will _map_ over `loader` and load each key.
40
37
  const flatChunkNames = flat(chunkNames);
41
- Object.keys(flatChunkNames).forEach((key) => {
42
- const chunkRegistry = registry[flatChunkNames[key]];
38
+ Object.entries(flatChunkNames).forEach(([keyPath, chunkName]) => {
39
+ const chunkRegistry = registry[chunkName];
43
40
  if (chunkRegistry) {
44
41
  // eslint-disable-next-line prefer-destructuring
45
- optsLoader[key] = chunkRegistry[0];
46
- optsModules.push(chunkRegistry[1]);
42
+ loader[keyPath] = chunkRegistry[0];
43
+ modules.push(chunkRegistry[1]);
47
44
  optsWebpack.push(chunkRegistry[2]);
48
45
  }
49
46
  });
50
47
  return Loadable.Map({
51
48
  loading: Loading,
52
- loader: optsLoader,
53
- modules: optsModules,
49
+ loader,
50
+ modules,
54
51
  webpack: () => optsWebpack,
55
52
  render: (loaded, props) => {
56
- // Clone the original object since we don't want to alter the original.
53
+ // `loaded` will be a map from key path (as returned from the flattened
54
+ // chunk names) to the modules loaded from the loaders. We now have to
55
+ // restore the chunk names' previous shape from this flat record.
56
+ // We do so by taking advantage of the existing `chunkNames` and replacing
57
+ // each chunk name with its loaded module, so we don't create another
58
+ // object from scratch.
57
59
  const loadedModules = JSON.parse(JSON.stringify(chunkNames));
58
- Object.keys(loaded).forEach((key) => {
59
- let val = loadedModules;
60
- const keyPath = key.split('.');
61
- for (let i = 0; i < keyPath.length - 1; i += 1) {
62
- val = val[keyPath[i]];
60
+ Object.entries(loaded).forEach(([keyPath, loadedModule]) => {
61
+ // JSON modules are also loaded as `{ default: ... }` (`import()`
62
+ // semantics) but we just want to pass the actual value to props.
63
+ const chunk = loadedModule.default;
64
+ // One loaded chunk can only be one of two things: a module (props) or a
65
+ // component. Modules are always JSON, so `default` always exists. This
66
+ // could only happen with a user-defined component.
67
+ if (!chunk) {
68
+ throw new Error(`The page component at ${path} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);
63
69
  }
64
- val[keyPath[keyPath.length - 1]] = loaded[key].default;
65
- const nonDefaultKeys = Object.keys(loaded[key]).filter((k) => k !== 'default');
66
- if (nonDefaultKeys && nonDefaultKeys.length) {
67
- nonDefaultKeys.forEach((nonDefaultKey) => {
68
- val[keyPath[keyPath.length - 1]][nonDefaultKey] =
69
- loaded[key][nonDefaultKey];
70
+ // A module can be a primitive, for example, if the user stored a string
71
+ // as a prop. However, there seems to be a bug with swc-loader's CJS
72
+ // logic, in that it would load a JSON module with content "foo" as
73
+ // `{ default: "foo", 0: "f", 1: "o", 2: "o" }`. Just to be safe, we
74
+ // first make sure that the chunk is non-primitive.
75
+ if (typeof chunk === 'object' || typeof chunk === 'function') {
76
+ Object.keys(loadedModule)
77
+ .filter((k) => k !== 'default')
78
+ .forEach((nonDefaultKey) => {
79
+ chunk[nonDefaultKey] = loadedModule[nonDefaultKey];
70
80
  });
71
81
  }
82
+ // We now have this chunk prepared. Go down the key path and replace the
83
+ // chunk name with the actual chunk.
84
+ let val = loadedModules;
85
+ const keyPaths = keyPath.split('.');
86
+ keyPaths.slice(0, -1).forEach((k) => {
87
+ val = val[k];
88
+ });
89
+ val[keyPaths[keyPaths.length - 1]] = chunk;
72
90
  });
73
- const Component = loadedModules.component;
74
- delete loadedModules.component;
75
- return <Component {...loadedModules} {...props}/>;
91
+ /* eslint-disable no-underscore-dangle */
92
+ const Component = loadedModules.__comp;
93
+ delete loadedModules.__comp;
94
+ const routeContext = loadedModules.__context;
95
+ delete loadedModules.__context;
96
+ /* eslint-enable no-underscore-dangle */
97
+ // Is there any way to put this RouteContextProvider upper in the tree?
98
+ return (<RouteContextProvider value={routeContext}>
99
+ <Component {...loadedModules} {...props}/>
100
+ </RouteContextProvider>);
76
101
  },
77
102
  });
78
103
  }
@@ -7,9 +7,9 @@
7
7
  /// <reference types="@docusaurus/module-type-aliases" />
8
8
  import React, { type ReactNode } from 'react';
9
9
  import type { Props } from '@docusaurus/ErrorBoundary';
10
- interface State {
10
+ declare type State = {
11
11
  error: Error | null;
12
- }
12
+ };
13
13
  export default class ErrorBoundary extends React.Component<Props, State> {
14
14
  constructor(props: Props);
15
15
  componentDidCatch(error: Error): void;
@@ -19,18 +19,17 @@ export default class ErrorBoundary extends React.Component {
19
19
  }
20
20
  }
21
21
  render() {
22
- var _a;
23
22
  const { children } = this.props;
24
23
  const { error } = this.state;
25
24
  if (error) {
26
- const fallback = (_a = this.props.fallback) !== null && _a !== void 0 ? _a : DefaultFallback;
25
+ const fallback = this.props.fallback ?? DefaultFallback;
27
26
  return fallback({
28
27
  error,
29
28
  tryAgain: () => this.setState({ error: null }),
30
29
  });
31
30
  }
32
- return (children !== null && children !== void 0 ? children :
33
- // See https://github.com/facebook/docusaurus/issues/6337#issuecomment-1012913647
34
- null);
31
+ return (children ??
32
+ // See https://github.com/facebook/docusaurus/issues/6337#issuecomment-1012913647
33
+ null);
35
34
  }
36
35
  }
@@ -9,4 +9,4 @@ import { type ReactNode } from 'react';
9
9
  import type { InterpolateProps, InterpolateValues } from '@docusaurus/Interpolate';
10
10
  export declare function interpolate<Str extends string>(text: Str, values?: InterpolateValues<Str, string | number>): string;
11
11
  export declare function interpolate<Str extends string, Value extends ReactNode>(text: Str, values?: InterpolateValues<Str, Value>): ReactNode;
12
- export default function Interpolate<Str extends string>({ children, values, }: InterpolateProps<Str>): ReactNode;
12
+ export default function Interpolate<Str extends string>({ children, values, }: InterpolateProps<Str>): JSX.Element;
@@ -4,53 +4,30 @@
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 React from 'react';
8
- /*
9
- Minimal implementation of a React interpolate component.
10
- We don't ship a markdown parser nor a feature-complete i18n library on purpose.
11
- More details here: https://github.com/facebook/docusaurus/pull/4295
12
- */
13
- const ValueRegexp = /{\w+}/g;
14
- const ValueFoundMarker = '{}'; // does not care much
7
+ import React, { isValidElement } from 'react';
15
8
  export function interpolate(text, values) {
16
- const elements = [];
17
- const processedText = text.replace(ValueRegexp, (match) => {
18
- // remove {{ and }} around the placeholder
19
- const key = match.substring(1, match.length - 1);
20
- const value = values === null || values === void 0 ? void 0 : values[key];
21
- if (typeof value !== 'undefined') {
22
- const element = React.isValidElement(value)
23
- ? value
24
- : // For non-React elements: basic primitive->string conversion
25
- String(value);
26
- elements.push(element);
27
- return ValueFoundMarker;
9
+ // eslint-disable-next-line prefer-named-capture-group
10
+ const segments = text.split(/(\{\w+\})/).map((seg, index) => {
11
+ // Odd indices (1, 3, 5...) of the segments are (potentially) interpolatable
12
+ if (index % 2 === 1) {
13
+ const value = values?.[seg.slice(1, -1)];
14
+ if (value !== undefined) {
15
+ return value;
16
+ }
17
+ // No match: add warning? There's no way to "escape" interpolation though
28
18
  }
29
- return match; // no match? add warning?
19
+ return seg;
30
20
  });
31
- // No interpolation to be done: just return the text
32
- if (elements.length === 0) {
33
- return text;
21
+ if (segments.some((seg) => isValidElement(seg))) {
22
+ return segments
23
+ .map((seg, index) => isValidElement(seg) ? React.cloneElement(seg, { key: index }) : seg)
24
+ .filter((seg) => seg !== '');
34
25
  }
35
- // Basic string interpolation: returns interpolated string
36
- if (elements.every((el) => typeof el === 'string')) {
37
- return processedText
38
- .split(ValueFoundMarker)
39
- .reduce((str, value, index) => { var _a; return str.concat(value).concat((_a = elements[index]) !== null && _a !== void 0 ? _a : ''); }, '');
40
- }
41
- // JSX interpolation: returns ReactNode
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
- ], []);
26
+ return segments.join('');
49
27
  }
50
28
  export default function Interpolate({ children, values, }) {
51
29
  if (typeof children !== 'string') {
52
- console.warn('Illegal <Interpolate> children', children);
53
- throw new Error('The Docusaurus <Interpolate> component only accept simple string values');
30
+ throw new Error(`The Docusaurus <Interpolate> component only accept simple string values. Received: ${isValidElement(children) ? 'React element' : typeof children}`);
54
31
  }
55
- return interpolate(children, values);
32
+ return <>{interpolate(children, values)}</>;
56
33
  }