Skip to content

[docs-infra] Add a live demo provider - #1784

Draft
brijeshb42 wants to merge 1 commit into
di-migration-headless-sourcefrom
di-migration-live-demo-provider
Draft

[docs-infra] Add a live demo provider#1784
brijeshb42 wants to merge 1 commit into
di-migration-headless-sourcefrom
di-migration-live-demo-provider

Conversation

@brijeshb42

Copy link
Copy Markdown
Contributor

Tenth in the docs-infra migration stack, on top of #1783.

Live editing required a generated client.ts per demo: the loader wrote a file that called createDemoClient, which wired the externals and a controller together. A host that already produces static imports for its demos had no way to skip that step.

LiveDemoProvider is that way — it composes CodeExternalsContext, useDemoController, and CodeControllerContext into one component, so wrapping demos in it makes them live with no generated file:

<LiveDemoProvider externals={{ '@mui/material': Material }} globals={{ process: {} }}>
  <Demo />
</LiveDemoProvider>

globals is for identifiers a demo mentions at the top level rather than imports — process being the usual one, which would otherwise be a ReferenceError in the runner. They bind as locals in the runner's scope, making it { ...globals, import: externals }, the shape Material UI's runner already uses. Two properties worth stating: a global cannot displace the module registry the require shim reads (nor the always-injected React/require), and the host controls exactly what a demo sees — { process: {} } exposes nothing, so reaching for process.env.NODE_ENV throws and surfaces as that variant's error rather than taking the page down.

createDemoClient is unchanged. The strategy suggested reimplementing it through the provider "where practical"; it isn't, because it wraps a consumer-supplied DemoController rather than this one, and rerouting it would change behaviour for existing consumers.

Gate: 10 new unit tests (provider composition and context stability, globals reaching the runner scope, a bound global, a forbidden process property access), 5,579 unit tests, 39 browser tests across chromium, firefox, and webkit, plus a clean typecheck, lint, and docs:validate. The 41 user.spec.ts failures are the pre-existing ones.

@brijeshb42 brijeshb42 added the scope: docs-infra Involves the docs-infra product (https://www.notion.so/mui-org/b9f676062eb94747b6768209f7751305). label Aug 14, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy preview

Bundle size

Total Size Change: 🔺+5.76KB(+0.17%) - Total Gzip Change: 🔺+2.4KB(+0.27%)
Files: 72 total (1 added, 0 removed, 1 changed)

Show details for 72 more bundles

@mui/internal-docs-infra/useDemoControllerparsed: 🔺+24B(+0.44%) gzip: 🔺+17B(+0.75%)
@mui/internal-docs-infra/LiveDemoProviderparsed: 🔺+5.73KB(new) gzip: 🔺+2.38KB(new)
@mui/internal-docs-infra/abstractCreateDemoparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateDemoClientparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateStreamparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateTypesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/ChunkProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/cliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeControllerContextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeExternalsContextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighterparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/errorsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazyparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazy/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoDataparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoData/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemapparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemap/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCodeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCodeWindowparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCoordinatedparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCopierparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCrossTabStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useDemoparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useErrorsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useLocalStorageStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/usePreferenceparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useScrollAnchorparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearchparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearch/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStreamparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStream/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useTypeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useTypesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useUrlHashStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/withDocsInfraparsed: 0B(0.00%) gzip: 0B(0.00%)
addLineGuttersparsed: 0B(0.00%) gzip: 0B(0.00%)
BuildEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeContextparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeEditorparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterChunkparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterClientparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeInitialSourceLoaderparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeSourceLoaderparsed: 0B(0.00%) gzip: 0B(0.00%)
compileCssWithPostcssparsed: 0B(0.00%) gzip: 0B(0.00%)
createFrameparsed: 0B(0.00%) gzip: 0B(0.00%)
createParseSourceWorkerClientparsed: 0B(0.00%) gzip: 0B(0.00%)
EditingEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
embedTransformsparsed: 0B(0.00%) gzip: 0B(0.00%)
enhanceCodeEmphasisparsed: 0B(0.00%) gzip: 0B(0.00%)
findExpandingRangesparsed: 0B(0.00%) gzip: 0B(0.00%)
getHastTextContentparsed: 0B(0.00%) gzip: 0B(0.00%)
grammarLoadersparsed: 0B(0.00%) gzip: 0B(0.00%)
grammarsparsed: 0B(0.00%) gzip: 0B(0.00%)
isFrameSpanparsed: 0B(0.00%) gzip: 0B(0.00%)
loadIsomorphicCodeVariantparsed: 0B(0.00%) gzip: 0B(0.00%)
parseSourceparsed: 0B(0.00%) gzip: 0B(0.00%)
rolldown-runtimeparsed: 0B(0.00%) gzip: 0B(0.00%)
source.cssparsed: 0B(0.00%) gzip: 0B(0.00%)
source.jsparsed: 0B(0.00%) gzip: 0B(0.00%)
source.jsonparsed: 0B(0.00%) gzip: 0B(0.00%)
source.mdxparsed: 0B(0.00%) gzip: 0B(0.00%)
source.shellparsed: 0B(0.00%) gzip: 0B(0.00%)
source.tsparsed: 0B(0.00%) gzip: 0B(0.00%)
source.tsxparsed: 0B(0.00%) gzip: 0B(0.00%)
source.yamlparsed: 0B(0.00%) gzip: 0B(0.00%)
text.html.basicparsed: 0B(0.00%) gzip: 0B(0.00%)
text.mdparsed: 0B(0.00%) gzip: 0B(0.00%)
TransformEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
transpileSourceparsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Performance

Total duration: 16.85 ms +0.60 ms(+3.7%) | Renders: 5 (+0) | Paint: 61.06 ms +2.09 ms(+3.5%)

Test Duration Renders
DataGrid mount with paint timing 2.61 ms 🔺+0.47 ms(+22.0%) 1 (+0)

6 tests within noise — details


Check out the code infra dashboard for more information about this PR.

Live editing required a generated `client.ts` per demo: the loader wrote a
file that called `createDemoClient`, which wired the externals and a
controller together. A host that already produces static imports for its
demos had no way to skip that step.

`LiveDemoProvider` is that way. It composes `CodeExternalsContext`,
`useDemoController`, and `CodeControllerContext` into one component, so
wrapping demos in it makes them live with no generated file.

It also takes `globals`, for identifiers a demo mentions at the top level
rather than imports — `process` being the usual one, which would otherwise
be a `ReferenceError` in the runner. Globals bind as locals in the runner's
scope, making it `{ ...globals, import: externals }`, which matches the
shape Material UI's runner already uses. A global cannot displace the
module registry the `require` shim reads, and the host controls exactly
what a demo sees: `{ process: {} }` exposes nothing, so reaching for
`process.env.NODE_ENV` throws and is reported as that variant's error.

`createDemoClient` is unchanged. It wraps a consumer-supplied
`DemoController` rather than this one, so reimplementing it through the
provider would change behaviour for existing consumers.
@brijeshb42
brijeshb42 force-pushed the di-migration-headless-source branch from 9e45aac to b4dde9f Compare August 14, 2026 18:44
@brijeshb42
brijeshb42 force-pushed the di-migration-live-demo-provider branch from 5ed9f0e to c19fef3 Compare August 14, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: docs-infra Involves the docs-infra product (https://www.notion.so/mui-org/b9f676062eb94747b6768209f7751305).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant