Repository navigation
docs(react): fix createLazyPlugin's JSDoc example to a call that compiles - #5990
Merged
Merged
Conversation
…iles
The `@example` block taught `() => import('@object-ui/plugin-grid')` as the
`importFn`. That package exports its components by NAME and has no `default`,
so the call supplied the module namespace object — TS2345 at compile time
("Property 'default' is missing"), and at runtime `React.lazy` would receive
the namespace object as the component.
Measured against the compiler, all three candidate spellings:
- bare namespace import RED TS2345
- `.then((m) => ({default: m.X}))` RED TS2322, infers `P` as `never`
- `async () => ({default: (await import(...)).X})` GREEN
All three examples now use the `async` unwrap, and each is given a distinct
binding so the fenced block is one coherent program rather than three
redeclarations of `const ObjectGrid`.
`preloadPlugin`'s example lower in the file is deliberately untouched: its
parameter is `() => Promise<T>`, which expects no `default`, so the bare
import is correct there.
Adds a standing guard. No gate reads a JSDoc `@example` in a `.tsx` source
file — `check-doc-snippet-types.mjs` scans markdown only — so the new test
pins the shape by compilation (`tsc -p tsconfig.test.json`, with a
`@ts-expect-error` on the old form) and pins the docblock text to that shape,
without enrolling this file into another gate's population.
Part of #5949. The docblock ships in the published .d.ts, so this is a user-visible patch rather than a releases-nothing change.
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
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.
Fixes #5949
What was wrong
createLazyPlugin's own@exampleblock passed() => import('@object-ui/plugin-grid')as theimportFn, three times over. That package exports its components by name and has nodefault, so the call supplies the module namespace object where a component is expected. Wrong in both dimensions: rejected by the compiler, and at runtimeReact.lazywould receive the namespace object as the component and render nothing useful.This is the worst-placed kind of doc error — it sits on the function it documents, and it is carried into the published
.d.tsthat editors surface on hover.The replacement was derived, not guessed
I read
@object-ui/plugin-grid's real export shape first:packages/plugin-grid/src/index.tsxopensexport { ObjectGrid, VirtualGrid, ImportWizard };,ObjectGridis declared as aReact.FCparameterised byObjectGridComponentProps, and the file has noexport defaultand noas defaultre-export (grep confirmed with a control probe, so the zero-hit reads as absent rather than mis-anchored).Then I measured all three candidate spellings against the compiler, in
packages/react's own strict test project:() => import('@object-ui/plugin-grid')(what the docblock taught)TS2345: Property 'default' is missing.then((m) => ({ default: m.ObjectGrid }))TS2322, infersPasneveron one branch of thethenoverloadasync () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid })So all three examples now use the
asyncunwrap. Each also gets a distinct binding (ObjectGrid,ObjectGridWithFallback,ObjectGridWithRetry) so the fenced block is one coherent program rather than three redeclarations of the sameconst. The@paramline, which previously just asserted "returns a module with default export", now says why a bare plugin import does not satisfy it.preloadPlugin's example lower in the same file is deliberately untouched. Its parameter is generic over whatever the import resolves to — a plainPromiseofT, with nodefaultrequired anywhere in the type — so the bare import is correct there. That is the one place the obvious sweep would have been wrong.Proving it compiles — and why not via
check:doc-snippetsscripts/check-doc-snippet-types.mjsstates its own scan surface as "every.mdxand.mdpage undercontent/docs, plus everypackages/*/README.md" — markdown documents only. A JSDoc@exampleinside a.tsxsource file is categorically outside it, which is exactly why this rotted. Extending that scan surface to source files is a contract change on the gate's population (its header requires anything added to be declared in the same breath) and is a different, larger card. I did not enrol this file into it as a side effect.Instead the new test
packages/react/src/__tests__/LazyPluginLoader.jsdocExample.test.tspins the two halves that together make the example true, each checked by the thing that can actually judge it:typeLevelContractis compiled bytsc -p tsconfig.test.json(chained from this package'stype-check, which is what CI's Type Check job runs). It pins that unwrapping a named export satisfiesimportFn, and carries a@ts-expect-erroron the old bare form — so if the compiler ever starts accepting a namespace object there, that line turns the build red.@examplefence, and assert it uses the unwrap and never the bare form — so the compiled shape and the documented text cannot drift.The honest limit, stated because a reader of a green run needs it: this does not compile the docblock's literal text. It cannot —
@object-ui/plugin-griddepends on@object-ui/react, so this package cannot import it in either direction without a workspace cycle. The module identity is instead pinned by an on-disk assertion that plugin-grid still has no default export (a path read, not an import;check:phantom-depsconfirms no dependency edge was created).Population of the same wrong shape (issue's "worth checking")
Swept, and reported rather than swept up — nothing outside the fence was touched:
content/docs/guide/deployment.md— already corrected onmain; it teaches the sameasyncunwrap this PR adopts. That is the sibling that surfaced the bug.packages/react/src/LazyPluginLoader.tsx:166(preloadPlugin) — bare import, and correct; left alone.packages/core/src/registry/Registry.ts:281and the manyComponentRegistry.registerLazy(...)call sites — a different API that legitimately takes the whole module namespace. Not the same defect.content/docs/guide/objectos-integration.mdx:546-548— a plugin map feeding a different loader, notcreateLazyPlugin. Not swept; flagged here only.packages/react/README.md— nocreateLazyPluginexample at all.Real-world callers already use the unwrap-by-name form against this very package (
packages/app-shell/src/views/ObjectView.tsx:23), which corroborates the shape independently.Verification
All run at
fc54843f8, the final commit on this branch:pnpm --filter @object-ui/react type-check— exit 0 (script echoed, not a zero-match no-op)pnpm exec vitest run packages/react/— Test Files 54 passed (54), Tests 739 passed (739)node scripts/check-changeset-presence.mjs— green, declares.changeset/lazy-plugin-jsdoc-compiles.mdcheck:control-bytes,check:esm-specifiers,check:phantom-deps,check:self-import— all exit 0 on their own verdict linesReverse-verification, both legs rebuilt and each mutation confirmed on disk before the reading was taken:
TS2578: Unused '@ts-expect-error' directive— the negative assertion is load-bearing, not a comment. Restored;tscclean again.Declared narrowing:
check:doc-snippetswas not run to completion locally — it needs most of the workspace built (it reportedunbuilt-packagefor 9 packages), which is the repo-wide build CI owns. Its verdict provably cannot move because of this diff: its population is markdown only and none of the 3 changed files is in it (verified with a control probe on the population regex), and every changed line of the.tsxis a comment line, so the emitted.d.tstype surface is byte-identical in the shapes that gate compiles against.Lint was likewise narrowed to the changed files: 0 errors, 1 warning, and that warning (
no-explicit-anyon thePtype parameter'sanydefault) is pre-existing onorigin/mainand not an added line. The config has no type-aware linting, so this diff cannot move the verdict on any untouched file.Note for readers: this repo's body sanitizer strips short angle-bracket fragments, so generic type arguments above are spelled in prose rather than in brackets.
Related: #5174, #5160, #5053.
Generated by Claude Code