Repository navigation
Conversation
🦋 Changeset detectedLatest commit: 51b7c19 The changes in this PR will be included in the next version bump. This PR includes changesets to release 8 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Hey, thanks for the PR, but I think the approach fixes only your case and still can rerender unkeyed nodes in many different cases. Also please cover both cases: removing from [p, iframe, button] should leave iframe/button untouched, and rotating [p, iframe, button] to [button, p, iframe] and back should move only the button. We can change vSideBuffer to Here is simple pseudo code: Let me know if this is clear |
…r moved Matching a sibling further down the list moved it in front of the cursor right away, so siblings that keep their place were detached and re-inserted. Iframes reloaded and focus was lost. Keep the sibling links while matching and record the new order in the side buffer. Once matching is done, remove the unmatched siblings and compare both ends of the old and new order, so only the siblings that really changed place are moved. This covers keyed and unkeyed nodes. Fixes QwikDev#9188
9c28309 to
51b7c19
Compare
|
Thanks for the detailed pointer, that was clear. Reworked along those lines and rebased on main (force-pushed as one commit):
Tests in One open point: new nodes are still inserted at the cursor while matching, so a new node created out of place can be inserted and then moved once at the end. Happy to change that if you'd prefer another approach. |
@qwik.dev/core
@qwik.dev/router
@qwik.dev/utils
eslint-plugin-qwik
create-qwik
@qwik.dev/optimizer
@qwik.dev/devtools
@qwik.dev/mcp
commit: |
What is it?
Description
Fixes #9188.
When a conditional element is removed, every later sibling of a different tag is detached and re-inserted. An
<iframe>after it reloads, and a focused element after it loses focus:Cause: in
moveOrCreateKeyedNode, when an unkeyed node is found further down the siblings (<iframe>while the cursor is still on the stale<p>), the found node is moved in front of the cursor. The<p>is deleted a moment later byexpectNoMore, so every kept sibling is moved once just to step over a node that is about to go away.Fix: when the found node is a later sibling at the same level, move the siblings that were skipped to reach it to just after it, instead of moving the found node. The resulting vnode order is exactly what it was before (
[found, skipped..., rest]), so the rest of the diff runs unchanged; only the DOM operations differ. In the issue's case the doomed<p>is the node that moves, and the<iframe>and<button>are never touched. Skipped text vnodes are inflated first, asvnode_removedoes. If the found node is not a later sibling at this level, the old move is used.A genuine reorder of unkeyed elements of different tags still works. It may now move the skipped run instead of the single found node. Consecutive moves before the same node are batched into one fragment insert by
_flushJournal.Tests, in
vnode-diff.unit.tsx, check the journal directly, likereconcile-keyed-loop.unit.tsxdoes:{false}replacing<p>before<iframe/><button/>: no insert/move or delete operation targets the iframe or the button (fails onmain);<p>and a<span>dropped from before<iframe/><button/>: same check (fails onmain);<p><iframe><button>reordered to<button><p><iframe>: same DOM nodes, right order (passes before and after).Commands run (Node 22,
pnpm build.core.devfirst):pnpm vitest run packages/qwik/src/core/client/vnode-diff.unit.tsx -t "removing an earlier element": 2 failed, 1 passed with the fix reverted; 3 passed with it.pnpm vitest run packages/: 3855 passed, 7 failed. The 7 failures are all inqwik-vite/src/plugins/plugin.unit.tsand also fail onmainin this environment (Cannot find module .../bindings/qwik.wasm.mjs, no Rust/WASM build). Onmainthe same run gives 3852 passed, 7 failed. Packages whose dependencies were not installed (devtools, docs, mcp, browser-extension) fail to import in both runs.pnpm test.e2e.chromium(dev build): 580 passed, 1 failed, 2 skipped, 1 did not run. The failure isssg-snapshot.e2e.ts› "core chunk brotli size stays within budget". It also fails onmainwith the dev build (36783 bytes onmain, 36821 on this branch, budget 34800). The test itself says it expects the production build, which was not built here.prettier --checkandeslinton the changed files: clean.tsc --noEmitreports only missingreact-dom/@supabase/*modules from packages that were not installed. Nothing inpackages/qwik.Not run:
pnpm build.core/api.update(no public API change), the Rust optimizer, the e2e suites withQWIK_OPTIMIZER=rust, the production build for the brotli budget check.Checklist
pnpm change