@docusaurus/core 3.3.2 → 3.4.0

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 (38) hide show
  1. package/lib/client/clientEntry.js +7 -3
  2. package/lib/client/exports/Link.js +12 -2
  3. package/lib/client/exports/useBaseUrl.d.ts +8 -0
  4. package/lib/client/exports/useBaseUrl.js +11 -3
  5. package/lib/commands/build.js +35 -21
  6. package/lib/commands/serve.js +15 -4
  7. package/lib/commands/start/utils.d.ts +3 -2
  8. package/lib/commands/start/utils.js +7 -2
  9. package/lib/commands/start/webpack.js +3 -3
  10. package/lib/server/brokenLinks.js +9 -1
  11. package/lib/server/codegen/codegen.d.ts +2 -1
  12. package/lib/server/codegen/codegen.js +4 -0
  13. package/lib/server/codegen/codegenRoutes.d.ts +1 -0
  14. package/lib/server/codegen/codegenRoutes.js +20 -6
  15. package/lib/server/configValidation.d.ts +4 -1
  16. package/lib/server/configValidation.js +29 -1
  17. package/lib/server/htmlTags.d.ts +5 -2
  18. package/lib/server/htmlTags.js +15 -6
  19. package/lib/server/i18n.js +37 -8
  20. package/lib/server/site.js +13 -5
  21. package/lib/server/storage.d.ts +13 -0
  22. package/lib/server/storage.js +36 -0
  23. package/lib/ssg.d.ts +4 -0
  24. package/lib/ssg.js +9 -1
  25. package/lib/templates/templates.d.ts +3 -0
  26. package/lib/templates/templates.js +26 -1
  27. package/lib/webpack/base.js +1 -1
  28. package/lib/webpack/client.js +10 -18
  29. package/lib/webpack/configure.d.ts +25 -0
  30. package/lib/webpack/configure.js +100 -0
  31. package/lib/webpack/plugins/ForceTerminatePlugin.d.ts +10 -0
  32. package/lib/webpack/plugins/ForceTerminatePlugin.js +25 -0
  33. package/lib/webpack/plugins/StaticDirectoriesCopyPlugin.d.ts +11 -0
  34. package/lib/webpack/plugins/StaticDirectoriesCopyPlugin.js +39 -0
  35. package/lib/webpack/server.js +0 -28
  36. package/lib/webpack/utils.d.ts +0 -22
  37. package/lib/webpack/utils.js +1 -80
  38. package/package.json +10 -10
@@ -10,8 +10,32 @@ exports.loadI18n = exports.getDefaultLocaleConfig = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
12
12
  const rtl_detect_1 = require("rtl-detect");
13
+ function inferLanguageDisplayName(locale) {
14
+ const tryLocale = (l) => {
15
+ try {
16
+ return new Intl.DisplayNames(l, {
17
+ type: 'language',
18
+ fallback: 'code',
19
+ }).of(l);
20
+ }
21
+ catch (e) {
22
+ // This is to compensate "of()" that is a bit strict
23
+ // Looks like starting Node 22, this locale throws: "en-US-u-ca-buddhist"
24
+ // RangeError: invalid_argument
25
+ return null;
26
+ }
27
+ };
28
+ const parts = locale.split('-');
29
+ // This is a best effort, we try various locale forms that could give a result
30
+ return (tryLocale(locale) ??
31
+ tryLocale(`${parts[0]}-${parts[1]}`) ??
32
+ tryLocale(parts[0]));
33
+ }
13
34
  function getDefaultLocaleLabel(locale) {
14
- const languageName = new Intl.DisplayNames(locale, { type: 'language' }).of(locale);
35
+ const languageName = inferLanguageDisplayName(locale);
36
+ if (!languageName) {
37
+ return locale;
38
+ }
15
39
  return (languageName.charAt(0).toLocaleUpperCase(locale) + languageName.substring(1));
16
40
  }
