fix(islands): wrap every client island in ErrorBoundary, not just AppIsland - #227
Open
nastaso wants to merge 2 commits into
Open
fix(islands): wrap every client island in ErrorBoundary, not just AppIsland#227nastaso wants to merge 2 commits into
nastaso wants to merge 2 commits into
Conversation
…Island CertDashboardIsland, HeaderInteractive, FooterIsland, DonateButtonIsland, CookieConsentIsland, and AccountLinkNoticeIsland previously mounted with no boundary, so a render throw blanked the region silently instead of degrading to the recovery card. StatsIsland already had this (PR #145) and AppIsland's own boundary is unchanged. Closes #70.
Deploying cloudcertprep with
|
| Latest commit: |
deba5ea
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3c4c93c0.cloudcertprep.pages.dev |
| Branch Preview URL: | https://fix-island-error-boundaries.cloudcertprep.pages.dev |
Codex adversarial audit (lens: find an island the change missed) found AuthLinkNotice (index.astro), DomainProgressStrip ([domain].astro), BlogShareButton (BlogLayout.astro), and AnalyticsBootstrap (BaseLayout.astro) - none named in #70's own list, all genuinely top-level client:-mounted components with no boundary. Verified independently with a full grep of every client:only/client:idle/client:load mount in src/ before fixing; that grep turned up exactly these 4 and no more.
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.
What does this PR do?
Closes #70. Reuses the existing
ErrorBoundary(no new component, no new dependency) and wraps every top-level client island root, so a render throw in any island degrades to the existing recovery card and logs vialogError, instead of blanking the region silently.Wrapped (first pass, matching #70's own list):
CertDashboardIsland,HeaderInteractive,FooterIsland,DonateButtonIsland,CookieConsentIsland,AccountLinkNoticeIsland.Wrapped (second pass, after a codex adversarial audit found #70's own list was incomplete):
AuthLinkNotice(index.astro),DomainProgressStrip([domain].astro),BlogShareButton(BlogLayout.astro),AnalyticsBootstrap(BaseLayout.astro). None of these four were named in #70 - I verified them with a full repo grep for everyclient:only/client:idle/client:loadmount insrc/, which turned up exactly these 4 gaps and no more.Already had it, untouched:
AppIsland(pre-existing, the boundary fix(islands): wrap every client island in ErrorBoundary, not just AppIsland #70 was modeled on).StatsIsland- checked before wrapping and it's already been boundary-wrapped since PR fix(stats,history): cert ordering, error-state chips, single loader, shift-free stats swap (S1/S2/H2 + FLASH F2/F3) #145. Issue fix(islands): wrap every client island in ErrorBoundary, not just AppIsland #70 listed it as unprotected; that's stale as of fix(stats,history): cert ordering, error-state chips, single loader, shift-free stats swap (S1/S2/H2 + FLASH F2/F3) #145, so I left it alone rather than double-wrap.No island hydration directives (
client:idle/client:only) or island logic changed anywhere - only an import + a JSX wrap around each existing return (or, for the 4 multi-early-return components, a rename-and-wrap: the original function becomes an unexported*Inner, and the exported name becomes a thin<ErrorBoundary>wrapper around it, so no internal branching had to be touched).Notes
CookieConsentIslandis currently unmounted inBaseLayout.astro(dormant - see the comment above the GA script block). The wrap is harmless and future-proofs it; no live effect today.AnalyticsBootstrapalways rendersnull- the wrap still protects against a synchronous render-phase throw before that return, for consistency with every other island's policy.Testing
This repo's vitest environment is
node(no DOM) and has noreact-test-renderer/@testing-library/react(AGENTS.md: no new dependencies). I checked bothrenderToStaticMarkupandrenderToPipeableStreamby hand before writing the test - neither recovers inline from a synchronous root-level throw the way the client reconciler does, so an end-to-end "mount and throw" test isn't possible here without a new dependency.Instead
src/components/ErrorBoundary.test.tsxdrivesErrorBoundary's own lifecycle methods directly (getDerivedStateFromError,componentDidCatch,render()) - the exact methods React itself calls - and asserts on the returned element tree. Mutation-tested by hand: changedrender()to always return children regardless ofhasError, confirmed the "renders the recovery card instead of blanking" test goes red, reverted, confirmed green again.npm run check(typecheck + lint + unit tests): 0 errors, 0 warnings, 304/304 tests pass (added 4).npm run build: full guard chain green (citation, internal-graph, person-graph,check:seo-head,csp:hash,cf:headers).PW_PORT=4399 PW_REUSE_SERVER=0 npm run e2e: 109/109 non-skipped tests pass (20 skipped need real Supabase creds, same as baseline) - re-run after the second-pass fixes too.Checklist
npm run checkpasses locallynpm run buildpasses locally (full guard chain)npm run e2epasses locally (isolated port)