Skip to content

Commit 3ca6de5

Browse files
authored
feat: partial hydration (#951)
* feat: partial hydration * fixup!
1 parent 96e1c26 commit 3ca6de5

20 files changed

Lines changed: 578 additions & 479 deletions

File tree

package-lock.json

Lines changed: 305 additions & 401 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@
5353
"README.md"
5454
],
5555
"dependencies": {
56+
"@11ty/is-land": "^5.0.1",
5657
"@actions/core": "^3.0.0",
5758
"@fontsource-variable/open-sans": "^5.3.0",
5859
"@fontsource/ibm-plex-mono": "^5.3.0",
5960
"@heroicons/react": "^2.2.0",
60-
"@node-core/rehype-shiki": "^1.4.2",
61-
"@node-core/ui-components": "^1.7.2",
61+
"@node-core/rehype-shiki": "^1.4.3",
62+
"@node-core/ui-components": "^1.7.4",
6263
"@orama/orama": "^3.1.18",
6364
"@orama/ui": "^1.5.4",
6465
"@swc/html-wasm": "^1.15.43",

packages/core/src/generators/web/bundlers/vite.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ export const createViteConfig = ({
236236
...(server ? { manifest: false } : {}),
237237
ssr: server,
238238

239+
// Islands make split CSS wrong: a component's stylesheet would arrive
240+
// with the chunk that hydrates it, long after the server-rendered markup
241+
// it styles is on screen. One stylesheet keeps the page styled from the
242+
// first paint, whenever — or whether — its islands load.
243+
...(server ? {} : { cssCodeSplit: false }),
244+
239245
// Browser output follows the generator's minification setting. Temporary
240246
// server output stays readable and disappears immediately after render.
241247
minify: server ? false : (vite.build?.minify ?? webConfig.minify),

packages/core/src/generators/web/constants.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const JSX_IMPORTS = {
2424
},
2525
CodeTabs: {
2626
name: 'CodeTabs',
27-
source: '@node-core/ui-components/MDX/CodeTabs',
27+
source: resolve(ROOT, './ui/components/CodeTabs'),
2828
},
2929
MDXTooltip: {
3030
name: 'MDXTooltip',

packages/core/src/generators/web/ui/components/Banner.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ArrowUpRightIcon } from '@heroicons/react/24/outline';
22
import Banner from '@node-core/ui-components/Common/Banner';
33

44
import useBanners from '../hooks/useBanners.mjs';
5+
import withIsland from '../islands/withIsland.jsx';
56

67
import { remoteConfigUrl, version } from '#theme/config';
78

@@ -29,4 +30,4 @@ const Banners = () => {
2930
);
3031
};
3132

32-
export default Banners;
33+
export default withIsland(Banners, { name: 'Banner', on: { idle: true } });

packages/core/src/generators/web/ui/components/CodeBox.jsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import BaseCodeBox from '@node-core/ui-components/Common/BaseCodeBox';
22

3+
import withIsland from '../islands/withIsland.jsx';
4+
35
import { languageDisplayNameMap } from '#theme/config';
46

57
/**
@@ -15,7 +17,7 @@ export const getLanguageDisplayName = language => {
1517
};
1618

1719
/** @param {import('react').PropsWithChildren<{ className: string }>} props */
18-
export default ({ className, ...props }) => {
20+
const CodeBox = ({ className, ...props }) => {
1921
const matches = className?.match(/language-(?<language>[a-zA-Z]+)/);
2022

2123
const language = matches?.groups?.language ?? '';
@@ -31,3 +33,10 @@ export default ({ className, ...props }) => {
3133
/>
3234
);
3335
};
36+
37+
// The only interactive part is the copy button; the highlighted code itself is
38+
// static markup, so it stays in the server output and is never re-rendered.
39+
export default withIsland(CodeBox, {
40+
name: 'CodeBox',
41+
on: { interaction: 'pointerover,focusin,touchstart' },
42+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import CodeTabs from '@node-core/ui-components/MDX/CodeTabs';
2+
3+
import withIsland from '../islands/withIsland.jsx';
4+
5+
export default withIsland(CodeTabs, {
6+
name: 'CodeTabs',
7+
on: { interaction: 'pointerover,focusin,touchstart' },
8+
});

packages/core/src/generators/web/ui/components/Layout/index.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import Article from '@node-core/ui-components/Containers/Article';
33

44
import Banner from '../Banner';
55

6-
import { server } from '#theme/config';
76
import Footer from '#theme/Footer';
87
import MetaBar from '#theme/Metabar';
98
import NavBar from '#theme/Navigation';
@@ -20,7 +19,7 @@ import SideBar from '#theme/Sidebar';
2019
*/
2120
export default ({ metadata, headings, readingTime, children }) => (
2221
<>
23-
{!server && <Banner />}
22+
<Banner />
2423
<NavBar metadata={metadata} />
2524
<Article>
2625
<SideBar metadata={metadata} />
Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,33 @@
1-
import ThemeToggle from '@node-core/ui-components/Common/ThemeToggle';
21
import NavBar from '@node-core/ui-components/Containers/NavBar';
32
import styles from '@node-core/ui-components/Containers/NavBar/index.module.css';
43
import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';
54

65
import SearchBox from './SearchBox';
7-
import { useTheme } from '../hooks/useTheme.mjs';
6+
import ThemeToggle from './ThemeToggle.jsx';
87

98
import { repository, showSearchBox, navigation } from '#theme/config';
109
import Logo from '#theme/Logo';
1110

1211
/**
1312
* NavBar component that displays the headings, search, etc.
1413
*/
15-
export default ({ metadata }) => {
16-
const [themePreference, setThemePreference] = useTheme();
17-
18-
return (
19-
<NavBar
20-
Logo={Logo}
21-
sidebarItemTogglerAriaLabel="Toggle navigation menu"
22-
navItems={navigation.navbar ?? []}
23-
// Drives the active-item highlight, and is dereferenced for every item
24-
// whose link is site-absolute, so it must always be a string.
25-
pathname={metadata.path}
14+
export default ({ metadata }) => (
15+
<NavBar
16+
Logo={Logo}
17+
sidebarItemTogglerAriaLabel="Toggle navigation menu"
18+
navItems={navigation.navbar ?? []}
19+
// Drives the active-item highlight, and is dereferenced for every item
20+
// whose link is site-absolute, so it must always be a string.
21+
pathname={metadata.path}
22+
>
23+
{showSearchBox && <SearchBox pathname={metadata.path} />}
24+
<ThemeToggle />
25+
<a
26+
href={`https://github.com/${repository}`}
27+
aria-label={`View ${repository} on GitHub`}
28+
className={styles.ghIconWrapper}
2629
>
27-
{showSearchBox && <SearchBox pathname={metadata.path} />}
28-
<ThemeToggle
29-
onChange={setThemePreference}
30-
currentTheme={themePreference}
31-
/>
32-
<a
33-
href={`https://github.com/${repository}`}
34-
aria-label={`View ${repository} on GitHub`}
35-
className={styles.ghIconWrapper}
36-
>
37-
<GitHubIcon />
38-
</a>
39-
</NavBar>
40-
);
41-
};
30+
<GitHubIcon />
31+
</a>
32+
</NavBar>
33+
);

packages/core/src/generators/web/ui/components/SearchBox/index.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import SearchHit from '@node-core/ui-components/Common/Search/Results/Hit';
99

1010
import styles from './index.module.css';
1111
import useOrama from '../../hooks/useOrama.mjs';
12+
import withIsland from '../../islands/withIsland.jsx';
1213
import { relativeOrAbsolute } from '../../utils/relativeOrAbsolute.mjs';
1314

1415
/**
@@ -97,4 +98,7 @@ const SearchBox = ({ pathname }) => {
9798
);
9899
};
99100

100-
export default SearchBox;
101+
export default withIsland(SearchBox, {
102+
name: 'SearchBox',
103+
on: { interaction: 'pointerover,focusin,touchstart' },
104+
});

0 commit comments

Comments
 (0)