17
41
  function getDefaultCalendar(localeStr) {
@@ -34,13 +58,18 @@ function getDefaultCalendar(localeStr) {
34
58
  return 'gregory';
35
59
  }
36
60
  function getDefaultLocaleConfig(locale) {
37
- return {
38
- label: getDefaultLocaleLabel(locale),
39
- direction: (0, rtl_detect_1.getLangDir)(locale),
40
- htmlLang: locale,
41
- calendar: getDefaultCalendar(locale),
42
- path: locale,
43
- };
61
+ try {
62
+ return {
63
+ label: getDefaultLocaleLabel(locale),
64
+ direction: (0, rtl_detect_1.getLangDir)(locale),
65
+ htmlLang: locale,
66
+ calendar: getDefaultCalendar(locale),
67
+ path: locale,
68
+ };
69
+ }
70
+ catch (e) {
71
+ throw new Error(`Docusaurus couldn't get default locale config for ${locale}`, { cause: e });
72
+ }
44
73
  }
45
74
  exports.getDefaultLocaleConfig = getDefaultLocaleConfig;
46
75
  async function loadI18n(config, options) {
@@ -21,6 +21,7 @@ const translations_1 = require("./translations/translations");
21
21
  const utils_2 = require("../utils");
22
22
  const codegen_1 = require("./codegen/codegen");
23
23
  const routes_1 = require("./routes");
24
+ const storage_1 = require("./storage");
24
25
  /**
25
26
  * Loading context is the very first step in site building. Its params are
26
27
  * directly acquired from CLI options. It mainly loads `siteConfig` and the i18n
@@ -53,9 +54,11 @@ async function loadContext(params) {
53
54
  const localizationDir = path_1.default.resolve(siteDir, i18n.path, i18n.localeConfigs[i18n.currentLocale].path);
54
55
  const siteConfig = { ...initialSiteConfig, baseUrl };
55
56
  const codeTranslations = await (0, translations_1.loadSiteCodeTranslations)({ localizationDir });
57
+ const siteStorage = (0, storage_1.createSiteStorage)(siteConfig);
56
58
  return {
57
59
  siteDir,
58
60
  siteVersion,
61
+ siteStorage,
59
62
  generatedFilesDir,
60
63
  localizationDir,
61
64
  siteConfig,
@@ -69,8 +72,11 @@ async function loadContext(params) {
69
72
  exports.loadContext = loadContext;
70
73
  function createSiteProps(params) {
71
74
  const { plugins, routes, context } = params;
72
- const { generatedFilesDir, siteDir, siteVersion, siteConfig, siteConfigPath, outDir, baseUrl, i18n, localizationDir, codeTranslations: siteCodeTranslations, } = context;
73
- const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)(plugins);
75
+ const { generatedFilesDir, siteDir, siteVersion, siteConfig, siteConfigPath, siteStorage, outDir, baseUrl, i18n, localizationDir, codeTranslations: siteCodeTranslations, } = context;
76
+ const { headTags, preBodyTags, postBodyTags } = (0, htmlTags_1.loadHtmlTags)({
77
+ plugins,
78
+ router: siteConfig.future.experimental_router,
79
+ });
74
80
  const siteMetadata = (0, siteMetadata_1.createSiteMetadata)({ plugins, siteVersion });
75
81
  const codeTranslations = {
76
82
  ...(0, translations_1.getPluginsDefaultCodeTranslations)({ plugins }),
@@ -83,6 +89,7 @@ function createSiteProps(params) {
83
89
  siteConfigPath,
84
90
  siteMetadata,
85
91
  siteVersion,
92
+ siteStorage,
86
93
  siteDir,
87
94
  outDir,
88
95
  baseUrl,
@@ -101,13 +108,14 @@ function createSiteProps(params) {
101
108
  // TODO global data should be part of site props?
102
109
  async function createSiteFiles({ site, globalData, }) {
103
110
  return utils_2.PerfLogger.async('Create site files', async () => {
104
- const { props: { plugins, generatedFilesDir, siteConfig, siteMetadata, i18n, codeTranslations, routes, baseUrl, }, } = site;
111
+ const { props: { plugins, generatedFilesDir, siteConfig, siteMetadata, siteStorage, i18n, codeTranslations, routes, baseUrl, }, } = site;
105
112
  const clientModules = (0, clientModules_1.getAllClientModules)(plugins);
106
113
  await (0, codegen_1.generateSiteFiles)({
107
114
  generatedFilesDir,
108
115
  clientModules,
109
116
  siteConfig,
110
117
  siteMetadata,
118
+ siteStorage,
111
119
  i18n,
112
120
  codeTranslations,
113
121
  globalData,
@@ -125,7 +133,7 @@ async function createSiteFiles({ site, globalData, }) {
125
133
  async function loadSite(params) {
126
134
  const context = await utils_2.PerfLogger.async('Load context', () => loadContext(params));
127
135
  const { plugins, routes, globalData } = await (0, plugins_1.loadPlugins)(context);
128
- const props = await createSiteProps({ plugins, routes, globalData, context });
136
+ const props = createSiteProps({ plugins, routes, globalData, context });
129
137
  const site = { props, params };
130
138
  await createSiteFiles({
131
139
  site,
@@ -147,7 +155,7 @@ async function reloadSitePlugin(site, pluginIdentifier) {
147
155
  plugins: site.props.plugins,
148
156
  context: site.props,
149
157
  });
150
- const newProps = await createSiteProps({
158
+ const newProps = createSiteProps({
151
159
  plugins,
152
160
  routes,
153
161
  globalData,
@@ -0,0 +1,13 @@
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 { DocusaurusConfig, SiteStorage } from '@docusaurus/types';
8
+ type PartialFuture = Pick<DocusaurusConfig['future'], 'experimental_storage'>;
9
+ type PartialConfig = Pick<DocusaurusConfig, 'url' | 'baseUrl'> & {
10
+ future: PartialFuture;
11
+ };
12
+ export declare function createSiteStorage(config: PartialConfig): SiteStorage;
13
+ export {};
@@ -0,0 +1,36 @@
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.createSiteStorage = void 0;
10
+ const utils_1 = require("@docusaurus/utils");
11
+ const utils_common_1 = require("@docusaurus/utils-common");
12
+ function automaticNamespace(config) {
13
+ const normalizedUrl = (0, utils_common_1.addTrailingSlash)((0, utils_1.normalizeUrl)([config.url, config.baseUrl]));
14
+ return (0, utils_1.simpleHash)(normalizedUrl, 3);
15
+ }
16
+ function getNamespaceString(config) {
17
+ if (config.future.experimental_storage.namespace === true) {
18
+ return automaticNamespace(config);
19
+ }
20
+ else if (config.future.experimental_storage.namespace === false) {
21
+ return null;
22
+ }
23
+ else {
24
+ return config.future.experimental_storage.namespace;
25
+ }
26
+ }
27
+ function createSiteStorage(config) {
28
+ const { type } = config.future.experimental_storage;
29
+ const namespaceString = getNamespaceString(config);
30
+ const namespace = namespaceString ? `-${namespaceString}` : '';
31
+ return {
32
+ type,
33
+ namespace,
34
+ };
35
+ }
36
+ exports.createSiteStorage = createSiteStorage;
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,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 type { Configuration, RuleSetRule } from 'webpack';
8
+ import type { Plugin, LoadedPlugin } from '@docusaurus/types';
9
+ /**
10
+ * Helper function to modify webpack config
11
+ * @param configureWebpack a webpack config or a function to modify config
12
+ * @param config initial webpack config
13
+ * @param isServer indicates if this is a server webpack configuration
14
+ * @param jsLoader custom js loader config
15
+ * @param content content loaded by the plugin
16
+ * @returns final/ modified webpack config
17
+ */
18
+ export declare function applyConfigureWebpack(configureWebpack: NonNullable<Plugin['configureWebpack']>, config: Configuration, isServer: boolean, jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) | undefined, content: unknown): Configuration;
19
+ export declare function applyConfigurePostCss(configurePostCss: NonNullable<Plugin['configurePostCss']>, config: Configuration): Configuration;
20
+ export declare function executePluginsConfigureWebpack({ plugins, config, isServer, jsLoader, }: {
21
+ plugins: LoadedPlugin[];
22
+ config: Configuration;
23
+ isServer: boolean;
24
+ jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) | undefined;
25
+ }): Configuration;
@@ -0,0 +1,100 @@
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.executePluginsConfigureWebpack = exports.applyConfigurePostCss = exports.applyConfigureWebpack = void 0;
10
+ const webpack_merge_1 = require("webpack-merge");
11
+ const utils_1 = require("./utils");
12
+ /**
13
+ * Helper function to modify webpack config
14
+ * @param configureWebpack a webpack config or a function to modify config
15
+ * @param config initial webpack config
16
+ * @param isServer indicates if this is a server webpack configuration
17
+ * @param jsLoader custom js loader config
18
+ * @param content content loaded by the plugin
19
+ * @returns final/ modified webpack config
20
+ */
21
+ function applyConfigureWebpack(configureWebpack, config, isServer, jsLoader, content) {
22
+ // Export some utility functions
23
+ const utils = {
24
+ getStyleLoaders: utils_1.getStyleLoaders,
25
+ getJSLoader: (0, utils_1.getCustomizableJSLoader)(jsLoader),
26
+ };
27
+ if (typeof configureWebpack === 'function') {
28
+ const { mergeStrategy, ...res } = configureWebpack(config, isServer, utils, content) ?? {};
29
+ const customizeRules = mergeStrategy ?? {};
30
+ return (0, webpack_merge_1.mergeWithCustomize)({
31
+ customizeArray: (0, webpack_merge_1.customizeArray)(customizeRules),
32
+ customizeObject: (0, webpack_merge_1.customizeObject)(customizeRules),
33
+ })(config, res);
34
+ }
35
+ return config;
36
+ }
37
+ exports.applyConfigureWebpack = applyConfigureWebpack;
38
+ function applyConfigurePostCss(configurePostCss, config) {
39
+ // Not ideal heuristic but good enough for our use-case?
40
+ function isPostCssLoader(loader) {
41
+ return !!loader?.options?.postcssOptions;
42
+ }
43
+ // Does not handle all edge cases, but good enough for now
44
+ function overridePostCssOptions(entry) {
45
+ if (isPostCssLoader(entry)) {
46
+ entry.options.postcssOptions = configurePostCss(entry.options.postcssOptions);
47
+ }
48
+ else if (Array.isArray(entry.oneOf)) {
49
+ entry.oneOf.forEach((r) => {
50
+ if (r) {
51
+ overridePostCssOptions(r);
52
+ }
53
+ });
54
+ }
55
+ else if (Array.isArray(entry.use)) {
56
+ entry.use
57
+ .filter((u) => typeof u === 'object')
58
+ .forEach((rule) => overridePostCssOptions(rule));
59
+ }
60
+ }
61
+ config.module?.rules?.forEach((rule) => overridePostCssOptions(rule));
62
+ return config;
63
+ }
64
+ exports.applyConfigurePostCss = applyConfigurePostCss;
65
+ // Plugin Lifecycle - configurePostCss()
66
+ function executePluginsConfigurePostCss({ plugins, config, }) {
67
+ let resultConfig = config;
68
+ plugins.forEach((plugin) => {
69
+ const { configurePostCss } = plugin;
70
+ if (configurePostCss) {
71
+ resultConfig = applyConfigurePostCss(configurePostCss.bind(plugin), resultConfig);
72
+ }
73
+ });
74
+ return resultConfig;
75
+ }
76
+ // Plugin Lifecycle - configureWebpack()
77
+ function executePluginsConfigureWebpack({ plugins, config, isServer, jsLoader, }) {
78
+ // Step1 - Configure Webpack
79
+ let resultConfig = config;
80
+ plugins.forEach((plugin) => {
81
+ const { configureWebpack } = plugin;
82
+ if (configureWebpack) {
83
+ resultConfig = applyConfigureWebpack(configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
84
+ resultConfig, isServer, jsLoader, plugin.content);
85
+ }
86
+ });
87
+ // Step2 - For client code, configure PostCSS
88
+ // The order matters! We want to configure PostCSS on loaders
89
+ // that were potentially added by configureWebpack
90
+ // See https://github.com/facebook/docusaurus/issues/10106
91
+ // Note: it's useless to configure postCSS for the server
92
+ if (!isServer) {
93
+ resultConfig = executePluginsConfigurePostCss({
94
+ plugins,
95
+ config: resultConfig,
96
+ });
97
+ }
98
+ return resultConfig;
99
+ }
100
+ exports.executePluginsConfigureWebpack = executePluginsConfigureWebpack;
@@ -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
- }
@@ -7,7 +7,6 @@
7
7
  /// <reference types="node" />
