Skip to content

Commit 6e246ec

Browse files
committed
[docs] Restore build-only invariant throws via NEXT_RUNTIME guard
PR mui#48365 introduced the `mui/no-guarded-throw` lint rule and removed the `if (process.env.NODE_ENV !== 'production')` wrappers around several throws in docs components, making those invariants throw at client render time. Restore the original "fail at build, not in the browser" semantics by guarding on `process.env.NEXT_RUNTIME` instead. The lint rule only matches `NODE_ENV` guards, and Next.js replaces `NEXT_RUNTIME` with `undefined` in client bundles, so the entire block is dead-code-eliminated from the browser. Also drop the explicit `'mui/no-guarded-throw': 'error'` override from `eslint.config.mjs` — the rule comes from the shared infra config.
1 parent 16363f3 commit 6e246ec

6 files changed

Lines changed: 61 additions & 49 deletions

File tree

docs/src/modules/components/TopLayoutBlog.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,16 @@ export default function TopLayoutBlog(props) {
347347
})
348348
.join(',')}&product=Blog`;
349349

350-
if (headers.manualCard === undefined) {
351-
throw new Error(
352-
[
353-
`MUI: the "manualCard" markdown header for the blog post "${slug}" is missing.`,
354-
`Set manualCard: true or manualCard: false header in docs/pages/blog/${slug}.md.`,
355-
].join('\n'),
356-
);
350+
// Guard with NEXT_RUNTIME so this check is dead-code-eliminated from client bundles.
351+
if (process.env.NEXT_RUNTIME) {
352+
if (headers.manualCard === undefined) {
353+
throw new Error(
354+
[
355+
`MUI: the "manualCard" markdown header for the blog post "${slug}" is missing.`,
356+
`Set manualCard: true or manualCard: false header in docs/pages/blog/${slug}.md.`,
357+
].join('\n'),
358+
);
359+
}
357360
}
358361

359362
return (

docs/src/modules/components/TopLayoutCaseStudy.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,16 @@ export default function TopLayoutCaseStudy(props) {
168168
const { canonicalAsServer } = pathnameToLanguage(router.asPath);
169169
const card = `/static/blog/${slug}/card.png`;
170170

171-
if (headers.manualCard === undefined) {
172-
throw new Error(
173-
[
174-
`MUI: the "manualCard" markdown header for the blog post "${slug}" is missing.`,
175-
`Set manualCard: true or manualCard: false header in docs/pages/blog/${slug}.md.`,
176-
].join('\n'),
177-
);
171+
// Guard with NEXT_RUNTIME so this check is dead-code-eliminated from client bundles.
172+
if (process.env.NEXT_RUNTIME) {
173+
if (headers.manualCard === undefined) {
174+
throw new Error(
175+
[
176+
`MUI: the "manualCard" markdown header for the blog post "${slug}" is missing.`,
177+
`Set manualCard: true or manualCard: false header in docs/pages/blog/${slug}.md.`,
178+
].join('\n'),
179+
);
180+
}
178181
}
179182

180183
return (

eslint.config.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ export default defineConfig(
9696
'react-hooks/incompatible-library': 'off',
9797
'react-hooks/static-components': 'off',
9898
'react-hooks/purity': 'off',
99-
100-
'mui/no-guarded-throw': 'error',
10199
},
102100
},
103101
...['mui-material', 'mui-system', 'mui-utils', 'mui-lab', 'mui-utils', 'mui-styled-engine'].map(

packages-internal/core-docs/src/AppLayout/components/AppFrameBanner.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ export function AppFrameBanner() {
4242
href = '/blog/introducing-mui-v9/';
4343
}
4444

45-
if (message.length > 100) {
46-
throw new Error(
47-
`Docs-infra: AppFrameBanner message is too long. It will overflow on smaller screens.`,
48-
);
45+
// Guard with NEXT_RUNTIME so this check is dead-code-eliminated from client bundles.
46+
if (process.env.NEXT_RUNTIME) {
47+
if (message.length > 100) {
48+
throw new Error(
49+
`Docs-infra: AppFrameBanner message is too long. It will overflow on smaller screens.`,
50+
);
51+
}
4952
}
5053

5154
if (message === '' || href === '') {

packages-internal/core-docs/src/AppLayout/navigation/AppNavDrawer.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,14 @@ export function AppNavDrawer(props: AppNavDrawerProps) {
481481
);
482482
}, [onClose, pages, activePageParents, t, productIdentifier, anchorEl, swipeableDrawer]);
483483

484-
if (!productIdentifier) {
485-
throw new Error('docs-infra: missing productIdentifier in PageContext');
486-
}
487-
488-
if (!productIdentifier.versions) {
489-
throw new Error('docs-infra: missing productIdentifier.versions in PageContext');
484+
// Guard with NEXT_RUNTIME so this check is dead-code-eliminated from client bundles.
485+
if (process.env.NEXT_RUNTIME) {
486+
if (!productIdentifier) {
487+
throw new Error('docs-infra: missing productIdentifier in PageContext');
488+
}
489+
if (!productIdentifier.versions) {
490+
throw new Error('docs-infra: missing productIdentifier.versions in PageContext');
491+
}
490492
}
491493

492494
return (

packages-internal/core-docs/src/Demo/Demo.tsx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -407,29 +407,32 @@ export interface DemoProps {
407407
export function Demo(props: DemoProps) {
408408
const { demo, demoOptions, disableAd, githubLocation, demoToolbarSlot: DemoToolbar } = props;
409409

410-
if (demoOptions.hideToolbar === false) {
411-
throw new Error(
412-
[
413-
'"hideToolbar": false is already the default.',
414-
`Please remove the property in {{"demo": "${demoOptions.demo}", …}}.`,
415-
].join('\n'),
416-
);
417-
}
418-
if (demoOptions.hideToolbar === true && demoOptions.defaultCodeOpen === true) {
419-
throw new Error(
420-
[
421-
'"hideToolbar": true, "defaultCodeOpen": true combination is invalid.',
422-
`Please remove one of the properties in {{"demo": "${demoOptions.demo}", …}}.`,
423-
].join('\n'),
424-
);
425-
}
426-
if (demoOptions.hideToolbar === true && demoOptions.disableAd === true) {
427-
throw new Error(
428-
[
429-
'"hideToolbar": true, "disableAd": true combination is invalid.',
430-
`Please remove one of the properties in {{"demo": "${demoOptions.demo}", …}}.`,
431-
].join('\n'),
432-
);
410+
// Guard with NEXT_RUNTIME so this check is dead-code-eliminated from client bundles.
411+
if (process.env.NEXT_RUNTIME) {
412+
if (demoOptions.hideToolbar === false) {
413+
throw new Error(
414+
[
415+
'"hideToolbar": false is already the default.',
416+
`Please remove the property in {{"demo": "${demoOptions.demo}", …}}.`,
417+
].join('\n'),
418+
);
419+
}
420+
if (demoOptions.hideToolbar === true && demoOptions.defaultCodeOpen === true) {
421+
throw new Error(
422+
[
423+
'"hideToolbar": true, "defaultCodeOpen": true combination is invalid.',
424+
`Please remove one of the properties in {{"demo": "${demoOptions.demo}", …}}.`,
425+
].join('\n'),
426+
);
427+
}
428+
if (demoOptions.hideToolbar === true && demoOptions.disableAd === true) {
429+
throw new Error(
430+
[
431+
'"hideToolbar": true, "disableAd": true combination is invalid.',
432+
`Please remove one of the properties in {{"demo": "${demoOptions.demo}", …}}.`,
433+
].join('\n'),
434+
);
435+
}
433436
}
434437

435438
if (

0 commit comments

Comments
 (0)