Skip to content

Commit cd49b0b

Browse files
authored
refactor: Wrap suspending pages w/ error boundaries, extract (#1264)
generic pages from the guide/doc pages
1 parent c2dcbfa commit cd49b0b

File tree

6 files changed

+87
-54
lines changed

6 files changed

+87
-54
lines changed

src/components/controllers/blog-page.jsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useRoute } from 'preact-iso';
1+
import { useRoute, ErrorBoundary } from 'preact-iso';
22
import { useContent } from '../../lib/use-content';
33
import { NotFound } from './not-found';
44
import { MarkdownRegion } from './markdown-region';
@@ -7,14 +7,14 @@ import { blogRoutes } from '../../lib/route-utils';
77
import style from './style.module.css';
88

99
export default function BlogPage() {
10-
const { params } = useRoute();
11-
const { slug } = params;
10+
const { slug } = useRoute().params;
11+
const isValidRoute = blogRoutes[`/blog/${slug}`];
1212

13-
if (!blogRoutes[`/blog/${slug}`]) {
14-
return <NotFound />;
15-
}
16-
17-
return <BlogLayout />;
13+
return (
14+
<ErrorBoundary>
15+
{isValidRoute ? <BlogLayout /> : <NotFound />}
16+
</ErrorBoundary>
17+
);
1818
}
1919

2020
function BlogLayout() {

src/components/controllers/doc-page.jsx renamed to src/components/controllers/guide-page.jsx

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect } from 'preact/hooks';
2-
import { useRoute } from 'preact-iso';
2+
import { useRoute, ErrorBoundary } from 'preact-iso';
33
import { useContent } from '../../lib/use-content';
44
import { useLanguage } from '../../lib/i18n.jsx';
55
import config from '../../config.json';
@@ -12,37 +12,35 @@ import { docRoutes } from '../../lib/route-utils';
1212
import { LATEST_MAJOR } from '../doc-version';
1313
import style from './style.module.css';
1414

