Conversation
…e to fix SSR hydration (close #711) The empty `<template />` placeholder in YunAdBoard is serialized as a real `<template></template>` element during SSR. On hydration Vue resolves the component to null and tries to replace that DOM node, throwing `TypeError: Failed to execute 'replaceChild' on 'Node'` on every page that renders YunLayoutLeft (e.g. opening a post directly). Switching to `<template v-if="false" />` makes the component render a comment node consistently in both SSR and on the client, so hydration matches. A comment node is also not a flex item, so this keeps the no-gap behaviour of the parent `.yun-layout-left` layout that ab57216 introduced — the reason the placeholder was changed from `<div />` to `<template />` in the first place. Reverting to `<div />` (as suggested in the issue) would fix hydration but reintroduce that gap. Adds a regression test that compiles the real component, asserts its SSR output contains no raw `<template>` element, and verifies it hydrates without a mismatch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
🚀 Deployed on https://6a38a0695ac75da1ac739b51--valaxy.netlify.app |
Deploying valaxy with
|
| Latest commit: |
9286950
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://cd4837e7.valaxy.pages.dev |
| Branch Preview URL: | https://fix-711.valaxy.pages.dev |
Deploying valaxy-api with
|
| Latest commit: |
9286950
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8a69ae42.valaxy-api.pages.dev |
| Branch Preview URL: | https://fix-711.valaxy-api.pages.dev |
There was a problem hiding this comment.
Pull request overview
This PR fixes an SSR hydration crash in valaxy-theme-yun where the empty, user-overridable YunAdBoard placeholder was serialized as a real <template> element in SSR, causing Vue hydration to attempt an invalid DOM replacement when the client renders nothing.
Changes:
- Updated
YunAdBoard.vueto render the placeholder as a stable comment node via<template v-if="false" />, avoiding both hydration errors and unwanted flex-gap layout effects. - Added a Vitest + jsdom regression test that compiles the real SFC template, asserts SSR output contains no raw
<template>element, and verifies hydration produces no mismatch warnings/errors. - Added a control test documenting the previous broken
<template />behavior to prevent regression.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
packages/valaxy-theme-yun/components/YunAdBoard.vue |
Switches the placeholder output to a comment node (SSR + client consistent) to prevent hydration crashes without affecting layout gap. |
test/client/yun-adboard.test.ts |
Adds a regression test suite covering SSR serialization and jsdom hydration behavior for the real YunAdBoard SFC. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Ensures the console.error/warn spies in the YunAdBoard hydration test are always restored, even if the mount assertion throws on a regression, so the mocks never leak into later tests. Addresses Copilot review feedback on #712. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the redundant named imports from `vue` and `vue/server-renderer` and call `Vue.createSSRApp` / `serverRenderer.renderToString` off the namespace objects (which are already needed wholesale by the compiled render functions). Addresses Copilot review feedback on #712. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
3 tasks
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
Fixes #711 — opening a post page directly throws
TypeError: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'on any page that rendersYunLayoutLeft.Root cause
YunAdBoard.vueis an empty, user-overridable placeholder. It rendered a bare<template />, which Vue's SSR compiler serializes as a real<template></template>element:On the client the component resolves to nothing, so during hydration Vue tries to replace that SSR
<template>DOM node withnull→replaceChildthrows.Fix
Render the placeholder with
<template v-if="false" />so it emits a comment node consistently in both SSR and on the client:// ssrRender → `<!---->` // client render → createCommentVNode("v-if", true)SSR and client now agree, so hydration matches.
Why not
<div />(the fix suggested in the issue)?A comment node is not a flex item, so it adds no gap to the parent
.yun-layout-left(flex+gap-4) layout. An empty<div>is a flex item and would reintroduce the exact spacing bug that commitab57216f("empty template for YunAdBoard parent gap size") originally fixed by switching<div />→<template />.<template v-if="false" />satisfies both constraints: no hydration crash and no gap.Test
Adds
test/client/yun-adboard.test.ts, which compiles the realYunAdBoard.vue, and asserts:<template>element;A control case confirms the old
<template />form serializes back to a<template>element (the regression guard). Reverting the component to the broken form makes the suite fail — test 2 reproduces the originalTypeErrorexactly.Verification
pnpm run build✅pnpm lint✅pnpm typecheck✅pnpm test✅ (the 2 failingtest/build/*cases require a priorpnpm demo:buildand are unrelated to this change)🤖 Generated with Claude Code