8
8
  import webpack, { type Configuration, type RuleSetRule } from 'webpack';
9
9
  import type { TransformOptions } from '@babel/core';
10
- import type { Plugin, LoadedPlugin } from '@docusaurus/types';
11
10
  export declare function formatStatsErrorMessage(statsJson: ReturnType<webpack.Stats['toJson']> | undefined): string | undefined;
12
11
  export declare function printStatsWarnings(statsJson: ReturnType<webpack.Stats['toJson']> | undefined): void;
13
12
  export declare function getStyleLoaders(isServer: boolean, cssOptionsArg?: {
@@ -22,27 +21,6 @@ export declare const getCustomizableJSLoader: (jsLoader?: 'babel' | ((isServer:
22
21
  isServer: boolean;
23
22
  babelOptions?: TransformOptions | string;
24
23
  }) => RuleSetRule;
25
- /**
26
- * Helper function to modify webpack config
27
- * @param configureWebpack a webpack config or a function to modify config
28
- * @param config initial webpack config
29
- * @param isServer indicates if this is a server webpack configuration
30
- * @param jsLoader custom js loader config
31
- * @param content content loaded by the plugin
32
- * @returns final/ modified webpack config
33
- */
34
- export declare function applyConfigureWebpack(configureWebpack: NonNullable<Plugin['configureWebpack']>, config: Configuration, isServer: boolean, jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) | undefined, content: unknown): Configuration;
35
- export declare function applyConfigurePostCss(configurePostCss: NonNullable<Plugin['configurePostCss']>, config: Configuration): Configuration;
36
- export declare function executePluginsConfigurePostCss({ plugins, config, }: {
37
- plugins: LoadedPlugin[];
38
- config: Configuration;
39
- }): Configuration;
40
- export declare function executePluginsConfigureWebpack({ plugins, config, isServer, jsLoader, }: {
41
- plugins: LoadedPlugin[];
42
- config: Configuration;
43
- isServer: boolean;
44
- jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) | undefined;
45
- }): Configuration;
46
24
  declare global {
47
25
  interface Error {
48
26
  /** @see https://webpack.js.org/api/node/#error-handling */