[docs-infra] Memoize formatInlineTypeAsHast#1308
Draft
Conversation
Large component prop graphs reference a small number of shared nested
types thousands of times. Without memoization, each reference re-runs
transformHtmlCodeInline → parseSource → Oniguruma's WASM TextMate
tokenizer on the same input. Oniguruma runs in a fixed-size
WebAssembly linear memory buffer, and the repeated scratch allocations
fragment that buffer until it overruns with
RuntimeError: memory access out of bounds
at wasm://wasm/001ce0fe:wasm-function[218]:0x26b63
at wasm://wasm/001ce0fe:wasm-function[202]:0x23386
(`001ce0fe` is the vscode-oniguruma wasm blob consumed via
@wooorm/starry-night in pipeline/parseSource.)
Instrumenting a mui-x DataGrid extraction showed:
- 1947 total calls to formatInlineTypeAsHast
- 5 unique input strings
- average ~389 duplicate calls per input
The duplication comes from two places both walking the type graph
independently:
- buildHighlightedExports in highlightTypes.ts, which builds a
`{ExportName.Props, .DataAttributes, .CssVariables}` map, each
entry calling formatInlineTypeAsHast on a synthetic object type
string.
- highlightComponentTypeMeta in highlightTypesMeta.ts, which walks
every prop and calls formatInlineTypeAsHast on its `typeText`,
`shortType`, default, and detailedType fields.
For a large component with many props that share structural types
(GridColDef, GridRowModesModel, GridCallbackDetails, ...), this
cross-product hits the tokenizer thousands of times with identical
inputs.
Fix: wrap formatInlineTypeAsHast with a process-lifetime Map keyed on
`(unionPrintWidth, typeText)`. Return a structuredClone of the cached
HAST so downstream mutations can't poison the cache. Expose a
`clearInlineTypeHastCache` helper for test isolation.
Verified with mui-x DataGrid POC (external):
/x/api/data-grid/data-grid 63s (was: crash after ~100s)
/x/api/charts/gauge 8s cold / 140ms warm (unchanged)
Also adds 4 regression tests under `typeHighlighting > memoization`:
cached equivalence, distinct-identity isolation, keying on
unionPrintWidth, and mutation idempotence. Tests now at 73 (was 69)
for this file.
Deploy previewhttps://deploy-preview-1308--mui-internal.netlify.app/ PerformanceTotal duration: 18.41 ms +2.28 ms(+14.1%) | Renders: 4 (+0) | Paint: 72.92 ms 🔺+3.94 ms(+5.7%)
Bundle size
Check out the code infra dashboard for more information about this PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
formatInlineTypeAsHastis called once per prop type during type extraction. Each call invokes Shiki's Oniguruma WASM tokenizer, which fragments the WASM heap and drives OOM on large consumer projects (mui-x hit this with ~300 pages).Adds a promise-cache keyed on
unionPrintWidth + typeText. Results are deep-cloned on read so downstream HAST mutation stays safe. ExposesclearInlineTypeHastCache()for tests.Adds 4 unit tests covering cache hit, mutation isolation, and key disambiguation.