Reimplement hydration with deterministic comment boundaries#58
Reimplement hydration with deterministic comment boundaries#58adebola-io wants to merge 7 commits into
Conversation
Remove unused hydration functionality and server-side context passing from the server and client packages to simplify rendering. After applying these changes, please rebuild the packages and run tests using `pnpm run test`.
- Remove `data-retend-hydration` attribute after hydration completes. - Replace CSS selector-based teleport lookups with attribute comparison to handle special characters. - Ensure proper cleanup during effect node disposal. Run `pnpm install` and `pnpm run test` after updating.
- Simplify `hydrate` entry point and remove internal docs. - Enforce strict hydration structural matching. - Rebuild packages before running tests with `pnpm run test`.
- Streamline hydration sequence in `hydrate` - Simplify `renderToString` recursion - Clean up hydration stack and state management in `DOMRenderer` - Refactor teleport counter and state initialization
- Standardize node flattening using `.flat()` - Improve `Await` promise tracking and disposal - Fix `For` loop initial node rendering - Add `createSwitch` helper for Switch component - Optimize hydration data access and `If` component logic
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
retend | 06cddb1 | Commit Preview URL Branch Preview URL |
Jul 23 2026, 06:26 PM |
PR Summary by QodoDeterministic hydration via serialized comment ranges (drop data-dyn markers)
AI Description
Diagram
High-Level Assessment
Files changed (28)
|
Code Review by Qodo
1. Claim flag type mismatch
|
| #markClaimed(node) { | ||
| if (node) hydrationData(node).claim ??= true; | ||
| } | ||
|
|
||
| /** | ||
| * @param {{ cursor: number, renderDepth: number, pendingHydrations: number, hydrating: boolean }} state | ||
| */ | ||
| #maybeCompleteHydrationBranch(state) { | ||
| if (!state.hydrating) return; | ||
| const branchIsIdle = | ||
| state.renderDepth === 0 && state.pendingHydrations === 0; | ||
| if (!branchIsIdle) return; | ||
| state.hydrating = false; | ||
| this.#hydratingBranchCount = Math.max(0, this.#hydratingBranchCount - 1); | ||
| /** @param {Node} node */ | ||
| #markClientNode(node) { | ||
| const claim = (hydrationData(node).claim ??= {}); | ||
| if (node.nodeType === ELEMENT_NODE) claim.opaque = true; | ||
| } |
There was a problem hiding this comment.
1. Claim flag type mismatch 🐞 Bug ≡ Correctness
DOMRenderer.#markClaimed stores hydrationData(node).claim as boolean true, but #markClientNode later assumes claim is an object and writes claim.opaque, which can throw a TypeError if the same element is ever marked as both claimed and client-owned during hydration updates.
Agent Prompt
## Issue description
`packages/retend-web/source/dom-renderer.js` uses `hydrationData(node).claim` with two incompatible shapes:
- `#markClaimed()` initializes it to boolean `true`.
- `#markClientNode()` treats it as an object and assigns `claim.opaque = true`.
If an element with `claim === true` later flows into `#markClientNode()`, the property assignment will throw (strict mode), potentially aborting hydration.
## Issue Context
This PR introduced the new hydration metadata model (`HYDRATION` symbol) and these helpers. `#markClaimed()` is used at least for Teleport containers and hydration separators.
## Fix Focus Areas
- packages/retend-web/source/dom-renderer.js[790-799]
- packages/retend-web/source/dom-renderer.js[580-592]
- packages/retend-web/source/dom-renderer.js[177-195]
## Suggested fix
1. Make `claim` a single consistent type (object) everywhere:
- Change `#markClaimed(node)` to initialize `claim` as `{}` (or a minimal object shape), not `true`.
2. Defensive normalization in `#markClientNode(node)`:
- If `hydrationData(node).claim === true`, replace it with `{}` before setting `opaque`.
3. Update any logic that relies on truthiness of `claim` (`#isClaimed`) to continue working with the object representation.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
retend
retend-oxlint-plugin
retend-server
retend-start
retend-utils
retend-web
retend-web-devtools
commit: |
No description provided.