15-
export function DocPage() {
16-
const { params } = useRoute();
17-
const { version, name } = params;
15+
export function GuidePage() {
16+
const { version, name } = useRoute().params;
17+
const isValidRoute = docRoutes[version]['/' + name];
1818

19-
if (!docRoutes[version]['/' + name]) {
20-
return <NotFound />;
21-
}
22-
23-
return <DocLayout isGuide />;
19+
return (
20+
<ErrorBoundary>
21+
{isValidRoute ? <GuideLayout /> : <NotFound />}
22+
</ErrorBoundary>
23+
);
2424
}
2525

26-
export function DocLayout({ isGuide = false }) {
26+
function GuideLayout() {
2727
const [isMounted, setMounted] = useState(false);
2828
const { path } = useRoute();
29-
const { html, meta } = useContent(path === '/' ? 'index' : path);
29+
const { html, meta } = useContent(path);
3030

3131
useEffect(() => {
3232
setMounted(true);
3333
}, []);
3434

3535
return (
36-
<div class={cx(style.page, isGuide && style.withSidebar)}>
36+
<div class={cx(style.page, style.withSidebar)}>
3737
<div class={style.outer}>
38-
{isGuide && (
39-
<div class={style.sidebarWrap}>
40-
<Sidebar />
41-
</div>
42-
)}
38+
<div class={style.sidebarWrap}>
39+
<Sidebar />
40+
</div>
4341
<div class={style.inner}>
44-
{isGuide && <OldDocsWarning />}
45-
{isGuide && isMounted && <UnmaintainedTranslationWarning meta={meta} />}
42+
{<OldDocsWarning />}
43+
{isMounted && <UnmaintainedTranslationWarning meta={meta} />}
4644
<MarkdownRegion html={html} meta={meta} />
4745
<Footer />
4846
</div>
@@ -85,6 +83,11 @@ function OldDocsWarning() {
8583

8684
// Maybe include zh? It's received some contributions recently
8785
const MAINTAINED_LANGUAGES = ['en', 'ru'];
86+
87+
/**
88+
* @param {object} props
89+
* @param {import('../../types.d.ts').ContentMetaData} props.meta
90+
*/
8891
function UnmaintainedTranslationWarning({ meta }) {
8992
const { path, params } = useRoute();
9093
const { name, version } = params;
Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
1-
import { useRoute } from 'preact-iso';
1+
import { useRoute, ErrorBoundary } from 'preact-iso';
22
import { navRoutes } from '../../lib/route-utils';
3+
import { useContent } from '../../lib/use-content';
34
import { NotFound } from './not-found';
4-
import { DocLayout } from './doc-page';
5+
import { MarkdownRegion } from './markdown-region';
6+
import Footer from '../footer/index';
7+
import style from './style.module.css';
58

9+
// Supports generic pages like `/`, `/about/*`, `/blog`, etc.
610
export function Page() {
711
const { path } = useRoute();
12+
const isValidRoute = navRoutes[path];
813

9-
if (!navRoutes[path]) {
10-
return <NotFound />;
11-
}
14+
return (
15+
<ErrorBoundary>
16+
{isValidRoute ? <PageLayout /> : <NotFound />}
17+
</ErrorBoundary>
18+
);
19+
}
20+
21+
export function PageLayout() {
22+
const { path } = useRoute();
23+
const { html, meta } = useContent(path === '/' ? 'index' : path);
1224

13-
return <DocLayout />;
25+
return (
26+
<div class={style.page}>
27+
<div class={style.outer}>
28+
<div class={style.inner}>
29+
<MarkdownRegion html={html} meta={meta} />
30+
<Footer />
31+
</div>
32+
</div>
33+
</div>
34+
);
1435
}

src/components/controllers/repl-page.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useLocation, useRoute } from 'preact-iso';
1+
import { useLocation, useRoute, ErrorBoundary } from 'preact-iso';
22
import { Repl } from './repl';
33
import { base64ToText } from './repl/query-encode.js';
44
import { fetchExample } from './repl/examples';
@@ -22,7 +22,9 @@ export default function ReplPage() {
2222
overflow: hidden !important;
2323
}
2424
`}</style>
25-
<Repl code={code} />
25+
<ErrorBoundary>
26+
<Repl code={code} />
27+
</ErrorBoundary>
2628
</div>
2729
);
2830
}

src/components/controllers/tutorial-page.jsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useRoute } from 'preact-iso';
1+
import { useRoute, ErrorBoundary } from 'preact-iso';
22
import { useEffect } from 'preact/hooks';
33
import { Tutorial } from './tutorial';
44
import { SolutionProvider } from './tutorial/contexts';
@@ -9,14 +9,14 @@ import { tutorialRoutes } from '../../lib/route-utils';
99
import style from './tutorial/style.module.css';
1010

1111
export default function TutorialPage() {
12-
const { params } = useRoute();
13-
const { step } = params;
12+
const { step } = useRoute().params;
13+
const isValidRoute = tutorialRoutes[`/tutorial${step ? `/${step}` : ''}`];
1414

15-
if (!tutorialRoutes[`/tutorial${step ? `/${step}` : ''}`]) {
16-
return <NotFound />;
17-
}
18-
19-
return <TutorialLayout />;
15+
return (
16+
<ErrorBoundary>
17+
{isValidRoute ? <TutorialLayout /> : <NotFound />}
18+
</ErrorBoundary>
19+
);
2020
}
2121

2222
function TutorialLayout() {

src/components/routes.jsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
11
import { useState } from 'preact/hooks';
22
import { Router, Route, lazy } from 'preact-iso';
33
import { Page } from './controllers/page';
4-
import { DocPage } from './controllers/doc-page';
4+
import { GuidePage } from './controllers/guide-page';
55
import { NotFound } from './controllers/not-found';
66
import { navRoutes } from '../lib/route-utils';
77

88
export const ReplPage = lazy(() => import('./controllers/repl-page'));
99
export const BlogPage = lazy(() => import('./controllers/blog-page'));
1010
export const TutorialPage = lazy(() => import('./controllers/tutorial-page'));
1111

12-
// @ts-ignore
13-
const routeChange = url => typeof ga === 'function' && ga('send', 'pageview', url);
12+
const routeChange = url =>
13+
// @ts-ignore
14+
typeof ga === 'function' && ga('send', 'pageview', url);
15+
16+
const genericRoutes = Object.keys(navRoutes)
17+
.filter(
18+
route =>
19+
!route.startsWith('/guide') &&
20+
!route.startsWith('/tutorial') &&
21+
!route.startsWith('/repl')
22+
)
23+
.map(route => (
24+
<Route key={route} path={route} component={Page} />
25+
));
1426

1527
export default function Routes() {
1628
const [loading, setLoading] = useState(false);
@@ -22,16 +34,11 @@ export default function Routes() {
2234
onLoadEnd={() => setLoading(false)}
2335
onRouteChange={routeChange}
2436
>
25-
{Object.keys(navRoutes)
26-
.filter(route => !route.startsWith('/guide'))
27-
.filter(route => !route.startsWith('/tutorial'))
28-
.map(route => {
29-
const component = route === '/repl' ? ReplPage : Page;
30-
return <Route key={route} path={route} component={component} />;
31-
})}
37+
{genericRoutes}
3238
<Route path="/tutorial/:step?" component={TutorialPage} />
33-
<Route path="/guide/:version/:name" component={DocPage} />
39+
<Route path="/guide/:version/:name" component={GuidePage} />
3440
<Route path="/blog/:slug" component={BlogPage} />
41+
<Route path="/repl" component={ReplPage} />
3542
<Route default component={NotFound} />
3643
</Router>
3744
</main>

0 commit comments

Comments
 (0)