@docusaurus/core 2.0.0-beta.12faed89d → 2.0.0-beta.14

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 (111) hide show
  1. package/bin/beforeCli.js +46 -22
  2. package/bin/docusaurus.js +42 -44
  3. package/lib/babel/preset.d.ts +6 -0
  4. package/lib/babel/preset.js +3 -3
  5. package/lib/choosePort.js +19 -20
  6. package/lib/client/.eslintrc.js +0 -1
  7. package/lib/client/App.js +12 -22
  8. package/lib/client/LinksCollector.d.ts +2 -2
  9. package/lib/client/LinksCollector.js +4 -8
  10. package/lib/client/PendingNavigation.d.ts +24 -1
  11. package/lib/client/PendingNavigation.js +1 -1
  12. package/lib/client/baseUrlIssueBanner/BaseUrlIssueBanner.d.ts +5 -0
  13. package/lib/client/client-lifecycles-dispatcher.d.ts +2 -2
  14. package/lib/client/client-lifecycles-dispatcher.js +0 -2
  15. package/lib/client/docusaurus.d.ts +6 -0
  16. package/lib/client/docusaurus.js +11 -19
  17. package/lib/client/exports/BrowserOnly.js +5 -3
  18. package/lib/client/exports/ErrorBoundary.d.ts +18 -0
  19. package/lib/client/exports/ErrorBoundary.js +35 -0
  20. package/lib/client/exports/Interpolate.js +12 -15
  21. package/lib/client/exports/Link.js +9 -9
  22. package/lib/client/exports/Translate.d.ts +2 -2
  23. package/lib/client/exports/Translate.js +13 -9
  24. package/lib/client/exports/browserContext.d.ts +11 -0
  25. package/lib/client/exports/browserContext.js +21 -0
  26. package/lib/client/exports/constants.js +1 -11
  27. package/lib/client/exports/{context.d.ts → docusaurusContext.d.ts} +5 -3
  28. package/lib/client/exports/docusaurusContext.js +25 -0
  29. package/lib/client/exports/useBaseUrl.js +2 -4
  30. package/lib/client/exports/useDocusaurusContext.js +2 -7
  31. package/lib/client/exports/useGlobalData.js +1 -5
  32. package/lib/client/exports/{context.js → useIsBrowser.d.ts} +1 -2
  33. package/lib/{webpack/sharedModuleAliases.d.ts → client/exports/useIsBrowser.js} +5 -4
  34. package/lib/client/flat.d.ts +2 -1
  35. package/lib/client/flat.js +7 -9
  36. package/lib/client/normalizeLocation.d.ts +1 -3
  37. package/lib/client/prefetch.js +0 -1
  38. package/lib/client/serverEntry.js +20 -42
  39. package/lib/client/theme-fallback/Error/index.js +47 -0
  40. package/lib/client/theme-fallback/Layout/index.js +1 -1
  41. package/lib/client/theme-fallback/Loading/index.js +2 -2
  42. package/lib/client/theme-fallback/Root/index.js +1 -3
  43. package/lib/commands/build.js +39 -44
  44. package/lib/commands/clear.d.ts +6 -0
  45. package/lib/commands/clear.js +17 -18
  46. package/lib/commands/commandUtils.d.ts +6 -0
  47. package/lib/commands/commandUtils.js +7 -7
  48. package/lib/commands/deploy.d.ts +3 -0
  49. package/lib/commands/deploy.js +99 -64
  50. package/lib/commands/external.js +4 -4
  51. package/lib/commands/serve.js +12 -18
  52. package/lib/commands/start.js +98 -86
  53. package/lib/commands/swizzle.js +42 -51
  54. package/lib/commands/writeHeadingIds.d.ts +9 -6
  55. package/lib/commands/writeHeadingIds.js +33 -34
  56. package/lib/commands/writeTranslations.js +31 -11
  57. package/lib/server/brokenLinks.js +13 -17
  58. package/lib/server/client-modules/index.js +1 -3
  59. package/lib/server/config.js +4 -4
  60. package/lib/server/configValidation.d.ts +1 -1
  61. package/lib/server/configValidation.js +14 -7
  62. package/lib/server/duplicateRoutes.js +8 -2
  63. package/lib/server/html-tags/htmlTags.js +5 -6
  64. package/lib/server/html-tags/index.js +2 -2
  65. package/lib/server/i18n.js +16 -16
  66. package/lib/server/index.js +132 -59
  67. package/lib/server/loadSetup.js +3 -3
  68. package/lib/server/moduleShorthand.d.ts +9 -0
  69. package/lib/server/moduleShorthand.js +42 -0
  70. package/lib/server/plugins/applyRouteTrailingSlash.js +1 -1
  71. package/lib/server/plugins/index.d.ts +1 -1
  72. package/lib/server/plugins/index.js +25 -21
  73. package/lib/server/plugins/init.js +9 -12
  74. package/lib/server/plugins/pluginIds.js +6 -4
  75. package/lib/server/presets/index.js +12 -12
  76. package/lib/server/routes.js +9 -11
  77. package/lib/server/themes/alias.d.ts +1 -0
  78. package/lib/server/themes/alias.js +21 -12
  79. package/lib/server/themes/index.d.ts +1 -1
  80. package/lib/server/themes/index.js +22 -23
  81. package/lib/server/translations/translations.d.ts +6 -0
  82. package/lib/server/translations/translations.js +19 -26
  83. package/lib/server/translations/translationsExtractor.d.ts +7 -1
  84. package/lib/server/translations/translationsExtractor.js +66 -59
  85. package/lib/server/utils.d.ts +8 -2
  86. package/lib/server/utils.js +8 -10
  87. package/lib/server/versions/__fixtures__/dummy-plugin.d.ts +0 -0
  88. package/lib/server/versions/__tests/index.test.js +5 -5
  89. package/lib/server/versions/index.js +6 -6
  90. package/lib/webpack/base.js +14 -16
  91. package/lib/webpack/client.js +9 -18
  92. package/lib/webpack/plugins/CleanWebpackPlugin.js +4 -11
  93. package/lib/webpack/plugins/LogPlugin.js +5 -6
  94. package/lib/webpack/plugins/WaitPlugin.js +4 -4
  95. package/lib/webpack/server.js +9 -9
  96. package/lib/webpack/utils.d.ts +0 -22
  97. package/lib/webpack/utils.js +37 -134
  98. package/package.json +55 -50
  99. package/lib/.tsbuildinfo +0 -1
  100. package/lib/client/.tsbuildinfo +0 -1
  101. package/lib/commands/buildRemoteBranchUrl.d.ts +0 -7
  102. package/lib/commands/buildRemoteBranchUrl.js +0 -27
  103. package/lib/constants.d.ts +0 -18
  104. package/lib/constants.js +0 -23
  105. package/lib/webpack/react-dev-utils-webpack5/README.md +0 -11
  106. package/lib/webpack/react-dev-utils-webpack5/evalSourceMapMiddleware.js +0 -57
  107. package/lib/webpack/react-dev-utils-webpack5/formatWebpackMessages.js +0 -138
  108. package/lib/webpack/react-dev-utils-webpack5/webpackHotDevClient.js +0 -285
  109. package/lib/webpack/sharedModuleAliases.js +0 -18
  110. package/tsconfig.client.json +0 -13
  111. package/tsconfig.json +0 -13
