Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 2b345a0

Browse files
author
Je
committed
feat: add ErrorBoundary
1 parent f189d18 commit 2b345a0

File tree

4 files changed

+69
-30
lines changed

4 files changed

+69
-30
lines changed

app.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { ComponentType, createContext, useCallback, useEffect, useState } from 'https://esm.sh/react'
22
import { DataContext } from './data.ts'
3-
import { E404Page, E501 } from './error.ts'
3+
import { E404Page, E501App, E501Page } from './error.ts'
44
import events from './events.ts'
55
import route from './route.ts'
66
import { RouterContext } from './router.ts'
@@ -35,15 +35,15 @@ export function ALEPH({ initial }: {
3535
const [app, setApp] = useState(() => {
3636
const { App } = initial.components
3737
return {
38-
Component: App ? (util.isLikelyReactComponent(App) ? App : E501.App) : null
38+
Component: App ? (util.isLikelyReactComponent(App) ? App : E501App) : null
3939
}
4040
})
4141
const [page, setPage] = useState(() => {
4242
const { components, url } = initial
4343
const { Page } = components
4444
return {
4545
url,
46-
Component: Page ? (util.isLikelyReactComponent(Page) ? Page : E501.Page) : null
46+
Component: Page ? (util.isLikelyReactComponent(Page) ? Page : E501Page) : null
4747
}
4848
})
4949
const onpopstate = useCallback(async () => {
@@ -64,7 +64,7 @@ export function ALEPH({ initial }: {
6464
} else {
6565
setPage({
6666
url,
67-
Component: E501.Page
67+
Component: E501Page
6868
})
6969
}
7070
} else {
@@ -103,7 +103,7 @@ export function ALEPH({ initial }: {
103103
} else {
104104
setPage(({ url }) => ({
105105
url,
106-
Component: E501.App
106+
Component: E501App
107107
}))
108108
}
109109
} else if (moduleId === './data.js' || moduleId === './data/index.js') {

bootstrap.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'https://esm.sh/react'
22
import { hydrate, render } from 'https://esm.sh/react-dom'
33
import { ALEPH, getModuleImportUrl } from './app.ts'
4+
import { ErrorBoundary } from './error.ts'
45
import route from './route.ts'
56
import type { AppManifest, Module, RouterURL } from './types.ts'
67
import util from './util.ts'
@@ -51,17 +52,22 @@ export default async function bootstrap({
5152
pageModule ? import(getModuleImportUrl(baseUrl, pageModule)) : Promise.resolve({}),
5253
])
5354
const el = React.createElement(
54-
ALEPH,
55-
{
56-
initial: {
57-
manifest: { baseUrl, defaultLocale, locales },
58-
pageModules,
59-
url,
60-
data,
61-
components: { E404, App, Page }
55+
ErrorBoundary,
56+
null,
57+
React.createElement(
58+
ALEPH,
59+
{
60+
initial: {
61+
manifest: { baseUrl, defaultLocale, locales },
62+
pageModules,
63+
url,
64+
data,
65+
components: { E404, App, Page }
66+
}
6267
}
63-
}
68+
)
6469
)
70+
6571
if (dataEl) {
6672
hydrate(el, mainEl)
6773
// remove ssr head elements, set a timmer to avoid tab title flash

error.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,40 @@ const e501PageEl = React.createElement(
1919
)
2020
const e404PageEl = React.createElement(ErrorPage, { status: 404 })
2121

22-
export const E501 = {
23-
App: () => e501AppEl,
24-
Page: () => e501PageEl
25-
}
22+
export const E501App = () => e501AppEl
23+
export const E501Page = () => e501PageEl
24+
export const E404Page = () => e404PageEl
25+
26+
export class ErrorBoundary extends React.Component {
27+
state: { stack: string | null }
28+
29+
constructor(props: any) {
30+
super(props)
31+
this.state = { stack: null }
32+
}
33+
34+
static getDerivedStateFromError(error: Error) {
35+
// Update state so the next render will show the fallback UI.
36+
return { stack: error.stack }
37+
}
38+
39+
componentDidCatch(error: any, errorInfo: any) {
40+
this.state = { stack: error.stack }
41+
}
2642

27-
export function E404Page() {
28-
return e404PageEl
43+
render() {
44+
if (this.state.stack) {
45+
return (
46+
React.createElement(
47+
'pre',
48+
null,
49+
this.state.stack
50+
)
51+
)
52+
}
53+
54+
return this.props.children
55+
}
2956
}
3057

3158
export function ErrorPage({ status, text = getStatusText(status), refreshButton }: { status: number, text?: string, refreshButton?: boolean }) {

renderer.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { ComponentType } from 'https://esm.sh/react'
22
import { renderToString } from 'https://esm.sh/react-dom/server'
33
import { DataContext } from './data.ts'
4-
import { E501 } from './error.ts'
4+
import { E501App, E501Page, ErrorBoundary } from './error.ts'
55
import { RouterContext } from './router.ts'
66
import type { RouterURL } from './types.ts'
77
import util from './util.ts'
@@ -13,15 +13,21 @@ export function renderPage(
1313
App: ComponentType<any> | undefined,
1414
Page: ComponentType<any>,
1515
) {
16-
const pageEl = React.createElement(util.isLikelyReactComponent(Page) ? Page : E501.Page)
17-
const appEl = App ? (util.isLikelyReactComponent(App) ? React.createElement(App, null, pageEl) : React.createElement(E501.App)) : pageEl
18-
return renderToString(React.createElement(
19-
DataContext.Provider,
20-
{ value: data },
16+
const pageEl = React.createElement(util.isLikelyReactComponent(Page) ? Page : E501Page)
17+
const appEl = App ? (util.isLikelyReactComponent(App) ? React.createElement(App, null, pageEl) : React.createElement(E501App)) : pageEl
18+
return renderToString(
2119
React.createElement(
22-
RouterContext.Provider,
23-
{ value: url },
24-
appEl
20+
ErrorBoundary,
21+
null,
22+
React.createElement(
23+
DataContext.Provider,
24+
{ value: data },
25+
React.createElement(
26+
RouterContext.Provider,
27+
{ value: url },
28+
appEl
29+
)
30+
)
2531
)
26-
))
32+
)
2733
}

0 commit comments

Comments
 (0)