Skip to content

Commit b7ea91e

Browse files
authored
refactor: Delegate all prefetching/preloading at app root (#1354)
* refactor: Delegate all prefetching/preloading at app root * Apply suggestion from @rschristian
1 parent 77986c8 commit b7ea91e

6 files changed

Lines changed: 50 additions & 57 deletions

File tree

src/components/app.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { LocationProvider, ErrorBoundary } from 'preact-iso';
22
import { LanguageProvider } from '../lib/i18n';
33
import { PrerenderDataProvider } from '../lib/prerender-data.jsx';
4+
import { useDelegatedPrefetch } from '../lib/use-delegated-prefetch.js';
45
import Header from './header';
56
import Routes from './routes';
67

78
/**
89
* @param {{ prerenderData?: import('../types.d.ts').PrerenderData }} props
910
*/
1011
export default function App({ prerenderData }) {
12+
useDelegatedPrefetch();
1113
return (
1214
<ErrorBoundary>
1315
<LocationProvider>

src/components/blog-overview/index.jsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import config from '../../config.json';
22
import { useLanguage, useTranslation, getRouteName } from '../../lib/i18n';
33
import { Time } from '../time';
4-
import { prefetchContent } from '../../lib/use-content';
5-
import { BlogPage } from '../routes.jsx';
64
import s from './style.module.css';
75

86
export default function BlogOverview() {
@@ -16,21 +14,16 @@ export default function BlogOverview() {
1614
const name = getRouteName(post, lang);
1715
const excerpt = post.excerpt[lang] || post.excerpt.en;
1816

19-
const prefetchAndPreload = () => {
20-
BlogPage.preload();
21-
prefetchContent(post.path);
22-
};
23-
2417
return (
2518
<article class={s.post}>
2619
<div class={s.meta}>
2720
<Time value={post.date} />
2821
</div>
2922
<h2 class={s.title}>
30-
<a href={post.path} onMouseOver={prefetchAndPreload} onTouchStart={prefetchAndPreload}>{name}</a>
23+
<a href={post.path}>{name}</a>
3124
</h2>
3225
<p class={s.excerpt}>{excerpt}</p>
33-
<a href={post.path} onMouseOver={prefetchAndPreload} onTouchStart={prefetchAndPreload} class="btn-small">
26+
<a href={post.path} class="btn-small">
3427
{continueReading} &rarr;
3528
</a>
3629
</article>

src/components/content-region/index.jsx

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,9 @@ import widgets from '../widgets';
44
import style from './style.module.css';
55
import { useTranslation } from '../../lib/i18n';
66
import { TocContext } from '../table-of-contents';
7-
import { prefetchContent } from '../../lib/use-content';
8-
import { ReplPage, TutorialPage, CodeEditor } from '../routes';
97

108
const COMPONENTS = {
11-
...widgets,
12-
a(props) {
13-
if (props.href && props.href.startsWith('/')) {
14-
const url = new URL(props.href, location.origin);
15-
16-
const prefetchAndPreload = () => {
17-
if (props.href.startsWith('/repl')) {
18-
ReplPage.preload();
19-
CodeEditor.preload();
20-
} else if (props.href.startsWith('/tutorial')) {
21-
TutorialPage.preload();
22-
CodeEditor.preload();
23-
}
24-
25-
prefetchContent(url.pathname);
26-
};
27-
28-
props.onMouseOver = prefetchAndPreload;
29-
props.onTouchStart = prefetchAndPreload;
30-
}
31-
32-
return <a {...props} />;
33-
}
9+
...widgets
3410
};
3511

3612
function SiblingNav({ route, lang, start }) {
@@ -73,7 +49,11 @@ export default function ContentRegion({ content, components, ...props }) {
7349
}, [props.current]);
7450

7551
return (
76-
<content-region name={props.current} data-page-nav={hasNav} can-edit={props.canEdit}>
52+
<content-region
53+
name={props.current}
54+
data-page-nav={hasNav}
55+
can-edit={props.canEdit}
56+
>
7757
{content && (
7858
<TocContext.Provider value={{ toc: props.toc }}>
7959
<Markup

src/components/header/index.jsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import Corner from './corner';
99
import { useOverlayToggle } from '../../lib/toggle-overlay';
1010
import { useLocation } from 'preact-iso';
1111
import { useLanguage, useTranslation, useNavTranslation } from '../../lib/i18n';
12-
import { prefetchContent } from '../../lib/use-content';
13-
import { ReplPage, TutorialPage, CodeEditor } from '../routes';
1412

1513
export default function Header() {
1614
const { url } = useLocation();
@@ -240,21 +238,6 @@ function ExpandableNavLink({ isOpen, label, children, ...rest }) {
240238
);
241239
}
242240

243-
/**
244-
* @param {string} href
245-
*/
246-
const prefetchAndPreload = href => {
247-
if (href.startsWith('/repl')) {
248-
ReplPage.preload();
249-
CodeEditor.preload();
250-
} else if (href.startsWith('/tutorial')) {
251-
TutorialPage.preload();
252-
CodeEditor.preload();
253-
}
254-
255-
prefetchContent(href);
256-
};
257-
258241
/**
259242
* @typedef {Object} NavLinkProps
260243
* @property {string} props.href
@@ -273,8 +256,6 @@ function NavLink({ href, flair, clsx, isOpen, ...rest }) {
273256
return (
274257
<a
275258
href={href}
276-
onMouseOver={() => prefetchAndPreload(href)}
277-
onTouchStart={() => prefetchAndPreload(href)}
278259
class={cx(pathMatchesHref(path, href) && style.current, clsx)}
279260
{...rest}
280261
>

src/components/sidebar/sidebar-nav.jsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useRoute } from 'preact-iso';
22
import cx from '../../lib/cx';
3-
import { prefetchContent } from '../../lib/use-content';
43
import style from './sidebar-nav.module.css';
54

65
/**
@@ -69,8 +68,6 @@ function SidebarNavLink(props) {
6968
<a
7069
href={href}
7170
onClick={onClick}
72-
onMouseOver={() => prefetchContent(href)}
73-
onTouchStart={() => prefetchContent(href)}
7471
class={cx(style.link, activeCss, style['level-' + level])}
7572
>
7673
{children}

src/lib/use-delegated-prefetch.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useEffect } from 'preact/hooks';
2+
3+
import { prefetchContent } from './use-content.js';
4+
import {
5+
ReplPage,
6+
TutorialPage,
7+
CodeEditor,
8+
BlogPage
9+
} from '../components/routes.jsx';
10+
11+
export function useDelegatedPrefetch() {
12+
useEffect(() => {
13+
const prefetchAndPreload = e => {
14+
if (e.target.tagName === 'A') {
15+
if (!e.target.href.startsWith(location.origin)) return;
16+
const pathname = new URL(e.target.href).pathname;
17+
18+
if (pathname.startsWith('/repl')) {
19+
ReplPage.preload();
20+
CodeEditor.preload();
21+
} else if (pathname.startsWith('/tutorial')) {
22+
TutorialPage.preload();
23+
CodeEditor.preload();
24+
} else if (pathname.startsWith('/blog/')) {
25+
BlogPage.preload();
26+
}
27+
28+
prefetchContent(pathname);
29+
}
30+
};
31+
32+
addEventListener('mouseover', prefetchAndPreload);
33+
addEventListener('touchstart', prefetchAndPreload);
34+
35+
return () => {
36+
removeEventListener('mouseover', prefetchAndPreload);
37+
removeEventListener('touchstart', prefetchAndPreload);
38+
};
39+
}, []);
40+
}

0 commit comments

Comments
 (0)