@@ -5,10 +5,12 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
8
+ import useIsBrowser from '@docusaurus/useIsBrowser';
9
+ // Similar comp to the one described here:
10
+ // https://www.joshwcomeau.com/react/the-perils-of-rehydration/#abstractions
9
11
  function BrowserOnly({ children, fallback, }) {
10
- const { isClient } = useDocusaurusContext();
11
- if (isClient && children != null) {
12
+ const isBrowser = useIsBrowser();
13
+ if (isBrowser && children != null) {
12
14
  return React.createElement(React.Fragment, null, children());
13
15
  }
14
16
  return fallback || null;
@@ -0,0 +1,18 @@
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
+ /// <reference types="@docusaurus/module-type-aliases" />
8
+ import React, { ReactNode } from 'react';
9
+ import type { Props } from '@docusaurus/ErrorBoundary';
10
+ interface State {
11
+ error: Error | null;
12
+ }
13
+ declare class ErrorBoundary extends React.Component<Props, State> {
14
+ constructor(props: Props);
15
+ componentDidCatch(error: Error): void;
16
+ render(): ReactNode;
17
+ }
18
+ export default ErrorBoundary;
@@ -0,0 +1,35 @@
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 ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
9
+ import DefaultFallback from '@theme/Error';
10
+ class ErrorBoundary extends React.Component {
11
+ constructor(props) {
12
+ super(props);
13
+ this.state = { error: null };
14
+ }
15
+ componentDidCatch(error) {
16
+ // Catch errors in any components below and re-render with error message
17
+ if (ExecutionEnvironment.canUseDOM) {
18
+ this.setState({ error });
19
+ }
20
+ }
21
+ render() {
22
+ var _a;
23
+ const { children } = this.props;
24
+ const { error } = this.state;
25
+ if (error) {
26
+ const fallback = (_a = this.props.fallback) !== null && _a !== void 0 ? _a : DefaultFallback;
27
+ return fallback({
28
+ error,
29
+ tryAgain: () => this.setState({ error: null }),
30
+ });
31
+ }
32
+ return children;
33
+ }
34
+ }
35
+ export default ErrorBoundary;
@@ -16,7 +16,7 @@ export function interpolate(text, values) {
16
16
  const elements = [];
17
17
  const processedText = text.replace(ValueRegexp, (match) => {
18
18
  // remove {{ and }} around the placeholder
19
- const key = match.substr(1, match.length - 2);
19
+ const key = match.substring(1, match.length - 1);
20
20
  const value = values === null || values === void 0 ? void 0 : values[key];
21
21
  if (typeof value !== 'undefined') {
22
22
  const element = React.isValidElement(value)
@@ -38,25 +38,22 @@ export function interpolate(text, values) {
38
38
  else if (elements.every((el) => typeof el === 'string')) {
39
39
  return processedText
40
40
  .split(ValueFoundMarker)
41
- .reduce((str, value, index) => {
42
- var _a;
43
- return str.concat(value).concat((_a = elements[index]) !== null && _a !== void 0 ? _a : '');
44
- }, '');
41
+ .reduce((str, value, index) => { var _a; return str.concat(value).concat((_a = elements[index]) !== null && _a !== void 0 ? _a : ''); }, '');
45
42
  }
46
43
  // JSX interpolation: returns ReactNode
47
44
  else {
48
- return processedText
49
- .split(ValueFoundMarker)
50
- .reduce((array, value, index) => {
51
- return [
52
- ...array,
53
- React.createElement(React.Fragment, { key: index },
54
- value,
55
- elements[index]),
56
- ];
57
- }, []);
45
+ return processedText.split(ValueFoundMarker).reduce((array, value, index) => [
46
+ ...array,
47
+ React.createElement(React.Fragment, { key: index },
48
+ value,
49
+ elements[index]),
50
+ ], []);
58
51
  }
59
52
  }
60
53
  export default function Interpolate({ children, values, }) {
54
+ if (typeof children !== 'string') {
55
+ console.warn('Illegal <Interpolate> children', children);
56
+ throw new Error('The Docusaurus <Interpolate> component only accept simple string values');
57
+ }
61
58
  return interpolate(children, values);
62
59
  }
@@ -50,25 +50,25 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
50
50
  targetLink = applyTrailingSlash(targetLink, { trailingSlash, baseUrl });
51
51
  }
52
52
  const preloaded = useRef(false);
53
- const LinkComponent = isNavLink ? NavLink : RRLink;
53
+ const LinkComponent = (isNavLink ? NavLink : RRLink);
54
54
  const IOSupported = ExecutionEnvironment.canUseIntersectionObserver;
55
- let io;
55
+ const ioRef = useRef();
56
56
  const handleIntersection = (el, cb) => {
57
- io = new window.IntersectionObserver((entries) => {
57
+ ioRef.current = new window.IntersectionObserver((entries) => {
58
58
  entries.forEach((entry) => {
59
59
  if (el === entry.target) {
60
60
  // If element is in viewport, stop listening/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
- io.unobserve(el);
64
- io.disconnect();
63
+ ioRef.current.unobserve(el);
64
+ ioRef.current.disconnect();
65
65
  cb();
66
66
  }
67
67
  }
68
68
  });
69
69
  });
70
70
  // Add element to the observer.
71
- io.observe(el);
71
+ ioRef.current.observe(el);
72
72
  };
73
73
  const handleRef = (ref) => {
74
74
  if (IOSupported && ref && isInternal) {
@@ -95,11 +95,11 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
95
95
  }
96
96
  // When unmounting, stop intersection observer from watching.
97
97
  return () => {
98
- if (IOSupported && io) {
99
- io.disconnect();
98
+ if (IOSupported && ioRef.current) {
99
+ ioRef.current.disconnect();
100
100
  }
101
101
  };
102
- }, [targetLink, IOSupported, isInternal]);
102
+ }, [ioRef, targetLink, IOSupported, isInternal]);
103
103
  const isAnchorLink = (_a = targetLink === null || targetLink === void 0 ? void 0 : targetLink.startsWith('#')) !== null && _a !== void 0 ? _a : false;
104
104
  const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
105
105
  if (targetLink && isInternal && !isAnchorLink && !noBrokenLinkCheck) {
@@ -5,8 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  /// <reference types="@docusaurus/module-type-aliases" />
8
- /// <reference types="react" />
8
+ import { ReactNode } from 'react';
9
9
  import { InterpolateValues } from '@docusaurus/Interpolate';
10
10
  import type { TranslateParam, TranslateProps } from '@docusaurus/Translate';
11
11
  export declare function translate<Str extends string>({ message, id }: TranslateParam<Str>, values?: InterpolateValues<Str, string | number>): string;
12
- export default function Translate<Str extends string>({ children, id, values, }: TranslateProps<Str>): JSX.Element;
12
+ export default function Translate<Str extends string>({ children, id, values, }: TranslateProps<Str>): ReactNode;
@@ -4,26 +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
- import Interpolate, { interpolate, } from '@docusaurus/Interpolate';
7
+ import { interpolate } from '@docusaurus/Interpolate';
9
8
  // Can't read it from context, due to exposing imperative API
10
9
  import codeTranslations from '@generated/codeTranslations';
11
10
  function getLocalizedMessage({ id, message, }) {
12
- var _a;
13
- return (_a = codeTranslations[id !== null && id !== void 0 ? id : message]) !== null && _a !== void 0 ? _a : message;
11
+ var _a, _b;
12
+ if (typeof id === 'undefined' && typeof message === 'undefined') {
13
+ throw new Error('Docusaurus translation declarations must have at least a translation id or a default translation message');
14
+ }
15
+ return (_b = (_a = codeTranslations[(id !== null && id !== void 0 ? id : message)]) !== null && _a !== void 0 ? _a : message) !== null && _b !== void 0 ? _b : id;
14
16
  }
15
17
  // Imperative translation API is useful for some edge-cases:
16
18
  // - translating page titles (meta)
17
19
  // - translating string props (input placeholders, image alt, aria labels...)
18
20
  export function translate({ message, id }, values) {
19
- var _a;
20
- const localizedMessage = (_a = getLocalizedMessage({ message, id })) !== null && _a !== void 0 ? _a : message;
21
+ const localizedMessage = getLocalizedMessage({ message, id });
21
22
  return interpolate(localizedMessage, values);
22
23
  }
23
24
  // Maybe we'll want to improve this component with additional features
24
25
  // Like toggling a translation mode that adds a little translation button near the text?
25
26
  export default function Translate({ children, id, values, }) {
26
- var _a;
27
- const localizedMessage = (_a = getLocalizedMessage({ message: children, id })) !== null && _a !== void 0 ? _a : children;
28
- return React.createElement(Interpolate, { values: values }, localizedMessage);
27
+ if (children && typeof children !== 'string') {
28
+ console.warn('Illegal <Translate> children', children);
29
+ throw new Error('The Docusaurus <Translate> component only accept simple string values');
30
+ }
31
+ const localizedMessage = getLocalizedMessage({ message: children, id });
32
+ return interpolate(localizedMessage, values);
29
33
  }
@@ -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 React, { ReactNode } from 'react';
8
+ export declare const Context: React.Context<boolean>;
9
+ export declare function BrowserContextProvider({ children, }: {
10
+ children: ReactNode;
11
+ }): JSX.Element;
@@ -0,0 +1,21 @@
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, { useEffect, useState } from 'react';
8
+ // Encapsulate the logic to avoid React hydration problems
9
+ // See https://www.joshwcomeau.com/react/the-perils-of-rehydration/
10
+ // On first client-side render, we need to render exactly as the server rendered
11
+ // isBrowser is set to true only after a successful hydration
12
+ // Note, isBrowser is not part of useDocusaurusContext() for perf reasons
13
+ // Using useDocusaurusContext() (much more common need) should not trigger re-rendering after a successful hydration
14
+ export const Context = React.createContext(false);
15
+ export function BrowserContextProvider({ children, }) {
16
+ const [isBrowser, setIsBrowser] = useState(false);
17
+ useEffect(() => {
18
+ setIsBrowser(true);
19
+ }, []);
20
+ return React.createElement(Context.Provider, { value: isBrowser }, children);
21
+ }
@@ -4,15 +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
- /*
8
- // eslint-disable-next-line no-restricted-imports
9
- export {
10
- // constants were only available on node
11
- // this makes some useful constants available to frontend/themes too
12
- // import {DEFAULT_PLUGIN_ID} '@docusaurus/constants'
13
- DEFAULT_PLUGIN_ID,
14
- } from '../../constants';
15
- */
16
- // Not duplicating the constants seems to produce
17
- // weird TS compilation side-effects
7
+ // Constants used on the client-side: duplicated from server-side code
18
8
  export const DEFAULT_PLUGIN_ID = 'default';
@@ -4,7 +4,9 @@
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';
7
+ import React, { ReactNode } from 'react';
8
8
  import { DocusaurusContext } from '@docusaurus/types';
9
- declare const _default: React.Context<DocusaurusContext | null>;
10
- export default _default;
9
+ export declare const Context: React.Context<DocusaurusContext>;
10
+ export declare function DocusaurusContextProvider({ children, }: {
11
+ children: ReactNode;
12
+ }): JSX.Element;
@@ -0,0 +1,25 @@
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 siteConfig from '@generated/docusaurus.config';
9
+ import globalData from '@generated/globalData';
10
+ import i18n from '@generated/i18n';
11
+ import codeTranslations from '@generated/codeTranslations';
12
+ import siteMetadata from '@generated/site-metadata';
13
+ // Static value on purpose: don't make it dynamic!
14
+ // Using context is still useful for testability reasons.
15
+ const contextValue = {
16
+ siteConfig,
17
+ siteMetadata,
18
+ globalData,
19
+ i18n,
20
+ codeTranslations,
21
+ };
22
+ export const Context = React.createContext(contextValue);
23
+ export function DocusaurusContextProvider({ children, }) {
24
+ return React.createElement(Context.Provider, { value: contextValue }, children);
25
+ }
@@ -27,11 +27,9 @@ function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolu
27
27
  return absolute ? siteUrl + basePath : basePath;
28
28
  }
29
29
  export function useBaseUrlUtils() {
30
- const { siteConfig: { baseUrl = '/', url: siteUrl } = {}, } = useDocusaurusContext();
30
+ const { siteConfig: { baseUrl = '/', url: siteUrl } = {} } = useDocusaurusContext();
31
31
  return {
32
- withBaseUrl: (url, options) => {
33
- return addBaseUrl(siteUrl, baseUrl, url, options);
34
- },
32
+ withBaseUrl: (url, options) => addBaseUrl(siteUrl, baseUrl, url, options),
35
33
  };
36
34
  }
37
35
  export default function useBaseUrl(url, options = {}) {
@@ -5,13 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { useContext } from 'react';
8
- import context from './context';
8
+ import { Context } from './docusaurusContext';
9
9
  function useDocusaurusContext() {
10
- const docusaurusContext = useContext(context);
11
- if (docusaurusContext === null) {
12
- // should not happen normally
13
- throw new Error('Docusaurus context not provided.');
14
- }
15
- return docusaurusContext;
10
+ return useContext(Context);
16
11
  }
17
12
  export default useDocusaurusContext;
@@ -5,11 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import useDocusaurusContext from './useDocusaurusContext';
8
- // TODO annoying constant duplication
9
- // if we import something from outside the /client folder,
10
- // the tsc directory structure is affected
11
- // import {DEFAULT_PLUGIN_ID} from '../../constants';
12
- const DEFAULT_PLUGIN_ID = 'default';
8
+ import { DEFAULT_PLUGIN_ID } from './constants';
13
9
  export default function useGlobalData() {
14
10
  const { globalData } = useDocusaurusContext();
15
11
  if (!globalData) {
@@ -4,5 +4,4 @@
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
- export default React.createContext(null);
7
+ export default function useIsBrowser(): boolean;
@@ -4,7 +4,8 @@
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
- declare const SharedModuleAliases: {
8
- 'react-loadable': string;
9
- };
10
- export default SharedModuleAliases;
7
+ import { useContext } from 'react';
8
+ import { Context } from './browserContext';
9
+ export default function useIsBrowser() {
10
+ return useContext(Context);
11
+ }
@@ -4,5 +4,6 @@
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
- declare function flat(target: unknown): Record<string, any>;
7
+ import type { RouteChunksTree } from '@docusaurus/types';
8
+ declare function flat(target: RouteChunksTree): Record<string, string>;
8
9
  export default flat;
@@ -4,22 +4,20 @@
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
- // Too dynamic
8
- /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ const isTree = (x) => typeof x === 'object' && !!x && Object.keys(x).length > 0;
9
8
  function flat(target) {
10
9
  const delimiter = '.';
11
10
  const output = {};
12
- function step(object, prev) {
11
+ function step(object, prefix) {
13
12
  Object.keys(object).forEach((key) => {
14
13
  const value = object[key];
15
- const type = typeof value;
16
- const isObject = type === 'object' && !!value;
17
- const newKey = prev ? prev + delimiter + key : key;
18
- if (isObject && Object.keys(value).length) {
14
+ const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
15
+ if (isTree(value)) {
19
16
  step(value, newKey);
20
- return;
21
17
  }
22
- output[newKey] = value;
18
+ else {
19
+ output[newKey] = value;
20
+ }
23
21
  });
24
22
  }
25
23
  step(target);
@@ -4,8 +4,6 @@
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
- declare type Location = {
8
- pathname: string;
9
- };
7
+ import type { Location } from '@docusaurus/history';
10
8
  declare function normalizeLocation<T extends Location>(location: T): T;
11
9
  export default normalizeLocation;
@@ -66,7 +66,6 @@ function prefetch(url) {
66
66
  resolve();
67
67
  preFetched[url] = true;
68
68
  })
69
- // eslint-disable-next-line @typescript-eslint/no-empty-function
70
69
  .catch(() => { }); // 404s are logged to the console anyway.
71
70
  });
72
71
  }
@@ -5,6 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ // @ts-check
9
+
8
10
  import * as eta from 'eta';
9
11
  import React from 'react';
10
12
  import {StaticRouter} from 'react-router-dom';
@@ -18,23 +20,21 @@ import path from 'path';
18
20
  import fs from 'fs-extra';
19
21
  import routes from '@generated/routes';
20
22
  import packageJson from '../../package.json';
21
- // eslint-disable-next-line import/no-unresolved
22
23
  import preload from './preload';
23
- // eslint-disable-next-line import/no-unresolved
24
24
  import App from './App';
25
25
  import {
26
26
  createStatefulLinksCollector,
27
27
  ProvideLinksCollector,
28
28
  } from './LinksCollector';
29
- import chalk from 'chalk';
29
+ import logger from '@docusaurus/logger';
30
30
  // eslint-disable-next-line no-restricted-imports
31
31
  import {memoize} from 'lodash';
32
32
 
33
- const getCompiledSSRTemplate = memoize((template) => {
34
- return eta.compile(template.trim(), {
33
+ const getCompiledSSRTemplate = memoize((template) =>
34
+ eta.compile(template.trim(), {
35
35
  rmWhitespace: true,
36
- });
37
- });
36
+ }),
37
+ );
38
38
 
39
39
  function renderSSRTemplate(ssrTemplate, data) {
40
40
  const compiled = getCompiledSSRTemplate(ssrTemplate);
@@ -45,20 +45,16 @@ export default async function render(locals) {
45
45
  try {
46
46
  return await doRender(locals);
47
47
  } catch (e) {
48
- console.error(
49
- chalk.red(
50
- `Docusaurus Node/SSR could not render static page with path "${locals.path}" because of following error:\n\n${e.stack}\n`,
51
- ),
52
- );
48
+ logger.error`Docusaurus Node/SSR could not render static page with path path=${locals.path} because of following error:
49
+ ${e.stack}`;
53
50
 
54
- const isNotDefinedErrorRegex = /(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
51
+ const isNotDefinedErrorRegex =
52
+ /(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
55
53
 
56
54
  if (isNotDefinedErrorRegex.test(e.message)) {
57
- console.error(
58
- chalk.green(
59
- 'Pro tip: It looks like you are using code that should run on the client-side only.\nTo get around it, try using <BrowserOnly> (https://docusaurus.io/docs/docusaurus-core/#browseronly) or ExecutionEnvironment (https://docusaurus.io/docs/docusaurus-core/#executionenvironment).\nIt might also require to wrap your client code in useEffect hook and/or import a third-party library dynamically (if any).',
60
- ),
61
- );
55
+ logger.info`It looks like you are using code that should run on the client-side only.
56
+ 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'}).
57
+ It might also require to wrap your client code in code=${'useEffect'} hook and/or import a third-party library dynamically (if any).`;
62
58
  }
63
59
 
64
60
  throw new Error('Server-side rendering fails due to the error above.');
@@ -131,10 +127,10 @@ async function doRender(locals) {
131
127
  version: packageJson.version,
132
128
  });
133
129
 
134
- // Minify html with https://github.com/DanielRuf/html-minifier-terser
135
- function doMinify() {
136
- return minify(renderedHtml, {
137
- removeComments: true,
130
+ try {
131
+ // Minify html with https://github.com/DanielRuf/html-minifier-terser
132
+ return await minify(renderedHtml, {
133
+ removeComments: false,
138
134
  removeRedundantAttributes: true,
139
135
  removeEmptyAttributes: true,
140
136
  removeScriptTypeAttributes: true,
@@ -142,27 +138,9 @@ async function doRender(locals) {
142
138
  useShortDoctype: true,
143
139
  minifyJS: true,
144
140
  });
145
- }
146
-
147
- // TODO this is a temporary error affecting only monorepos due to Terser 5 (async) being used by html-minifier-terser,
148
- // instead of the expected Terser 4 (sync)
149
- // TODO, remove this once we upgrade everything to Terser 5 (https://github.com/terser/html-minifier-terser/issues/46)
150
- // See also
151
- // - https://github.com/facebook/docusaurus/issues/3515
152
- // - https://github.com/terser/html-minifier-terser/issues/49
153
- try {
154
- return doMinify();
155
141
  } catch (e) {
156
- if (
157
- e.message &&
158
- e.message.includes("Cannot read property 'replace' of undefined")
159
- ) {
160
- console.error(
161
- chalk.red(
162
- '\nDocusaurus user: you probably have this known error due to using a monorepo/workspace.\nWe have a workaround for you, please see https://github.com/facebook/docusaurus/issues/3515\n',
163
- ),
164
- );
165
- }
142
+ logger.error`Minification of page path=${locals.path} failed because of following error:
143
+ ${e.stack}`;
166
144
  throw e;
167
145
  }
168
146
  }
@@ -0,0 +1,47 @@
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
+
8
+ import React from 'react';
9
+ import Layout from '@theme/Layout';
10
+ import ErrorBoundary from '@docusaurus/ErrorBoundary';
11
+
12
+ function ErrorDisplay({error, tryAgain}) {
13
+ return (
14
+ <div
15
+ style={{
16
+ display: 'flex',
17
+ flexDirection: 'column',
18
+ justifyContent: 'center',
19
+ alignItems: 'center',
20
+ height: '50vh',
21
+ width: '100%',
22
+ fontSize: '20px',
23
+ }}>
24
+ <h1>This page crashed.</h1>
25
+ <p>{error.message}</p>
26
+ <button type="button" onClick={tryAgain}>
27
+ Try again
28
+ </button>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ function Error({error, tryAgain}) {
34
+ // We wrap the error in its own error boundary because the layout can actually throw too...
35
+ // Only the ErrorDisplay component is simple enough to be considered safe to never throw
36
+ return (
37
+ <ErrorBoundary
38
+ // Note: we display the original error here, not the error that we captured in this extra error boundary
39
+ fallback={() => <ErrorDisplay error={error} tryAgain={tryAgain} />}>
40
+ <Layout title="Page Error">
41
+ <ErrorDisplay error={error} tryAgain={tryAgain} />
42
+ </Layout>
43
+ </ErrorBoundary>
44
+ );
45
+ }
46
+
47
+ export default Error;
@@ -20,7 +20,7 @@ function Layout(props) {
20
20
  <>
21
21
  <Head defaultTitle={`${defaultTitle}${tagline ? ` · ${tagline}` : ''}`}>
22
22
  {title && <title>{`${title} · ${tagline}`}</title>}
23
- {favicon && <link rel="shortcut icon" href={faviconUrl} />}
23
+ {favicon && <link rel="icon" href={faviconUrl} />}
24
24
  {description && <meta name="description" content={description} />}
25
25
  {description && (
26
26
  <meta property="og:description" content={description} />
@@ -7,7 +7,7 @@
7
7
 
8
8
  import React from 'react';
9
9
 
10
- export default ({error, retry, pastDelay}) => {
10
+ export default function Loading({error, retry, pastDelay}) {
11
11
  if (error) {
12
12
  return (
13
13
  <div
@@ -133,4 +133,4 @@ export default ({error, retry, pastDelay}) => {
133
133
  }
134
134
 
135
135
  return null;
136
- };
136
+ }
@@ -5,8 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React from 'react';
9
-
10
8
  // Wrapper at the very top of the app, that is applied constantly
11
9
  // and does not depend on current route (unlike the layout)
12
10
  //
@@ -15,7 +13,7 @@ import React from 'react';
15
13
  //
16
14
  // See https://github.com/facebook/docusaurus/issues/3919
17
15
  function Root({children}) {
18
- return <>{children}</>;
16
+ return children;
19
17
  }
20
18
 
21
19
  export default Root;