feat(marko-virtual): post-release follow-ups: full option parity, streaming SSR Support with Resume, typed handles, e2e coverage, examples#1219
Conversation
|
Important Review skippedToo many files! This PR contains 196 files, which is 46 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (196)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
|
@coderabbitai help |
ChatThere are 3 ways to chat with CodeRabbit:
CodeRabbit commands
Other keywords and placeholders
CodeRabbit configuration file (
|
|
@coderabbitai summary |
✅ Action performedSummary regeneration triggered. |
4bd71a2 to
fb05f90
Compare
To buildpnpm install
pnpm --filter @tanstack/virtual-core build
pnpm --filter @tanstack/marko-virtual build
pnpm --filter @tanstack/marko-virtual test:types To Test## runs unit tests
pnpm --filter @tanstack/marko-virtual exec vitest run --reporter=verbose
## runs e2e
pnpm -r --workspace-concurrency=1 --filter "./examples/marko/*" run test:e2eTo run examplespnpm --filter tanstack-marko-virtual-example-fixed dev
pnpm --filter tanstack-marko-virtual-example-variable dev
pnpm --filter tanstack-marko-virtual-example-dynamic dev
pnpm --filter tanstack-marko-virtual-example-grid dev
pnpm --filter tanstack-marko-virtual-example-smooth-scroll dev
pnpm --filter tanstack-marko-virtual-example-infinite-scroll dev
pnpm --filter tanstack-marko-virtual-example-window dev
pnpm --filter tanstack-marko-virtual-example-ssr dev
pnpm --filter tanstack-marko-virtual-example-ssr-fetch dev
pnpm --filter tanstack-marko-virtual-example-ssr-slice dev
pnpm --filter tanstack-marko-virtual-example-ssr-restore dev
pnpm --filter tanstack-marko-virtual-example-window-ssr-slice dev
pnpm --filter tanstack-marko-virtual-example-chat dev
pnpm --filter tanstack-marko-virtual-example-scroll-padding dev
pnpm --filter tanstack-marko-virtual-example-padding dev
pnpm --filter tanstack-marko-virtual-example-pretext dev
pnpm --filter tanstack-marko-virtual-example-sticky dev
pnpm --filter tanstack-marko-virtual-example-table dev
pnpm --filter tanstack-marko-virtual-example-chat-pretext dev |
c4e8d8f to
e5c653c
Compare
… type-strict examples
…am guidance packaging changed to the canonical Marko library shape per Marko team guidance (marko.json exports → built dist/tags, no tags-dir/script-lang, mtc-built declarations, in-repo consumers resolve tags from source via nested marko.json), plus the sideEffects fix
marko-virtual:
Follow-up to the initial
@tanstack/marko-virtual[PR#1156](#1156), covering the review follow-upsand everything found while hardening.
packages/virtual-coreis untouched — thisPR is Marko-adapter-only. The file count (~260) is dominated by per-example
scaffolding (test suites, tsconfigs, generated route typings, per-example type-check
wiring) across 19 examples; the source-logic changes are concentrated in the two tags
and the example pages. Two commits: the follow-up feature/fix work, and the
packaging restructure to the canonical Marko library shape (details in §4).
1. SSR support (new architecture in the tags)
The tags are now SSR-safe by construction. On the server, a tag renders either an
empty container with the correct total height, or — when given
initialRect— theactual initial rows into the HTML, computed by a lightweight
renderSlicepass(no live virtualizer instance ever runs on the server). The live, observing instance
is built client-only on mount and takes over on resume ([MarkoJS](https://markojs.com/) v6 does not replay).
Consumer-facing consequence, visible in the 7 pre-existing examples' diffs: the
<let/mounted>+<lifecycle onMount>+<if=mounted>guard scaffolding isdeleted — nobody needs to hide the virtualizer from the server anymore. Those
pages also migrate to the [tag-variable API](https://markojs.com/docs/guide/marko-5-interop#tags-api-syntax) (
<virtualizer/v .../>, self-closing),the documented shape.
Streaming composes for free: a virtualizer inside a streamed
<await>(with<try>/<@placeholder>) renders its server slice into the mid-stream chunk andresumes independently when that chunk arrives. This is a gated fact, not a claim:
the
ssr-slicesuite includes a raw-HTTP wire test asserting the placeholder flushesfirst and the server-painted rows arrive in a later chunk. Documented with a full
pattern sample in the README and docs (including the out-of-order no-JS caveat).
2. Full option parity
Both tags accept the remaining core options:
scrollMargin,enabled,isRtl,isScrollingResetDelay,useScrollendEvent,useAnimationFrameWithResizeObserver,laneAssignmentMode,useCachedMeasurements,debug, custommeasureElement; thewindow tag adds
horizontalandinitialOffset. Each option is proven by areal-Chromium behavioral test in
packages/marko-virtual/e2e/option-gates(a testrig, excluded from publish via the
filesfield).3. Typed tag variables + type verification
The tag variables (
/v) are typed by exported interfaces —VirtualizerHandle/WindowVirtualizerHandle. The.d.markodeclarations consumers see are buildoutput (see §4) — generated by
[marko-type-check](https://github.com/marko-js/language-server/tree/main/packages/type-check),
never hand-written, never committed.
pnpm test:typesruns mtc in check-only modeover the whole package (sources, tags, tests, fixtures). Every example additionally
has its own
test:typesscript, sopnpm -r --filter "./examples/marko/*" run test:typestype-checks all 19 exampleapps from the CLI.
4. Canonical Marko library packaging (per Marko team guidance)
The package now follows the structure of
marko-js/examples
library, replacing theinitial hand-rolled setup:
marko.jsonis the one-liner{ "exports": "./dist/tags" }— notags-dir, noscript-lang(both flagged in review as app-style config in a package).pnpm buildruns two tools:vite buildfor the plain-TS entry, thenmarko-type-check -p tsconfig.tags.jsonbuilding the tags intodist/tags—each tag's
.markowith the TypeScript stripped, its generated.d.marko,and compiled helper
.js/.d.ts. The tag build's incremental cache livesinside
distso any clean forces a re-emit (a stale cache outside thecleaned dir silently emits nothing).
filesshipsdist+marko.json+ README only; rawsrc/tagsno longerpublishes; the committed
.d.markofiles and their generator script are retired.the tags from source via a small nested
marko.jsonwithtags-dir— fulltypes, no build-order dependency — with the examples' tsconfigs
include-ing thesource tags (build-mode type-checking requires listing cross-package files).
language-toolsissuemakes installed-package tag types fail to load under pnpm's symlinked layout
(falls back to a permissive read-only default); npm/yarn consumers and runtime
behavior everywhere are unaffected; consumer stopgap
node-linker=hoisted.5. Twelve new examples (7 → 19)
padding,scroll-padding,sticky,table,pretext— one per corefeature area (padding offsets, scroll padding, sticky headers, table semantics,
calculated text heights via
@chenglou/pretext).chat— bottom-anchored messaging:anchorTo="end",followOnAppend,history prepends that keep the visible message anchored, near-top auto-load with
a load-ahead trigger, and a real streamed reply over the network (marko-run
+handlerreturning a chunkedReadableStream).chat-pretext— chat rebuilt on calculated heights: prepends land withzero scroll correction at any width (the suite asserts the prepend landed AND
produced at most the single compensation jump), and the streamed reply pushes its
growing height through
v.resizeItemper chunk (that API's first real consumer).behavior and raw view-source HTML in its suite:
ssr(no fetch, empty container, rows on client),ssr-fetch(server fetch,client rows),
ssr-slice(server fetch, rows in the server HTML viainitialRect, plus the streaming wire gate),ssr-restore(server rows at ascroll offset),
window-ssr-slice(server rows for the window tag).6. Tests
tags.test.tsexpanded; newoptions.test.ts(option plumbing)and
render-slice.test.ts(SSR seed math); fixtures updated + a new surfacefixture.
share port 4173, so they run sequentially (command below).
7. Fixes
sideEffectscorrected to["**/*.marko"](wasfalse): Marko templatesregister their renderers and resume effects via module side effects, so
sideEffects: falselet production bundlers tree-shake a tag's client module onany page that uses the tag render-only (no function references) — the resume
payload then points at registrations that never ran:
TypeError: effects[(i++)] is not a function, zero hydration. Invisible in dev and todev-mode suites; only surfaced by production-previewing a simple example.
Note for maintainers: the published 3.14.x carries this bug — render-only
consumers' prod builds are broken until this ships.
keyed loop lose their subscription to a page-level signal — which broke the chat
example's streamed reply in prod builds (text arrived and was stored, but never
painted). Reproduced in a 25-line page with no TanStack code, bisected to the fix
in marko 6.1.10, verified end-to-end here.
of the top (prepends land above the viewport; no hard-stop jolt), and
overflow-anchor: noneon the scroller (the virtualizer owns prependcompensation; native browser anchoring could double-compensate).
symlink formed a directory cycle that crashed
marko-run build(ENAMETOOLONG)via
@marko/vite's production template scan.tag-variable inference cycles,
String(item.key)for<for by>, thesecond-parameter event-handler idiom instead of
currentTarget, which Marko'sdelegated events reject at runtime).
8. Toolchain & workspace modernization
@marko/run^0.7 → ^0.10,marko→ ^6.2.2; package devDeps to@marko/vite^6.1.0.workspace:*→^3.14.0) soany example folder works when copied out of the monorepo; each example also
declares the
@marko/type-check+@marko/language-toolspair (both are neededfor the CLI type checks: pnpm exposes only a project's own bins, and
language-toolsneeds itsmarkopeer resolved from the declaring project).@playwright/testaligned to the root's^1.53.1everywhere;sherifpasses.pnpm-workspace.yaml: single@marko/compiler(5.40.0) enforced via override(two compiler instances in the graph break taglib discovery — comment inline),
plus the option-gates workspace entry.
.marko-run/routes.d.ts(marko-run's generated routetypings) — same convention as marko-run's own examples: typed routes on a fresh
clone, and route-surface changes show up in review.
.gitignore:**/*.tsbuildinfo(incremental-build cache from the newper-example tsconfigs).
9. Docs
docs/framework/marko/marko-virtual.mdsubstantially expanded (full inputreference for both tags, SSR guide including streaming via
<await>and theno-JS caveat, TypeScript guide); the package README adds the build/packaging
story, the streaming section, the pnpm consumer limitation, and a
production-sanity note naming both manual canaries (a render-only example AND
the interactive chat);
docs/installation.mdgains the Marko section;docs/config.jsonlists all 19 examples.How to verify
✅ Checklist
pnpm run test:pr.🚀 Release Impact