@docusaurus/core 0.0.0-5945 → 0.0.0-5946

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