Skip to content

Commit

Permalink
docs: add example of dynamic layout with static page
Browse files Browse the repository at this point in the history
you can see the time change as navigating the site which shows
that the layout is indeed dynamic

The rest of the home page stays unchanged and can be cached

Example for dai-shi#885
  • Loading branch information
tylersayshi committed Sep 30, 2024
1 parent 8b38ceb commit 23c60c3
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 0 deletions.
23 changes: 23 additions & 0 deletions examples/25_weave_render/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "waku-example",
"version": "0.1.0",
"type": "module",
"private": true,
"scripts": {
"dev": "waku dev",
"build": "waku build",
"start": "waku start"
},
"dependencies": {
"react": "19.0.0-rc-d6cb4e77-20240911",
"react-dom": "19.0.0-rc-d6cb4e77-20240911",
"react-server-dom-webpack": "19.0.0-rc-d6cb4e77-20240911",
"waku": "0.21.2"
},
"devDependencies": {
"@types/react": "18.3.5",
"@types/react-dom": "18.3.0",
"server-only": "0.0.1",
"typescript": "5.6.2"
}
}
19 changes: 19 additions & 0 deletions examples/25_weave_render/src/components/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import { useState } from 'react';

import { Link, useRouter_UNSTABLE as useRouter } from 'waku/router/client';

export const Counter = () => {
const { path } = useRouter();
const [count, setCount] = useState(0);
return (
<div style={{ border: '3px blue dashed', margin: '1em', padding: '1em' }}>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<h3>This is a client component.</h3>
<span>path: {path}</span>
<Link to="/">Go to Home</Link>
</div>
);
};
12 changes: 12 additions & 0 deletions examples/25_weave_render/src/components/FooPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'server-only';

import { Counter } from './Counter';

const Foo = () => (
<div>
<h2>Foo</h2>
<Counter />
</div>
);

export default Foo;
58 changes: 58 additions & 0 deletions examples/25_weave_render/src/components/HomeLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { ReactNode } from 'react';

import { Link } from 'waku/router/client';

import '../styles.css';

const Pending = ({ isPending }: { isPending: boolean }) => (
<span
style={{
marginLeft: 5,
transition: 'opacity 75ms 100ms',
opacity: isPending ? 1 : 0,
}}
>
Pending...
</span>
);

const getCurrentTime = () => new Date();

const HomeLayout = ({ children }: { children: ReactNode }) => {
const currentTime = getCurrentTime();
return (
<html>
<head>
<title>Waku</title>
</head>
<body>
<div>
<p>Last render time: {currentTime.toISOString()}</p>
<ul>
<li>
<Link
to="/"
pending={<Pending isPending />}
notPending={<Pending isPending={false} />}
>
Home
</Link>
</li>
<li>
<Link
to="/foo"
pending={<Pending isPending />}
notPending={<Pending isPending={false} />}
>
Foo
</Link>
</li>
</ul>
{children}
</div>
</body>
</html>
);
};

export default HomeLayout;
8 changes: 8 additions & 0 deletions examples/25_weave_render/src/components/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const Home = () => (
<div>
<h2>Home</h2>
<p>This is the home page.</p>
</div>
);

export default Home;
36 changes: 36 additions & 0 deletions examples/25_weave_render/src/entries.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { lazy } from 'react';
import { createPages } from 'waku';
import type { PathsForPages } from 'waku/router';
import FooPage from './components/FooPage';

// The use of `lazy` is optional and you can use import statements too.
const HomeLayout = lazy(() => import('./components/HomeLayout'));
const HomePage = lazy(() => import('./components/HomePage'));

const pages = createPages(async ({ createPage, createLayout }) => [
createLayout({
render: 'dynamic',
path: '/',
component: HomeLayout,
}),

createPage({
render: 'static',
path: '/',
component: HomePage,
}),

createPage({
render: 'static',
path: '/foo',
component: FooPage,
}),
]);

declare module 'waku/router' {
interface RouteConfig {
paths: PathsForPages<typeof pages>;
}
}

export default pages;
15 changes: 15 additions & 0 deletions examples/25_weave_render/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { StrictMode } from 'react';
import { createRoot, hydrateRoot } from 'react-dom/client';
import { Router } from 'waku/router/client';

const rootElement = (
<StrictMode>
<Router />
</StrictMode>
);

if ((globalThis as any).__WAKU_HYDRATE__) {
hydrateRoot(document, rootElement);
} else {
createRoot(document as any).render(rootElement);
}
3 changes: 3 additions & 0 deletions examples/25_weave_render/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: #fefefe;
}
15 changes: 15 additions & 0 deletions examples/25_weave_render/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"strict": true,
"target": "esnext",
"downlevelIteration": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"skipLibCheck": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"types": ["react/experimental"],
"jsx": "react-jsx"
}
}
28 changes: 28 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 23c60c3

Please sign in to comment.