A crashed island renders its error in dev and nothing in prod, leaving the surrounding server-rendered page intact. Island .tsx sources carry an explicit @jsxImportSource react pragma: the repo's root tsconfig points jsxImportSource at @wrnexus/core, so without it island JSX compiles to WRNexus's string renderer instead of React elements. Tests render on the client via createRoot rather than a server renderer, because React error boundaries do not engage during SSR — and islands are client-only regardless. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
/** @jsxImportSource react */
|
|
import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
|
|
export interface IslandErrorBoundaryProps {
|
|
name: string;
|
|
development: boolean;
|
|
children: ReactNode;
|
|
}
|
|
|
|
interface IslandErrorBoundaryState {
|
|
error: Error | null;
|
|
}
|
|
|
|
/**
|
|
* Contains island failures locally: a crashed island must never blank the
|
|
* surrounding server-rendered page.
|
|
*/
|
|
export class IslandErrorBoundary extends Component<
|
|
IslandErrorBoundaryProps,
|
|
IslandErrorBoundaryState
|
|
> {
|
|
override state: IslandErrorBoundaryState = { error: null };
|
|
|
|
static getDerivedStateFromError(error: Error): IslandErrorBoundaryState {
|
|
return { error };
|
|
}
|
|
|
|
override componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
console.error(`[wrnexus] island '${this.props.name}' failed to render`, error, info);
|
|
}
|
|
|
|
override render(): ReactNode {
|
|
const { error } = this.state;
|
|
if (!error) return this.props.children;
|
|
if (!this.props.development) return null;
|
|
return (
|
|
<div data-wrn-island-error={this.props.name} style={{ padding: "0.75rem" }}>
|
|
<strong>{`Island '${this.props.name}' failed`}</strong>
|
|
<pre>{error.stack ?? error.message}</pre>
|
|
</div>
|
|
);
|
|
}
|
|
} |