feat(core, mdx-loader): deduplicate MDX compilation - siteConfig.future.experimental_faster.mdxCrossCompilerCache (#10479)

This commit is contained in:
Sébastien Lorber 2024-09-06 16:07:09 +02:00 committed by GitHub
parent 897ebbe3ca
commit 5bab0b5432
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 333 additions and 151 deletions

View file

@ -6,30 +6,49 @@
*/
import {createProcessors} from './processor';
import type {Options} from './loader';
import type {Options} from './options';
import type {RuleSetRule, RuleSetUseItem} from 'webpack';
async function enhancedOptions(options: Options): Promise<Options> {
type CreateOptions = {
useCrossCompilerCache?: boolean;
};
async function normalizeOptions(
optionsInput: Options & CreateOptions,
): Promise<Options> {
// Because Jest doesn't like ESM / createProcessors()
if (process.env.N0DE_ENV === 'test' || process.env.JEST_WORKER_ID) {
return options;
return optionsInput;
}
let options = optionsInput;
// We create the processor earlier here, to avoid the lazy processor creating
// Lazy creation messes-up with Rsdoctor ability to measure mdx-loader perf
const newOptions: Options = options.processors
? options
: {...options, processors: await createProcessors({options})};
if (!options.processors) {
options = {...options, processors: await createProcessors({options})};
}
return newOptions;
// Cross-compiler cache permits to compile client/server MDX only once
// We don't want to cache in dev mode (docusaurus start)
// We only have multiple compilers in production mode (docusaurus build)
// TODO wrong but good enough for now (example: "docusaurus build --dev")
if (options.useCrossCompilerCache && process.env.NODE_ENV === 'production') {
options = {
...options,
crossCompilerCache: new Map(),
};
}
return options;
}
export async function createMDXLoaderItem(
options: Options,
options: Options & CreateOptions,
): Promise<RuleSetUseItem> {
return {
loader: require.resolve('@docusaurus/mdx-loader'),
options: await enhancedOptions(options),
options: await normalizeOptions(options),
};
}
@ -38,7 +57,7 @@ export async function createMDXLoaderRule({
options,
}: {
include: RuleSetRule['include'];
options: Options;
options: Options & CreateOptions;
}): Promise<RuleSetRule> {
return {
test: /\.mdx?$/i,

View file

@ -37,5 +37,6 @@ export type LoadedMDXContent<FrontMatter, Metadata, Assets = undefined> = {
(): JSX.Element;
};
export type {Options, MDXPlugin} from './loader';
export type {MDXPlugin} from './loader';
export type {MDXOptions} from './processor';
export type {Options} from './options';

View file

@ -18,14 +18,8 @@ import {
createAssetsExportCode,
extractContentTitleData,
} from './utils';
import type {
SimpleProcessors,
MDXOptions,
SimpleProcessorResult,
} from './processor';
import type {ResolveMarkdownLink} from './remark/resolveMarkdownLinks';
import type {MarkdownConfig} from '@docusaurus/types';
import type {WebpackCompilerName} from '@docusaurus/utils';
import type {Options} from './options';
import type {LoaderContext} from 'webpack';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
@ -35,33 +29,17 @@ type Pluggable = any; // TODO fix this asap
export type MDXPlugin = Pluggable;
export type Options = Partial<MDXOptions> & {
markdownConfig: MarkdownConfig;
staticDirs: string[];
siteDir: string;
isMDXPartial?: (filePath: string) => boolean;
isMDXPartialFrontMatterWarningDisabled?: boolean;
removeContentTitle?: boolean;
metadataPath?: (filePath: string) => string;
createAssets?: (metadata: {
filePath: string;
frontMatter: {[key: string]: unknown};
}) => {[key: string]: unknown};
resolveMarkdownLink?: ResolveMarkdownLink;
// Will usually be created by "createMDXLoaderItem"
processors?: SimpleProcessors;
};
export async function mdxLoader(
this: LoaderContext<Options>,
fileContent: string,
): Promise<void> {
const compilerName = getWebpackLoaderCompilerName(this);
const callback = this.async();
const filePath = this.resourcePath;
const options: Options = this.getOptions();
async function loadMDX({
fileContent,
filePath,
options,
compilerName,
}: {
fileContent: string;
filePath: string;
options: Options;
compilerName: WebpackCompilerName;
}): Promise<string> {
const {frontMatter} = await options.markdownConfig.parseFrontMatter({
filePath,
fileContent,
@ -70,18 +48,13 @@ export async function mdxLoader(
const hasFrontMatter = Object.keys(frontMatter).length > 0;
let result: SimpleProcessorResult;
try {
result = await compileToJSX({
fileContent,
filePath,
frontMatter,
options,
compilerName,
});
} catch (error) {
return callback(error as Error);
}
const result = await compileToJSX({
fileContent,
filePath,
frontMatter,
options,
compilerName,
});
const contentTitle = extractContentTitleData(result.data);
@ -97,7 +70,7 @@ ${JSON.stringify(frontMatter, null, 2)}`;
if (!options.isMDXPartialFrontMatterWarningDisabled) {
const shouldError = process.env.NODE_ENV === 'test' || process.env.CI;
if (shouldError) {
return callback(new Error(errorMessage));
throw new Error(errorMessage);
}
logger.warn(errorMessage);
}
@ -146,5 +119,68 @@ ${exportsCode}
${result.content}
`;
return callback(null, code);
return code;
}
// Note: we cache promises instead of strings
// This is because client/server compilations might be triggered in parallel
// When this happens for the same file, we don't want to compile it twice
async function loadMDXWithCaching({
resource,
fileContent,
filePath,
options,
compilerName,
}: {
resource: string; // path?query#hash
filePath: string; // path
fileContent: string;
options: Options;
compilerName: WebpackCompilerName;
}): Promise<string> {
// Note we "resource" as cache key, not "filePath" nor "fileContent"
// This is because:
// - the same file can be compiled in different variants (blog.mdx?truncated)
// - the same content can be processed differently (versioned docs links)
const cacheKey = resource;
const cachedPromise = options.crossCompilerCache?.get(cacheKey);
if (cachedPromise) {
// We can clean up the cache and free memory here
// We know there are only 2 compilations for the same file
// Note: once we introduce RSCs we'll probably have 3 compilations
// Note: we can't use string keys in WeakMap
// But we could eventually use WeakRef for the values
options.crossCompilerCache?.delete(cacheKey);
return cachedPromise;
}
const promise = loadMDX({
fileContent,
filePath,
options,
compilerName,
});
options.crossCompilerCache?.set(cacheKey, promise);
return promise;
}
export async function mdxLoader(
this: LoaderContext<Options>,
fileContent: string,
): Promise<void> {
const compilerName = getWebpackLoaderCompilerName(this);
const callback = this.async();
const options: Options = this.getOptions();
try {
const result = await loadMDXWithCaching({
resource: this.resource,
filePath: this.resourcePath,
fileContent,
options,
compilerName,
});
return callback(null, result);
} catch (error) {
return callback(error as Error);
}
}

View file

@ -0,0 +1,29 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type {MDXOptions, SimpleProcessors} from './processor';
import type {MarkdownConfig} from '@docusaurus/types';
import type {ResolveMarkdownLink} from './remark/resolveMarkdownLinks';
export type Options = Partial<MDXOptions> & {
markdownConfig: MarkdownConfig;
staticDirs: string[];
siteDir: string;
isMDXPartial?: (filePath: string) => boolean;
isMDXPartialFrontMatterWarningDisabled?: boolean;
removeContentTitle?: boolean;
metadataPath?: (filePath: string) => string;
createAssets?: (metadata: {
filePath: string;
frontMatter: {[key: string]: unknown};
}) => {[key: string]: unknown};
resolveMarkdownLink?: ResolveMarkdownLink;
// Will usually be created by "createMDXLoaderItem"
processors?: SimpleProcessors;
crossCompilerCache?: Map<string, Promise<string>>; // MDX => Promise<JSX> cache
};

View file

@ -11,7 +11,7 @@ import {
admonitionTitleToDirectiveLabel,
} from '@docusaurus/utils';
import {normalizeAdmonitionOptions} from './remark/admonitions';
import type {Options} from './loader';
import type {Options} from './options';
/**
* Preprocess the string before passing it to MDX

View file

@ -20,7 +20,7 @@ import codeCompatPlugin from './remark/mdx1Compat/codeCompatPlugin';
import {getFormat} from './format';
import type {WebpackCompilerName} from '@docusaurus/utils';
import type {MDXFrontMatter} from './frontMatter';
import type {Options} from './loader';
import type {Options} from './options';
import type {AdmonitionOptions} from './remark/admonitions';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721

View file

@ -10,7 +10,7 @@ import {escapePath, type WebpackCompilerName} from '@docusaurus/utils';
import {getProcessor, type SimpleProcessorResult} from './processor';
import {validateMDXFrontMatter} from './frontMatter';
import preprocessor from './preprocessor';
import type {Options} from './loader';
import type {Options} from './options';
/**
* Converts assets an object with Webpack require calls code.

View file

@ -13,6 +13,7 @@ import {
getFileCommitDate,
LAST_UPDATE_FALLBACK,
} from '@docusaurus/utils';
import {DEFAULT_FUTURE_CONFIG} from '@docusaurus/core/src/server/configValidation';
import pluginContentBlog from '../index';
import {validateOptions} from '../options';
import type {
@ -106,7 +107,7 @@ const getPlugin = async (
baseUrl: '/',
url: 'https://docusaurus.io',
markdown,
future: {},
future: DEFAULT_FUTURE_CONFIG,
staticDirectories: ['static'],
} as DocusaurusConfig;
return pluginContentBlog(

View file

@ -21,10 +21,7 @@ import {
resolveMarkdownLinkPathname,
} from '@docusaurus/utils';
import {getTagsFilePathsToWatch} from '@docusaurus/utils-validation';
import {
createMDXLoaderItem,
type Options as MDXLoaderOptions,
} from '@docusaurus/mdx-loader';
import {createMDXLoaderItem} from '@docusaurus/mdx-loader';
import {
getBlogTags,
paginateBlogPosts,
@ -114,7 +111,9 @@ export default async function pluginContentBlog(
const contentDirs = getContentPathList(contentPaths);
const loaderOptions: MDXLoaderOptions = {
const mdxLoaderItem = await createMDXLoaderItem({
useCrossCompilerCache:
siteConfig.future.experimental_faster.mdxCrossCompilerCache,
admonitions,
remarkPlugins,
rehypePlugins,
@ -168,7 +167,7 @@ export default async function pluginContentBlog(
}
return permalink;
},
};
});
function createBlogMarkdownLoader(): RuleSetUseItem {
const markdownLoaderOptions: BlogMarkdownLoaderOptions = {
@ -185,10 +184,7 @@ export default async function pluginContentBlog(
include: contentDirs
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator),
use: [
await createMDXLoaderItem(loaderOptions),
createBlogMarkdownLoader(),
],
use: [mdxLoaderItem, createBlogMarkdownLoader()],
};
}

View file

@ -25,10 +25,7 @@ import {
getTagsFile,
getTagsFilePathsToWatch,
} from '@docusaurus/utils-validation';
import {
createMDXLoaderRule,
type Options as MDXLoaderOptions,
} from '@docusaurus/mdx-loader';
import {createMDXLoaderRule} from '@docusaurus/mdx-loader';
import {loadSidebars, resolveSidebarPathOption} from './sidebars';
import {CategoryMetadataFilenamePattern} from './sidebars/generator';
import {
@ -107,50 +104,56 @@ export default async function pluginContentDocs(
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator);
const loaderOptions: MDXLoaderOptions = {
admonitions: options.admonitions,
remarkPlugins,
rehypePlugins,
recmaPlugins,
beforeDefaultRehypePlugins,
beforeDefaultRemarkPlugins,
staticDirs: siteConfig.staticDirectories.map((dir) =>
path.resolve(siteDir, dir),
),
siteDir,
isMDXPartial: createAbsoluteFilePathMatcher(options.exclude, contentDirs),
metadataPath: (mdxPath: string) => {
// Note that metadataPath must be the same/in-sync as
// the path from createData for each MDX.
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
return path.join(dataDir, `${docuHash(aliasedPath)}.json`);
return createMDXLoaderRule({
include: contentDirs,
options: {
useCrossCompilerCache:
siteConfig.future.experimental_faster.mdxCrossCompilerCache,
admonitions: options.admonitions,
remarkPlugins,
rehypePlugins,
recmaPlugins,
beforeDefaultRehypePlugins,
beforeDefaultRemarkPlugins,
staticDirs: siteConfig.staticDirectories.map((dir) =>
path.resolve(siteDir, dir),
),
siteDir,
isMDXPartial: createAbsoluteFilePathMatcher(
options.exclude,
contentDirs,
),
metadataPath: (mdxPath: string) => {
// Note that metadataPath must be the same/in-sync as
// the path from createData for each MDX.
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
return path.join(dataDir, `${docuHash(aliasedPath)}.json`);
},
// createAssets converts relative paths to require() calls
createAssets: ({frontMatter}: {frontMatter: DocFrontMatter}) => ({
image: frontMatter.image,
}),
markdownConfig: siteConfig.markdown,
resolveMarkdownLink: ({linkPathname, sourceFilePath}) => {
const version = getVersionFromSourceFilePath(
sourceFilePath,
versionsMetadata,
);
const permalink = resolveMarkdownLinkPathname(linkPathname, {
sourceFilePath,
sourceToPermalink: contentHelpers.sourceToPermalink,
siteDir,
contentPaths: version,
});
if (permalink === null) {
logger.report(
siteConfig.onBrokenMarkdownLinks,
)`Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
}
return permalink;
},
},
// createAssets converts relative paths to require() calls
createAssets: ({frontMatter}: {frontMatter: DocFrontMatter}) => ({
image: frontMatter.image,
}),
markdownConfig: siteConfig.markdown,
resolveMarkdownLink: ({linkPathname, sourceFilePath}) => {
const version = getVersionFromSourceFilePath(
sourceFilePath,
versionsMetadata,
);
const permalink = resolveMarkdownLinkPathname(linkPathname, {
sourceFilePath,
sourceToPermalink: contentHelpers.sourceToPermalink,
siteDir,
contentPaths: version,
});
if (permalink === null) {
logger.report(
siteConfig.onBrokenMarkdownLinks,
)`Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
}
return permalink;
},
};
return createMDXLoaderRule({include: contentDirs, options: loaderOptions});
});
}
const docsMDXLoaderRule = await createDocsMDXLoaderRule();

View file

@ -14,10 +14,7 @@ import {
createAbsoluteFilePathMatcher,
DEFAULT_PLUGIN_ID,
} from '@docusaurus/utils';
import {
createMDXLoaderRule,
type Options as MDXLoaderOptions,
} from '@docusaurus/mdx-loader';
import {createMDXLoaderRule} from '@docusaurus/mdx-loader';
import {createAllRoutes} from './routes';
import {
createPagesContentPaths,
@ -57,36 +54,39 @@ export default async function pluginContentPages(
} = options;
const contentDirs = getContentPathList(contentPaths);
const loaderOptions: MDXLoaderOptions = {
admonitions,
remarkPlugins,
rehypePlugins,
recmaPlugins,
beforeDefaultRehypePlugins,
beforeDefaultRemarkPlugins,
staticDirs: siteConfig.staticDirectories.map((dir) =>
path.resolve(siteDir, dir),
),
siteDir,
isMDXPartial: createAbsoluteFilePathMatcher(options.exclude, contentDirs),
metadataPath: (mdxPath: string) => {
// Note that metadataPath must be the same/in-sync as
// the path from createData for each MDX.
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
return path.join(dataDir, `${docuHash(aliasedSource)}.json`);
},
// createAssets converts relative paths to require() calls
createAssets: ({frontMatter}: {frontMatter: PageFrontMatter}) => ({
image: frontMatter.image,
}),
markdownConfig: siteConfig.markdown,
};
return createMDXLoaderRule({
include: contentDirs
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator),
options: loaderOptions,
options: {
useCrossCompilerCache:
siteConfig.future.experimental_faster.mdxCrossCompilerCache,
admonitions,
remarkPlugins,
rehypePlugins,
recmaPlugins,
beforeDefaultRehypePlugins,
beforeDefaultRemarkPlugins,
staticDirs: siteConfig.staticDirectories.map((dir) =>
path.resolve(siteDir, dir),
),
siteDir,
isMDXPartial: createAbsoluteFilePathMatcher(
options.exclude,
contentDirs,
),
metadataPath: (mdxPath: string) => {
// Note that metadataPath must be the same/in-sync as
// the path from createData for each MDX.
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
return path.join(dataDir, `${docuHash(aliasedSource)}.json`);
},
// createAssets converts relative paths to require() calls
createAssets: ({frontMatter}: {frontMatter: PageFrontMatter}) => ({
image: frontMatter.image,
}),
markdownConfig: siteConfig.markdown,
},
});
}

View file

@ -126,6 +126,7 @@ export type StorageConfig = {
export type FasterConfig = {
swcJsLoader: boolean;
swcJsMinimizer: boolean;
mdxCrossCompilerCache: boolean;
};
export type FutureConfig = {

View file

@ -9,6 +9,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -74,6 +75,7 @@ exports[`loadSiteConfig website with ts + js config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -139,6 +141,7 @@ exports[`loadSiteConfig website with valid JS CJS config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -204,6 +207,7 @@ exports[`loadSiteConfig website with valid JS ESM config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -269,6 +273,7 @@ exports[`loadSiteConfig website with valid TypeScript CJS config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -334,6 +339,7 @@ exports[`loadSiteConfig website with valid TypeScript ESM config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -399,6 +405,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -466,6 +473,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -533,6 +541,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},
@ -603,6 +612,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
"favicon": "img/docusaurus.ico",
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},

View file

@ -79,6 +79,7 @@ exports[`load loads props for site with custom i18n path 1`] = `
"customFields": {},
"future": {
"experimental_faster": {
"mdxCrossCompilerCache": false,
"swcJsLoader": false,
"swcJsMinimizer": false,
},

View file

@ -48,6 +48,7 @@ describe('normalizeConfig', () => {
experimental_faster: {
swcJsLoader: true,
swcJsMinimizer: true,
mdxCrossCompilerCache: true,
},
experimental_storage: {
type: 'sessionStorage',
@ -743,6 +744,7 @@ describe('future', () => {
experimental_faster: {
swcJsLoader: true,
swcJsMinimizer: true,
mdxCrossCompilerCache: true,
},
experimental_storage: {
type: 'sessionStorage',
@ -1091,6 +1093,8 @@ describe('future', () => {
it('accepts faster - full', () => {
const faster: FasterConfig = {
swcJsLoader: true,
swcJsMinimizer: true,
mdxCrossCompilerCache: true,
};
expect(
normalizeConfig({
@ -1202,6 +1206,7 @@ describe('future', () => {
`);
});
});
describe('swcJsMinimizer', () => {
it('accepts - undefined', () => {
const faster: Partial<FasterConfig> = {
@ -1272,5 +1277,76 @@ describe('future', () => {
`);
});
});
describe('mdxCrossCompilerCache', () => {
it('accepts - undefined', () => {
const faster: Partial<FasterConfig> = {
mdxCrossCompilerCache: undefined,
};
expect(
normalizeConfig({
future: {
experimental_faster: faster,
},
}),
).toEqual(fasterContaining({mdxCrossCompilerCache: false}));
});
it('accepts - true', () => {
const faster: Partial<FasterConfig> = {
mdxCrossCompilerCache: true,
};
expect(
normalizeConfig({
future: {
experimental_faster: faster,
},
}),
).toEqual(fasterContaining({mdxCrossCompilerCache: true}));
});
it('accepts - false', () => {
const faster: Partial<FasterConfig> = {
mdxCrossCompilerCache: false,
};
expect(
normalizeConfig({
future: {
experimental_faster: faster,
},
}),
).toEqual(fasterContaining({mdxCrossCompilerCache: false}));
});
it('rejects - null', () => {
// @ts-expect-error: invalid
const faster: Partial<FasterConfig> = {mdxCrossCompilerCache: 42};
expect(() =>
normalizeConfig({
future: {
experimental_faster: faster,
},
}),
).toThrowErrorMatchingInlineSnapshot(`
""future.experimental_faster.mdxCrossCompilerCache" must be a boolean
"
`);
});
it('rejects - number', () => {
// @ts-expect-error: invalid
const faster: Partial<FasterConfig> = {mdxCrossCompilerCache: 42};
expect(() =>
normalizeConfig({
future: {
experimental_faster: faster,
},
}),
).toThrowErrorMatchingInlineSnapshot(`
""future.experimental_faster.mdxCrossCompilerCache" must be a boolean
"
`);
});
});
});
});

View file

@ -44,12 +44,14 @@ export const DEFAULT_STORAGE_CONFIG: StorageConfig = {
export const DEFAULT_FASTER_CONFIG: FasterConfig = {
swcJsLoader: false,
swcJsMinimizer: false,
mdxCrossCompilerCache: false,
};
// When using the "faster: true" shortcut
export const DEFAULT_FASTER_CONFIG_TRUE: FasterConfig = {
swcJsLoader: true,
swcJsMinimizer: true,
mdxCrossCompilerCache: true,
};
export const DEFAULT_FUTURE_CONFIG: FutureConfig = {
@ -217,6 +219,9 @@ const FASTER_CONFIG_SCHEMA = Joi.alternatives()
swcJsMinimizer: Joi.boolean().default(
DEFAULT_FASTER_CONFIG.swcJsMinimizer,
),
mdxCrossCompilerCache: Joi.boolean().default(
DEFAULT_FASTER_CONFIG.mdxCrossCompilerCache,
),
}),
Joi.boolean()
.required()

View file

@ -8,6 +8,7 @@
import path from 'path';
import {fromPartial} from '@total-typescript/shoehorn';
import {loadPlugins, reloadPlugin} from '../plugins';
import {DEFAULT_FUTURE_CONFIG} from '../../configValidation';
import type {LoadContext, Plugin, PluginConfig} from '@docusaurus/types';
async function testLoad({
@ -27,6 +28,7 @@ async function testLoad({
siteConfig: {
baseUrl: '/',
trailingSlash: true,
future: DEFAULT_FUTURE_CONFIG,
themeConfig: {},
staticDirectories: [],
presets: [],

View file

@ -80,6 +80,8 @@ export async function createMDXFallbackPlugin({
siteConfig,
}: LoadContext): Promise<InitializedPlugin> {
const mdxLoaderItem = await createMDXLoaderItem({
useCrossCompilerCache:
siteConfig.future.experimental_faster.mdxCrossCompilerCache,
admonitions: true,
staticDirs: siteConfig.staticDirectories.map((dir) =>
path.resolve(siteDir, dir),