feat(core): add future.v4.mdx1CompatDisabledByDefault flag (#11896)

* add future.v4.mdx1CompatDisabledByDefault flag

* docs

* update snapshots

* add crowdin comment

* improve tests

* improve tests
This commit is contained in:
Sébastien Lorber
2026-04-03 19:13:09 +02:00
committed by GitHub
parent 00a8162834
commit 4892e7f257
8 changed files with 133 additions and 20 deletions
+1
View File
@@ -41,6 +41,7 @@ export type FutureV4Config = {
useCssCascadeLayers: boolean;
siteStorageNamespacing: boolean;
fasterByDefault: boolean;
mdx1CompatDisabledByDefault: boolean;
};
// VCS (Version Control System) info about a given change, e.g., a git commit.
+1
View File
@@ -21,6 +21,7 @@ export {
} from './config';
export {
MDX1CompatOptions,
MarkdownConfig,
MarkdownHooks,
DefaultParseFrontMatter,
@@ -27,6 +27,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -114,6 +115,7 @@ exports[`loadSiteConfig website with ts + js config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -201,6 +203,7 @@ exports[`loadSiteConfig website with valid JS CJS config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -288,6 +291,7 @@ exports[`loadSiteConfig website with valid JS ESM config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -375,6 +379,7 @@ exports[`loadSiteConfig website with valid TypeScript CJS config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -462,6 +467,7 @@ exports[`loadSiteConfig website with valid TypeScript ESM config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -549,6 +555,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -638,6 +645,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -727,6 +735,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -819,6 +828,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -107,6 +107,7 @@ exports[`loadSite custom-i18n-site loads site 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -282,6 +283,7 @@ exports[`loadSite simple-site-with-baseUrl loads site - custom config 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -449,6 +451,7 @@ exports[`loadSite simple-site-with-baseUrl loads site - custom outDir 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -616,6 +619,7 @@ exports[`loadSite simple-site-with-baseUrl loads site 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -827,6 +831,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale fr + custom
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -1060,6 +1065,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - custom outDir 1`] =
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -1293,6 +1299,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale de 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -1526,6 +1533,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale en 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -1759,6 +1767,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale es 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -1992,6 +2001,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale fr 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -2225,6 +2235,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site - locale it 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -2458,6 +2469,7 @@ exports[`loadSite simple-site-with-baseUrl-i18n loads site 1`] = `
},
"v4": {
"fasterByDefault": false,
"mdx1CompatDisabledByDefault": false,
"removeLegacyPostBuildHeadAttribute": false,
"siteStorageNamespacing": false,
"useCssCascadeLayers": false,
@@ -67,6 +67,7 @@ describe('normalizeConfig', () => {
useCssCascadeLayers: true,
siteStorageNamespacing: true,
fasterByDefault: true,
mdx1CompatDisabledByDefault: true,
},
faster: {
swcJsLoader: true,
@@ -513,6 +514,7 @@ describe('markdown', () => {
): MarkdownConfig {
return normalizeConfig({markdown}).markdown;
}
it('accepts undefined object', () => {
expect(normalizeMarkdown(undefined)).toEqual(DEFAULT_CONFIG.markdown);
});
@@ -1348,6 +1350,7 @@ describe('future', () => {
useCssCascadeLayers: true,
siteStorageNamespacing: true,
fasterByDefault: true,
mdx1CompatDisabledByDefault: true,
},
faster: {
swcJsLoader: true,
@@ -2566,6 +2569,7 @@ describe('future', () => {
useCssCascadeLayers: true,
siteStorageNamespacing: true,
fasterByDefault: true,
mdx1CompatDisabledByDefault: true,
};
expect(
normalizeConfig({
@@ -2906,5 +2910,64 @@ describe('future', () => {
`);
});
});
describe('mdx1CompatDisabledByDefault', () => {
function mdx1CompatContaining(mdx1Compat: object) {
return expect.objectContaining({
markdown: expect.objectContaining({mdx1Compat}),
});
}
const MDX1_COMPAT_ALL_TRUE = {
comments: true,
admonitions: true,
headingIds: true,
};
const MDX1_COMPAT_ALL_FALSE = {
comments: false,
admonitions: false,
headingIds: false,
};
it('defaults mdx1Compat to all true when flag is off', () => {
expect(normalizeConfig({})).toEqual(
mdx1CompatContaining(MDX1_COMPAT_ALL_TRUE),
);
});
it('defaults mdx1Compat to all false when flag is on', () => {
expect(
normalizeConfig({
future: {v4: {mdx1CompatDisabledByDefault: true}},
}),
).toEqual(mdx1CompatContaining(MDX1_COMPAT_ALL_FALSE));
});
it('defaults mdx1Compat to all false when v4: true', () => {
expect(
normalizeConfig({
future: {v4: true},
}),
).toEqual(mdx1CompatContaining(MDX1_COMPAT_ALL_FALSE));
});
it('keeps explicit mdx1Compat overrides when flag is on', () => {
expect(
normalizeConfig({
future: {v4: {mdx1CompatDisabledByDefault: true}},
markdown: {
mdx1Compat: {admonitions: true},
},
}),
).toEqual(
mdx1CompatContaining({
comments: false,
admonitions: true,
headingIds: false,
}),
);
});
});
});
});
@@ -26,6 +26,7 @@ import type {
FutureV4Config,
I18nConfig,
I18nLocaleConfig,
MDX1CompatOptions,
MarkdownConfig,
MarkdownHooks,
StorageConfig,
@@ -102,6 +103,7 @@ export const DEFAULT_FUTURE_V4_CONFIG: FutureV4Config = {
useCssCascadeLayers: false,
siteStorageNamespacing: false,
fasterByDefault: false,
mdx1CompatDisabledByDefault: false,
};
// When using the "v4: true" shortcut
@@ -110,6 +112,7 @@ export const DEFAULT_FUTURE_V4_CONFIG_TRUE: FutureV4Config = {
useCssCascadeLayers: true,
siteStorageNamespacing: true,
fasterByDefault: true,
mdx1CompatDisabledByDefault: true,
};
export const DEFAULT_FUTURE_CONFIG: FutureConfig = {
@@ -124,17 +127,22 @@ export const DEFAULT_MARKDOWN_HOOKS: MarkdownHooks = {
onBrokenMarkdownImages: 'throw',
};
export const DEFAULT_MARKDOWN_MDX1COMPAT: MDX1CompatOptions = {
comments: true,
admonitions: true,
headingIds: true,
};
export const DEFAULT_MARKDOWN_CONFIG: MarkdownConfig = {
format: 'mdx', // TODO change this to "detect" in Docusaurus v4?
// TODO Docusaurus v5: change this to "detect"?
// we probably need stable CommonMark support first
// see https://github.com/facebook/docusaurus/issues/9092
format: 'mdx',
mermaid: false,
emoji: true,
preprocessor: undefined,
parseFrontMatter: DEFAULT_PARSE_FRONT_MATTER,
mdx1Compat: {
comments: true,
admonitions: true,
headingIds: true,
},
mdx1Compat: DEFAULT_MARKDOWN_MDX1COMPAT,
anchors: {
maintainCase: false,
},
@@ -319,6 +327,9 @@ const FUTURE_V4_SCHEMA = Joi.alternatives()
fasterByDefault: Joi.boolean().default(
DEFAULT_FUTURE_V4_CONFIG.fasterByDefault,
),
mdx1CompatDisabledByDefault: Joi.boolean().default(
DEFAULT_FUTURE_V4_CONFIG.mdx1CompatDisabledByDefault,
),
}),
Joi.boolean()
.required()
@@ -511,17 +522,14 @@ export const ConfigSchema = Joi.object<DocusaurusConfig>({
.arity(1)
.optional()
.default(() => DEFAULT_CONFIG.markdown.preprocessor),
// Individual boolean defaults are not set here on purpose
// They are resolved in postProcessDocusaurusConfig based on
// the future.v4.mdx1CompatDisabledByDefault flag
mdx1Compat: Joi.object({
comments: Joi.boolean().default(
DEFAULT_CONFIG.markdown.mdx1Compat.comments,
),
admonitions: Joi.boolean().default(
DEFAULT_CONFIG.markdown.mdx1Compat.admonitions,
),
headingIds: Joi.boolean().default(
DEFAULT_CONFIG.markdown.mdx1Compat.headingIds,
),
}).default(DEFAULT_CONFIG.markdown.mdx1Compat),
comments: Joi.boolean(),
admonitions: Joi.boolean(),
headingIds: Joi.boolean(),
}).default({}),
remarkRehypeOptions:
// add proper external options validation?
// Not sure if it's a good idea, validation is likely to become stale
@@ -546,7 +554,12 @@ export const ConfigSchema = Joi.object<DocusaurusConfig>({
)
.default(DEFAULT_CONFIG.markdown.hooks.onBrokenMarkdownImages),
}).default(DEFAULT_CONFIG.markdown.hooks),
}).default(DEFAULT_CONFIG.markdown),
}).default({
...DEFAULT_CONFIG.markdown,
mdx1Compat: {
// erased on purpose, filled using postprocessing
},
}),
}).messages({
'docusaurus.configValidationWarning':
'Docusaurus config validation warning. Field {#label}: {#warningMessage}',
@@ -576,6 +589,16 @@ function postProcessDocusaurusConfig(config: DocusaurusConfig) {
}
}
// Resolve mdx1Compat config based on the v4.mdx1CompatDisabledByDefault flag
// undefined means "not explicitly set by user"
const mdx1CompatDefault = !config.future.v4.mdx1CompatDisabledByDefault;
const mdx1CompatKeys = Object.keys(
DEFAULT_MARKDOWN_MDX1COMPAT,
) as (keyof MDX1CompatOptions)[];
for (const key of mdx1CompatKeys) {
config.markdown.mdx1Compat[key] ??= mdx1CompatDefault;
}
if (config.onBrokenMarkdownLinks) {
logger.warn`The code=${'siteConfig.onBrokenMarkdownLinks'} config option is deprecated and will be removed in Docusaurus v4.
Please migrate and move this option to code=${'siteConfig.markdown.hooks.onBrokenMarkdownLinks'} instead.`;
+3 -1
View File
@@ -254,6 +254,7 @@ export default {
useCssCascadeLayers: true,
siteStorageNamespacing: true,
fasterByDefault: true,
mdx1CompatDisabledByDefault: true,
},
faster: {
swcJsLoader: true,
@@ -275,6 +276,7 @@ export default {
- [`useCssCascadeLayers`](https://github.com/facebook/docusaurus/pull/11142): This enables the [Docusaurus CSS Cascade Layers plugin](./plugins/plugin-css-cascade-layers.mdx) with pre-configured layers that we plan to apply by default for Docusaurus v4.
- `siteStorageNamespacing`: Defaults the [`storage.namespace`](#storage) config to `true` instead of `false`. This enables automatic browser storage key namespacing, which avoids storage key conflicts when multiple Docusaurus sites are hosted under the same domain, or on localhost.
- `fasterByDefault`: Defaults all `future.faster` flags to `true` instead of `false`. This enables [Docusaurus Faster](https://github.com/facebook/docusaurus/issues/10556) features by default. Requires having `@docusaurus/faster` in your dependencies. If you explicitly set individual `faster` flags, those explicit values take precedence.
- `mdx1CompatDisabledByDefault`: Defaults all [`markdown.mdx1Compat`](#markdown) flags to `false` instead of `true`. This prepares your site for Docusaurus v4, which will not enable MDX v1 compatibility by default. If you explicitly set individual `mdx1Compat` flags, those explicit values take precedence.
- `faster`: An object containing feature flags to make the Docusaurus build faster. This requires adding the `@docusaurus/faster` package to your site's dependencies. Use `true` as a shorthand to enable all flags. Read more on the [Docusaurus Faster](https://github.com/facebook/docusaurus/issues/10556) issue. Available feature flags:
- [`swcJsLoader`](https://github.com/facebook/docusaurus/pull/10435): Use [SWC](https://swc.rs/) to transpile JS (instead of [Babel](https://babeljs.io/)).
- [`swcJsMinimizer`](https://github.com/facebook/docusaurus/pull/10441): Use [SWC](https://swc.rs/) to minify JS (instead of [Terser](https://github.com/terser/terser)).
@@ -734,7 +736,7 @@ export default {
| `emoji` | `boolean` | `true` | When `true`, allows Docusaurus to render emoji shortcodes (e.g., `:+1:`) as Unicode emoji (👍). When `false`, emoji shortcodes are left as-is. |
| `preprocessor` | `MarkdownPreprocessor` | `undefined` | Gives you the ability to alter the Markdown content string before parsing. Use it as a last-resort escape hatch or workaround: it is almost always better to implement a Remark/Rehype plugin. |
| `parseFrontMatter` | `ParseFrontMatter` | `undefined` | Gives you the ability to provide your own front matter parser, or to enhance the default parser. Read our [front matter guide](../guides/markdown-features/markdown-features-intro.mdx#front-matter) for details. |
| `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. |
| `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. Defaults to all `false` when [`future.v4.mdx1CompatDisabledByDefault`](#future) is enabled. |
| `anchors` | `MarkdownAnchorsConfig` | `{maintainCase: false}` | Options to control the behavior of anchors generated from Markdown headings |
| `remarkRehypeOptions` | `object` | `undefined` | Makes it possible to pass custom [`remark-rehype` options](https://github.com/remarkjs/remark-rehype#options). |
| `hooks` | `MarkdownHooks` | `object` | Make it possible to customize the MDX loader behavior with callbacks or built-in options. |
+3 -2
View File
@@ -234,8 +234,9 @@ export default async function createConfigAsync() {
onBrokenMarkdownLinks: 'warn',
},
mdx1Compat: {
headingIds: false,
comments: false,
// Needed for us until Crowdin improves support
// See https://github.com/facebook/docusaurus/pull/11847#issuecomment-4183213345
admonitions: true,
},
remarkRehypeOptions: {
footnoteLabel: getLocalizedConfigValue('remarkRehypeOptions_footnotes'),