Skip to content

[docs] POC: wire @mui/internal-docs-infra types pipeline into API pages#22091

Draft
JCQuintas wants to merge 5 commits intomui:masterfrom
JCQuintas:docs-apitest-infra
Draft

[docs] POC: wire @mui/internal-docs-infra types pipeline into API pages#22091
JCQuintas wants to merge 5 commits intomui:masterfrom
JCQuintas:docs-apitest-infra

Conversation

@JCQuintas
Copy link
Copy Markdown
Member

Summary

Proof-of-concept wiring of the new @mui/internal-docs-infra types pipeline into mui-x API docs pages. Ports the base-ui pattern (mui/base-ui#2932) to generate per-component API docs from TypeScript types at build time instead of from the legacy runtime propTypes walker.

Scope: 294 API pages across charts, data-grid, date-pickers, tree-view, chat, scheduler, chat-box. Each page is a thin <TypesPageShell> wrapper around a generated types.<slug>.ts that calls createTypes(import.meta.url, Component) — rewritten at build time by the loadPrecomputedTypes webpack loader.

What's in this branch:

  • docs/src/modules/api-docs/createTypes.tsx + ReferenceTable.tsx + TypesPageShell.tsx — mui-x-side factory and renderer.
  • 294 generated types.*.ts / page .js pairs under docs/pages/x/api/**.
  • docs/src/modules/api-docs/typesRegistry.jsonname → url map used to collapse additional types that have their own page into a compact "Related:" link row.
  • docs/next.config.ts — webpack rule matching types.*.ts, React dedupe aliases, @mui/internal-docs-infra in transpilePackages.
  • tsconfig.json — flattened (previously extended @mui/monorepo/tsconfig.json), since the loader's loadTypescriptConfig walk chokes on node_modules package specifiers.
  • pnpm-workspace.yaml / package.json — TS 6.0.2 bump + (when iterating locally) link: overrides for the upstream extractor / docs-infra packages.

Known limitations — POC, not ready to merge:

What's verified:

  • 294 pages render with the expected component / hook / function / class / raw layouts.
  • Props list matches the legacy builder output for every verified family (charts, data-grid, pickers, tree-view).
  • pnpm eslint is clean across the generated tree.

Experimental port of base-ui PR mui#2932's approach to mui-x:

- Per-page `types.<slug>.ts` entry colocated with the API page. Calls
  `createTypes(import.meta.url, Gauge)` which the webpack loader
  `@mui/internal-docs-infra/pipeline/loadPrecomputedTypes` rewrites at
  build time with fully-resolved component type metadata.
- `docs/src/modules/api-docs/createTypes.tsx` factory binds mui-x's
  placeholder `ReferenceTable` to the shared docs-infra pipeline via
  `createTypesFactory` / `createMultipleTypesFactory`.
- `docs/src/modules/api-docs/ReferenceTable.tsx` — minimal POC renderer;
  not styled to match ApiPage yet, just dumps props to a `<table>`.
- `docs/next.config.ts` — webpack rule matching
  `docs/pages/x/api/**/types.*.ts` and piping through
  `loadPrecomputedTypes` after the default babel loader.
- `docs/pages/x/api/charts/gauge.js` — swapped out for a thin wrapper
  that renders `<TypesGauge />` instead of reading `gauge.json`.
- `tsconfig.json` — `extends` changed from `@mui/monorepo/tsconfig.json`
  to `./node_modules/@mui/monorepo/tsconfig.json`. The docs-infra
  loader's extends resolver uses `path.resolve(projectPath, raw.extends)`
  and can't handle node_modules package specifiers (upstream bug).

Results (local `pnpm dev`):
- Gauge page compiles in ~8s on cold load, ~140ms on subsequent reloads.
- `createMultipleTypes` form didn't populate `type.props` for a single
  non-namespace component — had to drop to `createTypes` (singular).
- 22 Gauge props resolved (value, cornerRadius, startAngle, endAngle,
  width, height, sx, classes, etc.) and rendered in the POC table.

Known limitations (POC scope, deliberately out of scope):
- DataGrid is too large: extraction took ~99s before hitting a wasm
  RuntimeError / memory-access-out-of-bounds. TS Language Service can't
  handle its full inheritance chain at this size.
- Events, selectors, interface pages, exports, grid-api: untouched.
- ReferenceTable is a placeholder — no styling, no slot/class sections,
  no mdx/description rendering beyond raw ReactNode.
- `types.*.md` sidecar files are generated by the loader and currently
  committed; should move to .gitignore once the approach is validated.
- Translation JSON files are unused by the new page.
Inline the compilerOptions previously inherited via
`extends: "@mui/monorepo/tsconfig.json"` so the root tsconfig is
self-contained. Unblocks `@mui/internal-docs-infra/pipeline/loadPrecomputedTypes`,
whose `loadTypescriptConfig` walk resolves `extends` as a literal
relative path and can't handle node_modules package specifiers.

Inlined from monorepo tsconfig:
  target, forceConsistentCasingInFileNames, noEmit, module,
  experimentalDecorators, allowSyntheticDefaultImports, noErrorTruncation.

Not inlined (already explicitly set by mui-x): lib, jsx, strict, allowJs,
moduleResolution. Dropped entirely: the monorepo's `paths` map for
`@mui/material`, `@mui/lab`, `@mui/system`, etc. — mui-x installs those
as real packages so TS resolves them via node_modules without mapping.

Verified: `tsc` passes cleanly for x-charts, x-data-grid, x-date-pickers,
x-tree-view. `pnpm docs:api`-equivalent Gauge POC still resolves 22 props
via the new types pipeline in ~8s cold / ~140ms warm.
Adds a DataGrid `types.data-grid.ts` entry as a POC repro and a
diagnosis writeup at `scripts/docs-infra-oom-repro.md`.

Root cause: `formatInlineTypeAsHast` in
`@mui/internal-docs-infra/pipeline/loadServerTypes/typeHighlighting.mjs`
is not memoized. For DataGrid, instrumentation showed:

  - 1947 total calls
  - 5 unique input strings
  - each call re-runs Oniguruma's TextMate regex VM on the same text

Oniguruma runs inside a fixed-size WASM linear memory buffer. Repeated
allocations on identical inputs fragment the heap until it overruns
with `RuntimeError: memory access out of bounds` at
wasm://wasm/001ce0fe — which is the vscode-oniguruma wasm blob used
by @wooorm/starry-night, not tsgo as first suspected.

Upstream fix filed as mui-public branch
`jcquintas/fix-highlightTypes-memoization` (commit e60dafa2). Wraps
formatInlineTypeAsHast with a process-lifetime `Map` keyed on
`(unionPrintWidth, typeText)` plus a structuredClone on read so
downstream mutations don't poison the cache. Adds 4 regression tests
under `typeHighlighting > memoization`.

Verified end-to-end with the same patch applied locally to mui-x's
installed node_modules copy:

  /x/api/data-grid/data-grid   63s (was: crash after ~100s)
  /x/api/charts/gauge          8s cold / 140ms warm (unchanged)

Separate issues surfaced while investigating (filed/to-file separately):

1. typescript-api-extractor/dist/parsers/typeResolver.js:295 silently
   downgrades TypeFlag.TemplateLiteral types to `any`. Correctness bug.

2. DataGrid's extracted shape is wrong even with the OOM fixed. Only
   surfaces 1 prop (`pagination`) and ~40 `BasePropsOverrides`
   augmentation interfaces. The generic ForwardRefExoticComponent
   signature isn't being instantiated to its resolved prop type.

3. loadTypescriptConfig.mts `extends` resolver — already worked around
   in commit efe32b0 (root tsconfig flattening).
@mui-bot
Copy link
Copy Markdown

mui-bot commented Apr 14, 2026

Deploy preview: https://deploy-preview-22091--material-ui-x.netlify.app/

Bundle size report

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 319ba2b

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Apr 14, 2026
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

DefaultCode: InlineCode,
};

export const createTypes = createTypesFactory(factoryOptions);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSDoc here is important because it doesn't inherit it from createTypesFactory

Suggested change
export const createTypes = createTypesFactory(factoryOptions);
/**
* Creates a type doc component that renders a reference table for the given component.
* @param url Depends on `import.meta.url` to determine the source file location.
* @param component The component to render a reference table for.
* @param [meta] Additional meta for the typedocs.
*/
export const createTypes = createTypesFactory(factoryOptions);

};

export const createTypes = createTypesFactory(factoryOptions);
export const createMultipleTypes = createMultipleTypesFactory(factoryOptions);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here:

Suggested change
export const createMultipleTypes = createMultipleTypesFactory(factoryOptions);
/**
* Creates a type doc component that renders a reference table for the given component.
* A variant is a different implementation style of the same component.
* @param url Depends on `import.meta.url` to determine the source file location.
* @param components The components to render reference tables for.
* @param [meta] Additional meta for the typedocs.
*/
export const createMultipleTypes = createMultipleTypesFactory(factoryOptions);

Comment thread docs/next.config.ts
// New types pipeline (POC) — intercept `types.*.ts` next to API pages and
// precompute props metadata at build time via the docs-infra loader.
{
test: /[/\\]docs[/\\]pages[/\\]x[/\\]api[/\\].+[/\\]types\..*\.ts$/,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that the types.ts and types.md files sort properly, I would recommend this format data-grid.types.ts

Suggested change
test: /[/\\]docs[/\\]pages[/\\]x[/\\]api[/\\].+[/\\]types\..*\.ts$/,
test: /[/\\]docs[/\\]pages[/\\]x[/\\]api[/\\].+[/\\].*\.types\.ts$/,

Comment thread docs/next.config.ts
),
docs: path.resolve(MONOREPO_PATH, './docs'),
docsx: path.resolve(currentDirectory, '../docs'),
// TEMP: force React dedupe so linked @mui/internal-docs-infra doesn't
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually I add file:../../mui-public/packages/docs-infra/build/ in the package.json instead of linking, the downside is you have to run pnpm i after every build of docs-infra to sync the built files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: out-of-date The pull request has merge conflicts and can't be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants