;
8 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/pages/about.module.css:
--------------------------------------------------------------------------------
1 | .h1 {
2 | font-size: 2.25rem;
3 | line-height: 2.5rem;
4 | font-weight: 700;
5 | letter-spacing: -0.025em;
6 | }
7 |
8 | .link {
9 | margin-top: 1rem;
10 | display: inline-block;
11 | text-decoration-line: underline;
12 | }
13 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | .h1 {
2 | font-size: 2.25rem;
3 | line-height: 2.5rem;
4 | font-weight: 700;
5 | letter-spacing: -0.025em;
6 | }
7 |
8 | .link {
9 | margin-top: 1rem;
10 | display: inline-block;
11 | text-decoration-line: underline;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/website/src/components/smart-quotes.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect } from 'react';
4 | import smartquotes from 'smartquotes';
5 |
6 | export function SmartQuotes() {
7 | useEffect(() => {
8 | smartquotes().listen();
9 | }, []);
10 |
11 | return null;
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/src/components/DynamicLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export default function DynamicLayout({ children }: { children: ReactNode }) {
4 | return (
5 | <>
6 | Dynamic Layout
7 | {children}
8 | >
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/packages/waku/tests/fixtures/plugin-fs-router-typegen-with-fsrouter-fake/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { createPages as fsRouter } from 'waku';
2 | import adapter from 'waku/adapters/default';
3 |
4 | export default adapter(
5 | fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' }) as never),
6 | );
7 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/src/pages/static.tsx:
--------------------------------------------------------------------------------
1 | export default async function AboutPage() {
2 | return (
3 |
4 |
Static page
5 |
Renderd at {new Date().toISOString()}
6 |
Argv: {JSON.stringify(process.argv.slice(2))}
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/components/ClientTitle.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect } from 'react';
4 |
5 | export const ClientTitle = ({ children }: { children: string }) => {
6 | useEffect(() => {
7 | document.title = children;
8 | }, [children]);
9 | return null;
10 | };
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/src/routes/page.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | const Home = () => (
4 |
5 |
Home
6 |
This is the home page.
7 |
8 |
9 | );
10 |
11 | export default Home;
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-catch-error/src/pages/invalid.tsx:
--------------------------------------------------------------------------------
1 | export default async function InvalidPage() {
2 | return (
3 |
6 | );
7 | }
8 |
9 | export const getConfig = async () => {
10 | return {
11 | render: 'dynamic',
12 | } as const;
13 | };
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-catch-error/waku.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'waku/config';
2 |
3 | export default defineConfig({
4 | /**
5 | * Base path for HTTP requests to indicate RSC requests.
6 | * Defaults to "RSC".
7 | */
8 | rscBase: 'RSC', // Just for clarification in tests
9 | });
10 |
--------------------------------------------------------------------------------
/packages/waku/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "..",
5 | "outDir": "./dist",
6 | "lib": ["esnext"]
7 | },
8 | "include": ["."],
9 | "references": [
10 | {
11 | "path": ".."
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "monorepo",
3 | "private": true,
4 | "workspaces": [
5 | "packages/*"
6 | ],
7 | "dependencies": {
8 | "react": "19.2.3",
9 | "react-dom": "19.2.3",
10 | "react-server-dom-webpack": "19.2.3",
11 | "waku": "latest"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/src/components/DeeplyNestedLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export const DeeplyNestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Deeply Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/src/components/ServerThrows/index.tsx:
--------------------------------------------------------------------------------
1 | import { throws } from '../funcs.js';
2 | import { Counter } from './Counter.js';
3 |
4 | export function ServerThrows() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/custom-library-adapter/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | export default function Page() {
2 | return (
3 |
4 | Hello from custom adapter
5 |
6 | );
7 | }
8 |
9 | export const getConfig = async () => ({ render: 'static' as const });
10 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/hello-server.tsx:
--------------------------------------------------------------------------------
1 | import { HelloClient } from '../components/hello-client.js';
2 |
3 | export default async function HelloServer() {
4 | return ;
5 | }
6 |
7 | export const getConfig = () => {
8 | return {
9 | render: 'dynamic',
10 | } as const;
11 | };
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/src/pages/destination.tsx:
--------------------------------------------------------------------------------
1 | export default async function DestinationPage() {
2 | return (
3 |
4 |
Destination Page
5 |
6 | );
7 | }
8 |
9 | export const getConfig = async () => {
10 | return {
11 | render: 'static',
12 | } as const;
13 | };
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-target-bundle/src/components/Textarea.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 | import TextareaAutosize from 'react-textarea-autosize';
3 |
4 | export const Textarea = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/components/DeeplyNestedLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export const DeeplyNestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Deeply Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/examples/43_weave-render/src/components/FooLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const FooLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
FOO layout
7 | {children}
8 |
9 | );
10 | };
11 |
12 | export default FooLayout;
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/nested/_layout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const NestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
12 | export default NestedLayout;
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/src/pages/css-modules-client.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import styles from './css-modules-client.module.css';
4 |
5 | export default function CssModulesClient() {
6 | return (
7 |
8 | Hello
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/styled-components/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from '../components/Counter';
2 |
3 | export default function HomePage() {
4 | return (
5 |
6 |
Waku - styled-components
7 | styled-components Example
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/nested/_layout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const NestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
12 | export default NestedLayout;
13 |
--------------------------------------------------------------------------------
/examples/52_tanstack-router/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { App } from './app';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | createRoot(document as any).render(rootElement);
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/src/components/NestedLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const NestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
12 | export default NestedLayout;
13 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/components/NestedLayout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const NestedLayout = ({ children }: { children: ReactNode }) => {
4 | return (
5 |
6 |
Nested Layout
7 | {children}
8 |
9 | );
10 | };
11 |
12 | export default NestedLayout;
13 |
--------------------------------------------------------------------------------
/examples/51_spa/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import App from './components/App';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | createRoot(document as any).render(rootElement);
12 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/components/Root.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export default function Root({ children }: { children: ReactNode }) {
4 | return (
5 |
6 |
7 | Waku
8 |
9 | {children}
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/components/SlicePage.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | export default function SlicePage() {
4 | return (
5 |
6 |
Slice Page
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/examples/22_define-router/src/components/Root.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export default function Root({ children }: { children: ReactNode }) {
4 | return (
5 |
6 |
7 | Waku
8 |
9 | {children}
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | createRoot(document as any).render(rootElement);
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/functions/say-hello.tsx:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import { SayHello } from '../components/say-hello.js';
4 |
5 | export async function sayHello() {
6 | const promise = new Promise((resolve) =>
7 | setTimeout(() => resolve('React'), 1000),
8 | );
9 | return ;
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/bar.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from './_components/Counter.js';
2 |
3 | const Bar = () => (
4 |
5 |
Bar
6 |
7 |
8 | );
9 |
10 | export const getConfig = () => {
11 | return {
12 | render: 'dynamic',
13 | } as const;
14 | };
15 |
16 | export default Bar;
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-catch-error/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { fsRouter } from 'waku';
2 | import adapter from 'waku/adapters/default';
3 | import validatorMiddleware from './middleware/validator';
4 |
5 | export default adapter(
6 | fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })),
7 | { middlewareFns: [validatorMiddleware] },
8 | );
9 |
--------------------------------------------------------------------------------
/e2e/fixtures/styled-components/src/pages/_layout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 | import { StyledComponentsRegistry } from '../components/StyledComponentsRegistry';
3 |
4 | export default function RootLayout({ children }: { children: ReactNode }) {
5 | return {children} ;
6 | }
7 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/bar.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from './_components/Counter';
2 |
3 | const Bar = () => (
4 |
5 |
Bar
6 |
7 |
8 | );
9 |
10 | export const getConfig = () => {
11 | return {
12 | render: 'dynamic',
13 | } as const;
14 | };
15 |
16 | export default Bar;
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/custom-user-adapter/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | export default function Page() {
2 | return (
3 |
4 |
5 | Hello from custom user adapter
6 |
7 |
8 | );
9 | }
10 |
11 | export const getConfig = async () => ({ render: 'static' as const });
12 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/foo/index.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from '../_components/Counter';
2 |
3 | const Foo = () => (
4 |
5 |
Foo
6 |
7 |
8 | );
9 |
10 | export const getConfig = () => {
11 | return {
12 | render: 'dynamic',
13 | } as const;
14 | };
15 |
16 | export default Foo;
17 |
--------------------------------------------------------------------------------
/examples/51_spa/src/functions/greet.tsx:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | export async function greet() {
4 | const now = new Date().toISOString();
5 | console.log('greet', now);
6 | return (
7 |
8 |
Hello from server ({now})
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/packages/waku/src/router/server.ts:
--------------------------------------------------------------------------------
1 | export {
2 | unstable_defineRouter,
3 | unstable_getRscPath,
4 | unstable_getRscParams,
5 | unstable_rerenderRoute,
6 | unstable_notFound,
7 | unstable_redirect,
8 | } from './define-router.js';
9 | export { createPages } from './create-pages.js';
10 | export { fsRouter } from './fs-router.js';
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/foo/index.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from '../_components/Counter.js';
2 |
3 | const Foo = () => (
4 |
5 |
Foo
6 |
7 |
8 | );
9 |
10 | export const getConfig = () => {
11 | return {
12 | render: 'dynamic',
13 | } as const;
14 | };
15 |
16 | export default Foo;
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/packages/context-library/src/context-provider.js:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { createContext, createElement } from 'react';
4 |
5 | export const Context = createContext('original');
6 |
7 | export const ContextProvider = ({ children }) => {
8 | return createElement(Context, { value: 'provider value' }, children);
9 | };
10 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/components/footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | padding: 1.5rem;
3 | }
4 |
5 | @media (min-width: 1024px) {
6 | .footer {
7 | position: fixed;
8 | bottom: 0px;
9 | left: 0px;
10 | }
11 | }
12 |
13 | .a {
14 | margin-top: 1rem;
15 | display: inline-block;
16 | text-decoration-line: underline;
17 | }
18 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/debug.tsx:
--------------------------------------------------------------------------------
1 | import { getRouterConfigs } from '../waku.server.js';
2 |
3 | export default async function Debug() {
4 | const configs = await getRouterConfigs();
5 | return (
6 |
7 |
Route inspection
8 |
{JSON.stringify(configs, null, 2)}
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.eslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "noEmit": true,
5 | "allowJs": true
6 | },
7 | "include": [
8 | "eslint.config.ts",
9 | "packages/",
10 | "examples/",
11 | "e2e/",
12 | "playwright.config.ts"
13 | ],
14 | "exclude": ["**/node_modules", "**/dist"]
15 | }
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/build/dynamic.tsx:
--------------------------------------------------------------------------------
1 | export default async function Dynamic() {
2 | return (
3 |
4 | [dynamic]
5 |
6 | phase =
7 |
8 | {String((globalThis as any).__WAKU_IS_BUILD__ === true)}
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-basic/src/components/test-client.tsx:
--------------------------------------------------------------------------------
1 | // https://github.com/wakujs/waku/pull/1539
2 |
3 | 'use client';
4 |
5 | import { use } from 'react';
6 |
7 | const promise = Promise.resolve('test');
8 |
9 | export function TestClient() {
10 | const data = use(promise);
11 | return {data}
;
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/wildcard-api-routes/src/pages/_root.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | export default function Root({ children }: { children: ReactNode }) {
4 | return (
5 |
6 |
7 | Wildcard API Routes
8 |
9 | {children}
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { fsRouter } from 'waku';
2 | import adapter from 'waku/adapters/default';
3 |
4 | const router = fsRouter(
5 | import.meta.glob('./**/*.{tsx,ts}', { base: './pages' }),
6 | );
7 |
8 | export const getRouterConfigs = () => router.unstable_getRouterConfigs();
9 |
10 | export default adapter(router);
11 |
--------------------------------------------------------------------------------
/packages/website/src/lib/shiki.ts:
--------------------------------------------------------------------------------
1 | import { createHighlighter } from 'shiki';
2 | import theme from '../theme.json';
3 |
4 | const highlighter = createHighlighter({
5 | langs: ['tsx'],
6 | themes: [theme as any],
7 | });
8 |
9 | export const codeToHtml = async (code: string, options: any) =>
10 | (await highlighter).codeToHtml(code, options);
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/src/components/counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | export const Counter = () => {
6 | const [count, setCount] = useState(0);
7 |
8 | return (
9 | setCount((c) => c + 1)}>
10 | Count: {count}
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/build/static.tsx:
--------------------------------------------------------------------------------
1 | export default async function Static() {
2 | return (
3 |
4 | [static]
5 |
6 | phase ={' '}
7 |
8 | {String((globalThis as any).__WAKU_IS_BUILD__ === true)}
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-target-bundle/README.md:
--------------------------------------------------------------------------------
1 | # SSR Bundling for NPM packages with environment depended code parts
2 |
3 | Choosing the right code based on the `export` section of the `react-textarea-autosize` module based on the backend server deployment target ('node' | 'webworker') and the client browser. No browser only code should be bundled with server only code.
4 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 | import styles from './header.module.css';
3 |
4 | export const Header = () => {
5 | return (
6 |
7 |
8 | Waku starter
9 |
10 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/waku.config.ts:
--------------------------------------------------------------------------------
1 | import react from '@vitejs/plugin-react';
2 | import { defineConfig } from 'waku/config';
3 |
4 | export default defineConfig({
5 | vite: {
6 | plugins: [
7 | react({
8 | babel: {
9 | plugins: ['babel-plugin-react-compiler'],
10 | },
11 | }),
12 | ],
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/packages/waku/.swcrc:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://swc.rs/schema.json",
3 | "jsc": {
4 | "parser": {
5 | "syntax": "typescript"
6 | },
7 | "transform": {
8 | "react": {
9 | "runtime": "automatic"
10 | }
11 | },
12 | "target": "esnext"
13 | },
14 | "sourceMaps": true,
15 | "exclude": [".*\\.d\\.ts$"]
16 | }
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/src/components/hydrated.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useSyncExternalStore } from 'react';
4 |
5 | const noop = () => () => {};
6 |
7 | export const Hydrated = () => {
8 | const ok = useSyncExternalStore(
9 | noop,
10 | () => true,
11 | () => false,
12 | );
13 | return Hydrated: {String(ok)}
;
14 | };
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/src/components/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import {
4 | type ErrorBoundaryProps,
5 | ErrorBoundary as ReactErrorBoundary,
6 | } from 'react-error-boundary';
7 |
8 | const ErrorBoundary = (props: ErrorBoundaryProps) => {
9 | return ;
10 | };
11 |
12 | export default ErrorBoundary;
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/custom-library-adapter/modules/custom-adapter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-waku-adapter",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "exports": {
7 | ".": "./src/index.js",
8 | "./build-enhancer": "./src/build-enhancer.js"
9 | },
10 | "peerDependencies": {
11 | "waku": "*"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/packages/dummy-library/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dummy-library",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "description": "Dummy package for testing",
6 | "exports": {
7 | "./entry-point": {
8 | "types": "./src/index.d.ts",
9 | "import": "./src/index.js"
10 | }
11 | },
12 | "private": true
13 | }
14 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/_slices/one.tsx:
--------------------------------------------------------------------------------
1 | export default function SliceOne() {
2 | return (
3 |
4 |
5 | Slice One {new Date().toLocaleString()}
6 |
7 |
8 | );
9 | }
10 |
11 | export const getConfig = () => {
12 | return {
13 | render: 'static',
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/_slices/two.tsx:
--------------------------------------------------------------------------------
1 | export default function SliceTwo() {
2 | return (
3 |
4 |
5 | Slice Two {new Date().toLocaleString()}
6 |
7 |
8 | );
9 | }
10 |
11 | export const getConfig = () => {
12 | return {
13 | render: 'dynamic',
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/components/ServerThrows/index.tsx:
--------------------------------------------------------------------------------
1 | import { ServerBox } from '../Box.js';
2 | import { throws } from './actions.js';
3 | import { Counter } from './Counter.js';
4 |
5 | export function ServerThrows() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/wildcard-api-routes/src/pages/[...wildcard].tsx:
--------------------------------------------------------------------------------
1 | const Page = ({ wildcard }: { wildcard: string[] }) => (
2 |
3 |
/{wildcard.join('/')}
4 |
Catch All Pages Route
5 |
6 | );
7 |
8 | export const getConfig = async () => {
9 | return {
10 | render: 'dynamic',
11 | };
12 | };
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/examples/12_nossr/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
6 |
7 | Waku starter
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/nested/[name].tsx:
--------------------------------------------------------------------------------
1 | import type { PageProps } from 'waku/router';
2 |
3 | const Page = ({ name }: PageProps<'/nested/[name]'>) => (
4 |
5 |
Nested / {name}
6 |
7 | );
8 |
9 | export const getConfig = () => {
10 | return {
11 | render: 'dynamic',
12 | } as const;
13 | };
14 |
15 | export default Page;
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssg-wildcard/src/pages/[...wildcard].tsx:
--------------------------------------------------------------------------------
1 | const Page = ({ wildcard }: { wildcard: string[] }) => (
2 |
3 |
/{wildcard.join('/')}
4 |
5 | );
6 |
7 | export const getConfig = async () => {
8 | return {
9 | render: 'static',
10 | staticPaths: [[], 'foo', ['bar', 'baz']],
11 | };
12 | };
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/examples/01_template/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
6 |
7 | Waku starter
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/examples/02_template_js/src/components/header.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
6 |
7 | Waku starter
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/examples/07_cloudflare/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
6 |
7 | Waku starter
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/examples/08_jotai-demo/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
6 |
7 | Waku starter
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/nested/[name].tsx:
--------------------------------------------------------------------------------
1 | import type { PageProps } from 'waku/router';
2 |
3 | const Page = ({ name }: PageProps<'/nested/[name]'>) => (
4 |
5 |
Nested / {name}
6 |
7 | );
8 |
9 | export const getConfig = () => {
10 | return {
11 | render: 'dynamic',
12 | } as const;
13 | };
14 |
15 | export default Page;
16 |
--------------------------------------------------------------------------------
/packages/website/waku.config.ts:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import { defineConfig } from 'waku/config';
3 |
4 | export default defineConfig({
5 | vite: {
6 | plugins: [tailwindcss()],
7 | environments: {
8 | rsc: {
9 | resolve: {
10 | external: ['shiki'],
11 | },
12 | },
13 | },
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/components/ServerAction/Server.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 | import { createAI } from 'ai/rsc';
3 |
4 | const AI = createAI({
5 | foo: async () => {
6 | 'use server';
7 | return 0;
8 | },
9 | });
10 |
11 | export function ServerProvider({ children }: { children: ReactNode }) {
12 | return {children} ;
13 | }
14 |
--------------------------------------------------------------------------------
/examples/42_react-tweet/waku.config.ts:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import { defineConfig } from 'waku/config';
3 |
4 | export default defineConfig({
5 | vite: {
6 | plugins: [tailwindcss()],
7 | optimizeDeps: {
8 | // https://github.com/vitejs/vite-plugin-react/issues/759
9 | exclude: ['react-tweet'],
10 | },
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from '../components/counter';
2 |
3 | export default async function HomePage() {
4 | return (
5 |
6 |
Home page
7 |
8 |
renderd at {new Date().toISOString()}
9 |
argv: {JSON.stringify(process.argv.slice(2))}
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-asset/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | createRoot(document as any).render(rootElement);
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | createRoot(document as any).render(rootElement);
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/src/pages/sync.tsx:
--------------------------------------------------------------------------------
1 | import { unstable_redirect as redirect } from 'waku/router/server';
2 |
3 | export default async function SyncPage() {
4 | await new Promise((resolve) => setTimeout(resolve, 100));
5 | redirect('/destination');
6 | }
7 |
8 | export const getConfig = async () => {
9 | return {
10 | render: 'dynamic',
11 | } as const;
12 | };
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/pages/dynamic-not-found/sync.tsx:
--------------------------------------------------------------------------------
1 | import { unstable_notFound as notFound } from 'waku/router/server';
2 |
3 | export default async function SyncPage() {
4 | await new Promise((resolve) => setTimeout(resolve, 100));
5 | notFound();
6 | }
7 |
8 | export const getConfig = async () => {
9 | return {
10 | render: 'dynamic',
11 | } as const;
12 | };
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-css-modules/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | createRoot(document as any).render(rootElement);
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/pages/exists.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export default function Exists() {
4 | return (
5 |
6 |
Existing page
7 |
8 | Back
9 |
10 |
11 | );
12 | }
13 |
14 | export const getConfig = async () => {
15 | return {
16 | render: 'static',
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-context-provider/src/components/context-provider.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { createContext } from 'react';
4 | import type { ReactNode } from 'react';
5 |
6 | export const Context = createContext('original');
7 |
8 | export const ContextProvider = ({ children }: { children: ReactNode }) => {
9 | return {children} ;
10 | };
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/src/pages/async/index.tsx:
--------------------------------------------------------------------------------
1 | import { unstable_redirect as redirect } from 'waku/router/server';
2 |
3 | export default async function AsyncPage() {
4 | await new Promise((resolve) => setTimeout(resolve, 100));
5 | redirect('/destination');
6 | }
7 |
8 | export const getConfig = async () => {
9 | return {
10 | render: 'dynamic',
11 | } as const;
12 | };
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/pages/dynamic-not-found/async/index.tsx:
--------------------------------------------------------------------------------
1 | import { unstable_notFound as notFound } from 'waku/router/server';
2 |
3 | export default async function AsyncPage() {
4 | await new Promise((resolve) => setTimeout(resolve, 100));
5 | notFound();
6 | }
7 |
8 | export const getConfig = async () => {
9 | return {
10 | render: 'dynamic',
11 | } as const;
12 | };
13 |
--------------------------------------------------------------------------------
/examples/38_cookies/private/items.json:
--------------------------------------------------------------------------------
1 | [
2 | { "id": 1, "name": "John" },
3 | { "id": 2, "name": "Jane" },
4 | { "id": 3, "name": "Bob" },
5 | { "id": 4, "name": "Mary" },
6 | { "id": 5, "name": "Peter" },
7 | { "id": 6, "name": "Kate" },
8 | { "id": 7, "name": "Mike" },
9 | { "id": 8, "name": "Liz" },
10 | { "id": 9, "name": "Steve" },
11 | { "id": 10, "name": "Sue" }
12 | ]
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/components/ServerPing/index.tsx:
--------------------------------------------------------------------------------
1 | import { ServerBox } from '../Box.js';
2 | import { increase, ping, wrap } from './actions.js';
3 | import { Counter } from './Counter.js';
4 |
5 | export function ServerPing() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/examples/51_spa/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import adapter from 'waku/adapters/default';
2 |
3 | export default adapter({
4 | handleRequest: async (input, { renderRsc }) => {
5 | if (input.type === 'function') {
6 | const value = await input.fn(...input.args);
7 | return renderRsc({ _value: value });
8 | }
9 | return 'fallback';
10 | },
11 | handleBuild: async () => {},
12 | });
13 |
--------------------------------------------------------------------------------
/packages/waku/src/lib/utils/create-pages.ts:
--------------------------------------------------------------------------------
1 | /** Remove (group)s from path. Like /(group)/foo => /foo */
2 | export const getGrouplessPath = (path: string) => {
3 | if (path.includes('(')) {
4 | const withoutGroups = path
5 | .split('/')
6 | .filter((part) => !part.startsWith('('));
7 | path = withoutGroups.length > 1 ? withoutGroups.join('/') : '/';
8 | }
9 | return path;
10 | };
11 |
--------------------------------------------------------------------------------
/packages/website/src/components/code.tsx:
--------------------------------------------------------------------------------
1 | import { codeToHtml } from '../lib/shiki';
2 |
3 | type CodeProps = {
4 | code: string;
5 | };
6 |
7 | export const Code = async ({ code, ...rest }: CodeProps) => {
8 | const html = await codeToHtml(code.trim(), {
9 | lang: 'tsx',
10 | theme: 'lucy',
11 | });
12 |
13 | return
;
14 | };
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/tailwindcss/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { TestClient } from '../components/client';
2 |
3 | export default async function HomePage() {
4 | return (
5 |
6 |
7 |
8 |
9 | );
10 | }
11 |
12 | function TestServer() {
13 | return (
14 | test-server
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/_slices/one.tsx:
--------------------------------------------------------------------------------
1 | export default function Slice001() {
2 | // TODO is there a more reasonable way?
3 | // eslint-disable-next-line react-hooks/purity
4 | const rand = Math.random();
5 | return Slice 001 ({rand}) ;
6 | }
7 |
8 | export const getConfig = () => {
9 | return {
10 | render: 'dynamic',
11 | id: 'slice001',
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/packages/waku-project/src/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export const Header = () => {
4 | return (
5 |
8 |
9 | Waku starter
10 |
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/examples/37_css-vanilla-extract/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from '../components/counter';
2 | import { serverStyle } from '../server.css';
3 |
4 | export default async function HomePage() {
5 | return (
6 |
7 |
Waku
8 |
Server Style (green)
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/examples/52_tanstack-router/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import adapter from 'waku/adapters/default';
2 |
3 | export default adapter({
4 | handleRequest: async (input, { renderRsc }) => {
5 | if (input.type === 'function') {
6 | const value = await input.fn(...input.args);
7 | return renderRsc({ _value: value });
8 | }
9 | return 'fallback';
10 | },
11 | handleBuild: async () => {},
12 | });
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/src/pages/dynamic.tsx:
--------------------------------------------------------------------------------
1 | export default function DyanmicPage() {
2 | return (
3 |
4 |
Dynamic page
5 |
renderd at {new Date().toISOString()}
6 |
argv: {JSON.stringify(process.argv.slice(2))}
7 |
8 | );
9 | }
10 |
11 | export const getConfig = async () => {
12 | return {
13 | render: 'dynamic',
14 | } as const;
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/src/pages/about.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export default async function AboutPage() {
4 | return (
5 |
6 |
About Page
7 |
8 | Return home
9 |
10 |
11 | );
12 | }
13 |
14 | export const getConfig = async () => {
15 | return {
16 | render: 'static',
17 | } as const;
18 | };
19 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/pages/_layout.module.css:
--------------------------------------------------------------------------------
1 | .div {
2 | font-family: 'Nunito';
3 | }
4 |
5 | .main {
6 | margin: 1.5rem;
7 | display: flex;
8 | align-items: center;
9 | }
10 |
11 | .main > * {
12 | min-height: 16rem;
13 | min-width: 16rem;
14 | }
15 |
16 | @media (min-width: 1024px) {
17 | .main {
18 | margin: 0px;
19 | min-height: 100svh;
20 | justify-content: center;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/07_cloudflare/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { contextStorage } from 'hono/context-storage';
2 | import { fsRouter } from 'waku';
3 | import adapter from 'waku/adapters/cloudflare';
4 | import cloudflareMiddleware from './middleware/cloudflare';
5 |
6 | export default adapter(
7 | fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })),
8 | { middlewareFns: [contextStorage, cloudflareMiddleware] },
9 | );
10 |
--------------------------------------------------------------------------------
/packages/website/src/lib/load-docs.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'node:fs';
2 |
3 | export const loadReadme = (): string => {
4 | const content = readFileSync('../../README.md', 'utf8');
5 | return content.replace(/\r\n?/g, '\n');
6 | };
7 |
8 | export const loadCreatePages = (): string => {
9 | const file = readFileSync('../../docs/create-pages.mdx', 'utf8');
10 | return file.replace(/\r\n?/g, '\n');
11 | };
12 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export default async function HomePage() {
4 | return (
5 |
6 |
Home Page
7 | Sync Page
8 | Async Page
9 |
10 | );
11 | }
12 |
13 | export const getConfig = async () => {
14 | return {
15 | render: 'static',
16 | } as const;
17 | };
18 |
--------------------------------------------------------------------------------
/examples/03_demo/waku.config.ts:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import react from '@vitejs/plugin-react';
3 | import { defineConfig } from 'waku/config';
4 |
5 | export default defineConfig({
6 | vite: {
7 | plugins: [
8 | tailwindcss(),
9 | react({
10 | babel: {
11 | plugins: ['babel-plugin-react-compiler'],
12 | },
13 | }),
14 | ],
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/slice-page.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | export default function SlicePage() {
4 | return (
5 |
6 |
Slice Page
7 |
8 |
9 |
10 | );
11 | }
12 |
13 | export const getConfig = () => {
14 | return {
15 | render: 'dynamic',
16 | slices: ['one', 'two'],
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/components/funcs.ts:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import { unstable_rerenderRoute } from 'waku/router/server';
4 |
5 | const PAGES = ['/bar', '/baz', '/nested/qux', '/nested/aaa', '/nested/bbb'];
6 |
7 | export const jump = async () => {
8 | const page = PAGES[Math.floor(Math.random() * PAGES.length)] as string;
9 | console.log(`Jumping to ${page}`);
10 | unstable_rerenderRoute(page);
11 | };
12 |
--------------------------------------------------------------------------------
/examples/37_css-vanilla-extract/src/components/counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import { clientStyle } from '../client.css';
5 |
6 | export const Counter = () => {
7 | const [count, setCount] = useState(0);
8 |
9 | return (
10 | setCount((c) => c + 1)} className={clientStyle}>
11 | Client Style: {count} (orange)
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/examples/01_template/waku.config.ts:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import react from '@vitejs/plugin-react';
3 | import { defineConfig } from 'waku/config';
4 |
5 | export default defineConfig({
6 | vite: {
7 | plugins: [
8 | tailwindcss(),
9 | react({
10 | babel: {
11 | plugins: ['babel-plugin-react-compiler'],
12 | },
13 | }),
14 | ],
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/examples/02_template_js/waku.config.js:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import react from '@vitejs/plugin-react';
3 | import { defineConfig } from 'waku/config';
4 |
5 | export default defineConfig({
6 | vite: {
7 | plugins: [
8 | tailwindcss(),
9 | react({
10 | babel: {
11 | plugins: ['babel-plugin-react-compiler'],
12 | },
13 | }),
14 | ],
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/components/header.module.css:
--------------------------------------------------------------------------------
1 | .header {
2 | display: flex;
3 | align-items: center;
4 | gap: 1rem;
5 | padding: 1.5rem;
6 | }
7 |
8 | @media (min-width: 1024px) {
9 | .header {
10 | position: fixed;
11 | left: 0px;
12 | top: 0px;
13 | }
14 | }
15 |
16 | .h2 {
17 | font-size: 1.125rem;
18 | line-height: 1.75rem;
19 | font-weight: 700;
20 | letter-spacing: -0.025em;
21 | }
22 |
--------------------------------------------------------------------------------
/examples/06_form-demo/waku.config.ts:
--------------------------------------------------------------------------------
1 | import tailwindcss from '@tailwindcss/vite';
2 | import react from '@vitejs/plugin-react';
3 | import { defineConfig } from 'waku/config';
4 |
5 | export default defineConfig({
6 | vite: {
7 | plugins: [
8 | tailwindcss(),
9 | react({
10 | babel: {
11 | plugins: ['babel-plugin-react-compiler'],
12 | },
13 | }),
14 | ],
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/packages/waku/tests/fixtures/plugin-fs-router-typegen-with-createpages/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { createPages } from 'waku';
2 | import adapter from 'waku/adapters/default';
3 | import HomePage from './pages/index.js';
4 |
5 | const pages = createPages(async ({ createPage }) => [
6 | createPage({
7 | render: 'static',
8 | path: '/',
9 | component: HomePage,
10 | }),
11 | ]);
12 |
13 | export default adapter(pages);
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/packages/context-library/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "context-library",
3 | "type": "module",
4 | "version": "0.0.0",
5 | "description": "A library with React Context",
6 | "exports": {
7 | "./entry-point": {
8 | "types": "./src/index.d.ts",
9 | "import": "./src/index.js"
10 | }
11 | },
12 | "private": true,
13 | "peerDependencies": {
14 | "react": ">=18.0.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/partial-build/src/pages/_root.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | export default function Root({ children }: { children: ReactNode }) {
4 | return (
5 |
6 |
7 | Waku
8 |
9 | {children}
10 |
11 | );
12 | }
13 |
14 | export const getConfig = async () => {
15 | return {
16 | render: 'static',
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/components/ServerAction/Client.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect } from 'react';
4 | import { useActions } from 'ai/rsc';
5 |
6 | export const ClientActionsConsumer = () => {
7 | const actions = useActions();
8 | useEffect(() => {
9 | (globalThis as any).actions = actions;
10 | }, [actions]);
11 | return globalThis.actions: {JSON.stringify(Object.keys(actions))}
;
12 | };
13 |
--------------------------------------------------------------------------------
/examples/32_minimal_js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "32_minimal_js",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/src/pages/css-modules.tsx:
--------------------------------------------------------------------------------
1 | import styles from './css-modules.module.css';
2 |
3 | export default async function CssModules() {
4 | return (
5 |
6 |
7 | CSS Modules
8 |
9 |
10 | );
11 | }
12 |
13 | export const getConfig = async () => {
14 | return {
15 | render: 'static',
16 | } as const;
17 | };
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/src/pages/async/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Suspense } from 'react';
2 | import type { ReactNode } from 'react';
3 |
4 | export default async function AsyncLayout({
5 | children,
6 | }: {
7 | children: ReactNode;
8 | }) {
9 | return {children} ;
10 | }
11 |
12 | export const getConfig = async () => {
13 | return {
14 | render: 'static',
15 | } as const;
16 | };
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/use-router/src/pages/static.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 | import TestRouter from '../TestRouter.js';
3 |
4 | const Page = () => (
5 | <>
6 | Static
7 |
8 | Go to dynamic
9 |
10 |
11 | >
12 | );
13 |
14 | export const getConfig = async () => {
15 | return {
16 | render: 'static',
17 | };
18 | };
19 |
20 | export default Page;
21 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | const Home = () => {
2 | // TODO is there a more reasonable way?
3 | // eslint-disable-next-line react-hooks/purity
4 | const now = Date.now();
5 | return (
6 |
7 |
Home
8 |
now: {now}
9 |
10 | );
11 | };
12 |
13 | export const getConfig = () => {
14 | return {
15 | render: 'dynamic',
16 | } as const;
17 | };
18 |
19 | export default Home;
20 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/root.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 |
3 | export default function Root() {
4 | return (
5 |
6 |
7 | Build static
8 |
9 |
10 | Build dynamic
11 |
12 |
13 | /server/static
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/examples/36_form/src/components/funcs.ts:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import { rerender } from '../als';
4 |
5 | // module state on server
6 | let message = '';
7 |
8 | export const getMessage = async () => message;
9 |
10 | export const greet = async (formData: FormData) => {
11 | message = `Hello ${formData.get('name') || 'Anonymous'} from server!`;
12 | rerender('');
13 | };
14 |
15 | export const increment = async (count: number) => count + 1;
16 |
--------------------------------------------------------------------------------
/packages/create-waku/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "module": "ESNext",
5 | "rootDir": "./src",
6 | "outDir": "./dist",
7 | "lib": ["esnext"],
8 | "emitDeclarationOnly": false,
9 | "moduleResolution": "bundler"
10 | },
11 | "include": ["./src"],
12 | "exclude": ["./template"],
13 | "references": [
14 | {
15 | "path": "../waku"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/pages/dynamic-not-found/async/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Suspense } from 'react';
2 | import type { ReactNode } from 'react';
3 |
4 | export default async function AsyncLayout({
5 | children,
6 | }: {
7 | children: ReactNode;
8 | }) {
9 | return {children} ;
10 | }
11 |
12 | export const getConfig = async () => {
13 | return {
14 | render: 'static',
15 | } as const;
16 | };
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-basic/src/components/test-app.tsx:
--------------------------------------------------------------------------------
1 | // https://github.com/wakujs/waku/pull/1539
2 |
3 | import { TestClient } from './test-client.js';
4 |
5 | const TestApp = () => {
6 | return (
7 |
8 |
9 | Waku
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | };
19 |
20 | export default TestApp;
21 |
--------------------------------------------------------------------------------
/examples/34_functions/src/components2/funcs2.ts:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import { unstable_getContext as getContext } from 'waku/server';
4 |
5 | export const greet = async (name: string) => {
6 | await Promise.resolve();
7 | return `Hello ${name} from server!`;
8 | };
9 |
10 | export const hello = async (name: string) => {
11 | await Promise.resolve();
12 | console.log('Context:', getContext());
13 | console.log('Hello', name, '!');
14 | };
15 |
--------------------------------------------------------------------------------
/packages/waku/src/lib/vite-entries/entry.server.tsx:
--------------------------------------------------------------------------------
1 | import serverEntry from 'virtual:vite-rsc-waku/server-entry';
2 | import { INTERNAL_setAllEnv } from '../../server.js';
3 |
4 | export { serverEntry as unstable_serverEntry };
5 |
6 | export async function INTERNAL_runFetch(
7 | env: Readonly>,
8 | req: Request,
9 | ...args: any[]
10 | ) {
11 | INTERNAL_setAllEnv(env);
12 | return serverEntry.fetch(req, ...args);
13 | }
14 |
--------------------------------------------------------------------------------
/packages/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "./src",
5 | "outDir": "./dist",
6 | "module": "esnext",
7 | "moduleResolution": "bundler",
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "types": ["node"]
11 | },
12 | "include": ["src", "src/theme.json"],
13 | "references": [
14 | {
15 | "path": "../waku"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | if ((globalThis as any).__WAKU_HYDRATE__) {
12 | hydrateRoot(document, rootElement);
13 | } else {
14 | createRoot(document as any).render(rootElement);
15 | }
16 |
--------------------------------------------------------------------------------
/examples/21_create-pages/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | if ((globalThis as any).__WAKU_HYDRATE__) {
12 | hydrateRoot(document, rootElement);
13 | } else {
14 | createRoot(document as any).render(rootElement);
15 | }
16 |
--------------------------------------------------------------------------------
/examples/34_functions/src/components2/funcs.ts:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import { rerender } from '../als';
4 |
5 | export const greet = async (name: string) => {
6 | await Promise.resolve();
7 | return `Hello ${name} from server!`;
8 | };
9 |
10 | // module state on server
11 | let counter = 0;
12 |
13 | export const getCounter = async () => counter;
14 |
15 | export const increment = async () => {
16 | counter += 1;
17 | rerender('Waku');
18 | };
19 |
--------------------------------------------------------------------------------
/examples/42_react-tweet/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | if ((globalThis as any).__WAKU_HYDRATE__) {
12 | hydrateRoot(document, rootElement);
13 | } else {
14 | createRoot(document as any).render(rootElement);
15 | }
16 |
--------------------------------------------------------------------------------
/examples/43_weave-render/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | if ((globalThis as any).__WAKU_HYDRATE__) {
12 | hydrateRoot(document, rootElement);
13 | } else {
14 | createRoot(document as any).render(rootElement);
15 | }
16 |
--------------------------------------------------------------------------------
/packages/website/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import slugify from '@sindresorhus/slugify';
2 |
3 | export const getAnchor = (value: any) => {
4 | const isString = typeof value === 'string';
5 |
6 | return isString ? slugify(value) : '';
7 | };
8 |
9 | export const scrollTo = (id: string) => {
10 | const element = document.getElementById(id);
11 |
12 | if (element) {
13 | element.scrollIntoView({ behavior: 'smooth', block: 'start' });
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/page-with-segment/(article)/[slug].tsx:
--------------------------------------------------------------------------------
1 | import type { PageProps } from 'waku/router';
2 |
3 | // Create blog article pages
4 | export default async function BlogArticlePage({
5 | slug,
6 | }: PageProps<'/page-with-segment/[slug]'>) {
7 | return {slug} ;
8 | }
9 |
10 | export const getConfig = async () => {
11 | return {
12 | render: 'static',
13 | staticPaths: ['introducing-waku'],
14 | } as const;
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | );
10 |
11 | if ((globalThis as any).__WAKU_HYDRATE__) {
12 | hydrateRoot(document.body, rootElement);
13 | } else {
14 | createRoot(document.body).render(rootElement);
15 | }
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/page-with-segment/article/[slug].tsx:
--------------------------------------------------------------------------------
1 | import type { PageProps } from 'waku/router';
2 |
3 | // Create blog article pages
4 | export default async function BlogArticlePage({
5 | slug,
6 | }: PageProps<'/page-with-segment/article/[slug]'>) {
7 | return {slug} ;
8 | }
9 |
10 | export const getConfig = async () => {
11 | return {
12 | render: 'static',
13 | staticPaths: ['introducing-waku'],
14 | } as const;
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/subroute/[...catchAll].tsx:
--------------------------------------------------------------------------------
1 | import type { PageProps } from 'waku/router';
2 |
3 | function SubrouteCatchAll({ catchAll }: PageProps<'/subroute/[...catchAll]'>) {
4 | return (
5 |
6 |
Subroute Catch-All: {catchAll.join('/')}
7 |
8 | );
9 | }
10 |
11 | export const getConfig = () => {
12 | return {
13 | render: 'dynamic',
14 | } as const;
15 | };
16 |
17 | export default SubrouteCatchAll;
18 |
--------------------------------------------------------------------------------
/examples/03_demo/src/components/reload.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | export const Reload = () => {
4 | const handleReload = () => {
5 | window.location.reload();
6 | };
7 |
8 | return (
9 |
13 | reload
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/examples/36_form/src/als.ts:
--------------------------------------------------------------------------------
1 | import { AsyncLocalStorage } from 'node:async_hooks';
2 |
3 | type Rerender = (rscPath: string) => void;
4 |
5 | const store = new AsyncLocalStorage();
6 |
7 | export const runWithRerender = (rerender: Rerender, fn: () => T): T => {
8 | return store.run(rerender, fn);
9 | };
10 |
11 | export const rerender = (rscPath: string) => {
12 | const fn = store.getStore();
13 | if (fn) {
14 | fn(rscPath);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/examples/37_css/src/components/counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | export const Counter = () => {
6 | const [count, setCount] = useState(0);
7 | return (
8 |
9 |
Count: {count}
10 |
setCount((c) => c + 1)}>Increment
11 |
This is a client component.
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/pages/page-with-slices/index.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | const slices = ['slice001', 'two'] as const;
4 |
5 | export default function Slices() {
6 | return (
7 | <>
8 | Slices
9 |
10 |
11 | >
12 | );
13 | }
14 |
15 | export const getConfig = () => {
16 | return {
17 | render: 'dynamic',
18 | slices,
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/e2e/fixtures/waku-jotai-integration/src/pages/_layout.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 | import { RouterProvider } from 'waku-jotai/router';
3 |
4 | type RootLayoutProps = { children: ReactNode };
5 |
6 | export default async function RootLayout({ children }: RootLayoutProps) {
7 | return {children} ;
8 | }
9 |
10 | export const getConfig = async () => {
11 | return {
12 | render: 'dynamic',
13 | } as const;
14 | };
15 |
--------------------------------------------------------------------------------
/examples/31_minimal/src/components/Counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | export const Counter = () => {
6 | const [count, setCount] = useState(0);
7 | return (
8 |
9 |
Count: {count}
10 |
setCount((c) => c + 1)}>Increment
11 |
This is a client component.
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/examples/34_functions/src/als.ts:
--------------------------------------------------------------------------------
1 | import { AsyncLocalStorage } from 'node:async_hooks';
2 |
3 | type Rerender = (rscPath: string) => void;
4 |
5 | const store = new AsyncLocalStorage();
6 |
7 | export const runWithRerender = (rerender: Rerender, fn: () => T): T => {
8 | return store.run(rerender, fn);
9 | };
10 |
11 | export const rerender = (rscPath: string) => {
12 | const fn = store.getStore();
13 | if (fn) {
14 | fn(rscPath);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/examples/38_cookies/src/components/Counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | export const Counter = () => {
6 | const [count, setCount] = useState(0);
7 | return (
8 |
9 |
Count: {count}
10 |
setCount((c) => c + 1)}>Increment
11 |
This is a client component.
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-context-provider/src/components/app.tsx:
--------------------------------------------------------------------------------
1 | import { ContextConsumer } from './context-consumer.js';
2 | import { ContextProvider } from './context-provider.js';
3 |
4 | export default function App() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/examples/32_minimal_js/src/components/counter.jsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 |
5 | export const Counter = () => {
6 | const [count, setCount] = useState(0);
7 | return (
8 |
9 |
Count: {count}
10 |
setCount((c) => c + 1)}>Increment
11 |
This is a client component.
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/src/routes/bar1/page.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | const Bar1 = () => {
4 | // TODO is there a more reasonable way?
5 | // eslint-disable-next-line react-hooks/purity
6 | const rand = Math.random();
7 | return (
8 |
9 |
Bar1
10 |
{rand}
11 |
12 |
13 | );
14 | };
15 |
16 | export default Bar1;
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/src/routes/bar2/page.tsx:
--------------------------------------------------------------------------------
1 | import { Slice } from 'waku/router/client';
2 |
3 | const Bar2 = () => {
4 | // TODO is there a more reasonable way?
5 | // eslint-disable-next-line react-hooks/purity
6 | const rand = Math.random();
7 | return (
8 |
9 |
Bar2
10 |
{rand}
11 |
12 |
13 | );
14 | };
15 |
16 | export default Bar2;
17 |
--------------------------------------------------------------------------------
/packages/create-waku/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup';
2 |
3 | export default defineConfig((options) => ({
4 | entry: ['src/index.ts'],
5 | external: [/package\.json/],
6 | format: ['esm'],
7 | minify: !options.watch,
8 | clean: true,
9 | /** @see https://github.com/egoist/tsup/issues/927#issuecomment-2354939322 */
10 | banner: {
11 | js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`,
12 | },
13 | }));
14 |
--------------------------------------------------------------------------------
/packages/website/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import { fsRouter } from 'waku';
2 | import nodeAdapter from 'waku/adapters/node';
3 | import vercelAdapter from 'waku/adapters/vercel';
4 |
5 | const adapter: typeof vercelAdapter = process.env.VERCEL
6 | ? vercelAdapter
7 | : nodeAdapter;
8 |
9 | const handler: ReturnType = adapter(
10 | fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' })),
11 | { static: true },
12 | );
13 |
14 | export default handler;
15 |
--------------------------------------------------------------------------------
/examples/32_minimal_js/src/waku.client.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if (globalThis.__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/packages/waku/src/minimal/server.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | Unstable_HandleBuild as HandleBuild,
3 | Unstable_HandleRequest as HandleRequest,
4 | Unstable_ServerEntry as ServerEntry,
5 | } from '../lib/types.js';
6 |
7 | export function unstable_defineHandlers(handlers: {
8 | handleRequest: HandleRequest;
9 | handleBuild: HandleBuild;
10 | }) {
11 | return handlers;
12 | }
13 |
14 | export function unstable_defineServerEntry(fns: ServerEntry['default']) {
15 | return fns;
16 | }
17 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 | import { Counter } from '../components/counter.js';
3 |
4 | export default async function HomePage() {
5 | return (
6 |
7 |
Home Page
8 |
9 |
10 | About
11 |
12 |
13 | );
14 | }
15 |
16 | export const getConfig = async () => {
17 | return {
18 | render: 'static',
19 | } as const;
20 | };
21 |
--------------------------------------------------------------------------------
/packages/waku/src/lib/vite-entries/entry.browser.tsx:
--------------------------------------------------------------------------------
1 | import { setServerCallback } from '@vitejs/plugin-rsc/browser';
2 | import { unstable_callServerRsc } from '../../minimal/client.js';
3 | setServerCallback(unstable_callServerRsc);
4 |
5 | if (import.meta.hot) {
6 | import.meta.hot.on('rsc:update', (e) => {
7 | console.log('[rsc:update]', e);
8 | globalThis.__WAKU_RSC_RELOAD_LISTENERS__?.forEach((l) => l());
9 | });
10 | }
11 |
12 | import 'virtual:vite-rsc-waku/client-entry';
13 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/waku.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'waku/config';
2 | import type { VitePlugin } from 'waku/config';
3 |
4 | function buildMode(): VitePlugin {
5 | return {
6 | name: 'build-mode',
7 | load() {
8 | // FIXME this hack seems fragile.
9 | (globalThis as any).__WAKU_IS_BUILD__ = this.environment.mode === 'build';
10 | },
11 | };
12 | }
13 |
14 | export default defineConfig({
15 | vite: {
16 | plugins: [buildMode()],
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/examples/03_demo/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/12_nossr/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/36_form/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/37_css/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/37_css/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/39_api/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/39_api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/42_react-tweet/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/51_spa/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/54_jotai/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/ClientEcho.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect, useState } from 'react';
4 | import { Echo } from './Echo.js';
5 |
6 | export function ClientEcho({ echo }: { echo: string }) {
7 | const [timeStamp, setTimestamp] = useState(() => Date.now());
8 | useEffect(() => {
9 | const interval = setInterval(() => setTimestamp(Date.now()), 1000);
10 | return () => clearInterval(interval);
11 | });
12 | return ;
13 | }
14 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-swr/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-swr/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/01_template/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/01_template/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/02_template_js/src/components/footer.jsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/06_form-demo/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/07_cloudflare/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/08_jotai-demo/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | export const Footer = () => {
2 | return (
3 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/examples/12_nossr/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/31_minimal/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/31_minimal/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/33_promise/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/34_functions/src/components2/ButtonServer.tsx:
--------------------------------------------------------------------------------
1 | import ButtonClient from './ButtonClient';
2 |
3 | let counter = 0;
4 |
5 | const ButtonServer = ({ name }: { name: string }) => {
6 | const now = Date.now();
7 | async function handleClick() {
8 | 'use server';
9 | console.log('Button clicked!', name, now, ++counter);
10 | }
11 | return (
12 |
13 | {name}
14 |
15 | );
16 | };
17 |
18 | export default ButtonServer;
19 |
--------------------------------------------------------------------------------
/examples/34_functions/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/35_nesting/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/38_cookies/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/41_path-alias/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/53_islands/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/53_islands/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/54_jotai/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/base-path/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/create-pages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-asset/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssg-wildcard/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-basic/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/tailwindcss/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/use-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/11_fs-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/21_create-pages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/22_define-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/37_css-stylex/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/42_react-tweet/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/43_weave-render/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/broken-links/src/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 | import { ClientTitle } from '../components/ClientTitle.js';
3 |
4 | export default function NotFound() {
5 | return (
6 |
7 |
Custom not found
8 |
Custom Not Found Title
9 |
10 | Back
11 |
12 |
13 | );
14 | }
15 |
16 | export const getConfig = async () => {
17 | return {
18 | render: 'static',
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/partial-build/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/render-type/src/ServerEcho.tsx:
--------------------------------------------------------------------------------
1 | import { unstable_getContext as getContext } from 'waku/server';
2 | import { Echo } from './Echo.js';
3 |
4 | export function ServerEcho({ echo }: { echo: string }) {
5 | // TODO is there a more reasonable way?
6 | // eslint-disable-next-line react-hooks/purity
7 | const now = performance.now();
8 | return (
9 | <>
10 |
11 | {getContext().req.url}
12 | >
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-css-modules/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssg-performance/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-catch-error/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-target-bundle/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-target-bundle/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/styled-components/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/45_view-transitions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/52_tanstack-router/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/website/src/components/providers.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import type { ReactNode } from 'react';
4 | import { Provider, createStore } from 'jotai';
5 | import { menuAtom, scrolledAtom } from '../atoms';
6 |
7 | type ProvidersProps = { children: ReactNode };
8 |
9 | const store = createStore();
10 | store.set(menuAtom, false);
11 | store.set(scrolledAtom, false);
12 |
13 | export const Providers = ({ children }: ProvidersProps) => {
14 | return {children} ;
15 | };
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/custom-library-adapter/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/custom-user-adapter/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-basic/src/components/test-env/server.tsx:
--------------------------------------------------------------------------------
1 | export function TestEnvServer() {
2 | const data = {
3 | 'import.meta.env.WAKU_PUBLIC_TEST': import.meta.env.WAKU_PUBLIC_TEST || '-',
4 | 'import.meta.env.WAKU_PRIVATE_TEST':
5 | import.meta.env.WAKU_PRIVATE_TEST || '-',
6 | 'process.env.WAKU_PUBLIC_TEST': process.env.WAKU_PUBLIC_TEST || '-',
7 | 'process.env.WAKU_PRIVATE_TEST': process.env.WAKU_PRIVATE_TEST || '-',
8 | };
9 | return {JSON.stringify(data, null, 2)} ;
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-context-provider/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-context-provider/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/waku-jotai-integration/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/wildcard-api-routes/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/components/footer.tsx:
--------------------------------------------------------------------------------
1 | import styles from './footer.module.css';
2 |
3 | export const Footer = () => {
4 | return (
5 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/examples/37_css-vanilla-extract/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/53_islands/src/components/Dynamic.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 |
3 | const Dynamic = async ({ children }: { children: ReactNode }) => {
4 | await new Promise((resolve) => setTimeout(resolve, 1000));
5 | return (
6 |
7 |
This is a dynamic server component.
8 | {children}
9 |
{new Date().toISOString()}
10 |
11 | );
12 | };
13 |
14 | export default Dynamic;
15 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'packages/*'
3 | - 'examples/*'
4 | - 'e2e/fixtures/*'
5 | # package.json in dist is generated by `waku build`
6 | - '!**/dist'
7 | preferWorkspacePackages: true
8 | saveWorkspaceProtocol: true
9 | linkWorkspacePackages: true
10 | minimumReleaseAge: 1440
11 | minimumReleaseAgeExclude:
12 | - '@hiogawa/node-loader-cloudflare'
13 | - '@vitejs/plugin-rsc'
14 | - 'react'
15 | - 'react-dom'
16 | - 'react-server-dom-webpack'
17 | - 'scheduler'
18 | - 'waku-jotai'
19 |
--------------------------------------------------------------------------------
/e2e/fixtures/monorepo/packages/waku-project/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/src/components/ServerPing/actions.tsx:
--------------------------------------------------------------------------------
1 | 'use server';
2 |
3 | import type { ReactNode } from 'react';
4 |
5 | export const ping = async () => {
6 | return 'pong';
7 | };
8 |
9 | export const increase = async (value: number) => {
10 | return value + 1;
11 | };
12 |
13 | export const wrap = async (node: ReactNode) => {
14 | return {node} ;
15 | };
16 |
17 | export const getData = async () => {
18 | return Server Data ;
19 | };
20 |
--------------------------------------------------------------------------------
/e2e/fixtures/use-router/src/pages/dynamic.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'waku';
2 | import { MyButton } from '../components/my-button.js';
3 | import TestRouter from '../TestRouter.js';
4 |
5 | const Page = () => (
6 | <>
7 | Dynamic
8 |
9 | Go to static
10 |
11 |
12 |
13 | >
14 | );
15 |
16 | export const getConfig = () => {
17 | return {
18 | render: 'dynamic',
19 | } as const;
20 | };
21 |
22 | export default Page;
23 |
--------------------------------------------------------------------------------
/examples/03_demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["node"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/12_nossr/src/waku.server.ts:
--------------------------------------------------------------------------------
1 | import { fsRouter } from 'waku';
2 | import adapter from 'waku/adapters/default';
3 |
4 | const router = fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' }));
5 |
6 | export default adapter({
7 | handleRequest: async (input, utils) => {
8 | if (input.type === 'custom') {
9 | return 'fallback'; // no ssr
10 | }
11 | return router.handleRequest(input, utils);
12 | },
13 | handleBuild: (utils) => {
14 | return router.handleBuild(utils);
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/examples/22_define-router/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { ErrorBoundary, Router } from 'waku/router/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 |
10 |
11 | );
12 |
13 | if ((globalThis as any).__WAKU_HYDRATE__) {
14 | hydrateRoot(document, rootElement);
15 | } else {
16 | createRoot(document as any).render(rootElement);
17 | }
18 |
--------------------------------------------------------------------------------
/examples/36_form/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["node"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/45_view-transitions/src/components/Link.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import type { ComponentProps } from 'react';
4 | import { Link as OrigLink } from 'waku/router/client';
5 |
6 | const startViewTransition =
7 | typeof document !== 'undefined'
8 | ? (fn: () => void) => {
9 | document.startViewTransition(fn);
10 | }
11 | : undefined;
12 |
13 | export function Link(props: ComponentProps) {
14 | return ;
15 | }
16 |
--------------------------------------------------------------------------------
/examples/06_form-demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["node"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/34_functions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["node"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/38_cookies/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["node"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | types: [opened, synchronize]
8 | merge_group:
9 |
10 | jobs:
11 | lint:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v6
15 | - uses: pnpm/action-setup@v4
16 | - uses: actions/setup-node@v6
17 | with:
18 | node-version: 'lts/*'
19 | cache: 'pnpm'
20 | - run: pnpm install
21 | - run: pnpm run compile
22 | - run: pnpm test:lint
23 |
--------------------------------------------------------------------------------
/packages/website/src/atoms/index.ts:
--------------------------------------------------------------------------------
1 | import { atom } from 'jotai';
2 | import { atomWithStorage } from 'jotai/utils';
3 |
4 | export const menuAtom = atom(false);
5 |
6 | export const scrolledAtom = atom(false);
7 |
8 | export const destinationAtom = atom('');
9 |
10 | export type RoutingPreference = 'file-based' | 'config-based';
11 |
12 | const ROUTING_PREFERENCE_KEY = 'waku-routing-preference';
13 |
14 | export const routingTabAtom = atomWithStorage(
15 | ROUTING_PREFERENCE_KEY,
16 | 'file-based',
17 | );
18 |
--------------------------------------------------------------------------------
/examples/08_jotai-demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["react/experimental"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-asset/src/waku.server.tsx:
--------------------------------------------------------------------------------
1 | import adapter from 'waku/adapters/default';
2 | import App from './components/App.js';
3 |
4 | export default adapter({
5 | handleRequest: async (input, { renderRsc }) => {
6 | if (input.type === 'component') {
7 | return renderRsc({ App: });
8 | }
9 | if (input.type === 'function') {
10 | const value = await input.fn(...input.args);
11 | return renderRsc({ _value: value });
12 | }
13 | },
14 | handleBuild: async () => {},
15 | });
16 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/modules/ai/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ai",
3 | "type": "module",
4 | "version": "1.0.0",
5 | "description": "Vercel AI mockup",
6 | "exports": {
7 | "./rsc": {
8 | "types": "./src/index.d.ts",
9 | "react-server": "./src/server.js",
10 | "import": "./src/client.js"
11 | }
12 | },
13 | "devDependencies": {
14 | "react-dom": "^18",
15 | "react-server-dom-webpack": "~19.2.3"
16 | },
17 | "peerDependencies": {
18 | "react": "^18 || ^19"
19 | },
20 | "private": true
21 | }
22 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-catch-error/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorBoundary } from 'react-error-boundary';
2 | import ThrowsComponent from '../components/server/throws.js';
3 |
4 | export default async function HomePage() {
5 | return (
6 |
7 |
Home Page
8 |
Something went wrong }>
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export const getConfig = async () => {
16 | return {
17 | render: 'static',
18 | } as const;
19 | };
20 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-swr/src/components/App.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from './Counter.js';
2 |
3 | const App = ({ name }: { name: string }) => {
4 | return (
5 |
6 |
7 | Waku example
8 |
9 |
10 |
13 |
{name}
14 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/examples/04_cssmodules/src/components/counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import styles from './counter.module.css';
5 |
6 | export const Counter = () => {
7 | const [count, setCount] = useState(0);
8 |
9 | const handleIncrement = () => setCount((c) => c + 1);
10 |
11 | return (
12 |
13 | Count: {count}
14 |
15 | Increment
16 |
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/examples/07_cloudflare/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "types": ["./worker-configuration.d.ts"],
16 | "jsx": "react-jsx"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/33_promise/src/waku.client.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react';
2 | import { createRoot, hydrateRoot } from 'react-dom/client';
3 | import { Root, Slot } from 'waku/minimal/client';
4 |
5 | const rootElement = (
6 |
7 |
8 |
9 | A client element
10 |
11 |
12 |
13 | );
14 |
15 | if ((globalThis as any).__WAKU_HYDRATE__) {
16 | hydrateRoot(document, rootElement);
17 | } else {
18 | createRoot(document as any).render(rootElement);
19 | }
20 |
--------------------------------------------------------------------------------
/examples/42_react-tweet/src/templates/home-page.tsx:
--------------------------------------------------------------------------------
1 | import { Tweet } from 'react-tweet';
2 |
3 | export const HomePage = async () => {
4 | const data = await getData();
5 |
6 | return (
7 |
8 |
{data.title}
9 | {data.headline}
10 |
11 |
12 | );
13 | };
14 |
15 | const getData = async () => {
16 | const data = {
17 | title: 'Waku',
18 | headline: 'Waku',
19 | };
20 |
21 | return data;
22 | };
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-basic/modules/ai/src/shared.js:
--------------------------------------------------------------------------------
1 | 'use client';
2 | import { createContext, useContext } from 'react';
3 | import { jsx } from 'react/jsx-runtime';
4 |
5 | const ActionContext = createContext(null);
6 |
7 | export function useActions() {
8 | return useContext(ActionContext);
9 | }
10 |
11 | export function InternalProvider(props) {
12 | return jsx('div', {
13 | 'data-testid': 'ai-internal-provider',
14 | children: jsx(ActionContext, {
15 | value: props.actions,
16 | children: props.children,
17 | }),
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/examples/36_form/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "36_form",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/37_css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "37_css",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "classnames": "2.3.2",
13 | "react": "~19.2.3",
14 | "react-dom": "~19.2.3",
15 | "react-server-dom-webpack": "~19.2.3",
16 | "waku": "0.27.5"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^19.2.7",
20 | "@types/react-dom": "^19.2.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/39_api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "39_api",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/51_spa/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "51_spa",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/styled-components/src/components/Counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import styled from 'styled-components';
5 |
6 | const Button = styled.button`
7 | border: 1px solid orange;
8 | padding: 0.5rem 1rem;
9 | background: transparent;
10 | cursor: pointer;
11 | &:hover {
12 | background: rgba(255, 165, 0, 0.1);
13 | }
14 | `;
15 |
16 | export const Counter = () => {
17 | const [count, setCount] = useState(0);
18 | return setCount((c) => c + 1)}>Count: {count} ;
19 | };
20 |
--------------------------------------------------------------------------------
/examples/41_path-alias/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "noEmit": true,
6 | "isolatedModules": true,
7 | "moduleDetection": "force",
8 | "downlevelIteration": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "skipLibCheck": true,
13 | "noUncheckedIndexedAccess": true,
14 | "exactOptionalPropertyTypes": true,
15 | "jsx": "react-jsx",
16 | "paths": {
17 | "@/*": ["./src/*"]
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fs-router",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/fs-router/src/components/hello-client.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Suspense, useEffect, useState } from 'react';
4 | import { sayHello } from '../functions/say-hello.js';
5 |
6 | export function HelloClient() {
7 | const [isClient, setIsClient] = useState(false);
8 | useEffect(() => {
9 | // FIXME what should be the best practice for this case?
10 | // eslint-disable-next-line react-hooks/set-state-in-effect
11 | setIsClient(true);
12 | }, []);
13 | return isClient && {sayHello()} ;
14 | }
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/hot-reload/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hot-reload",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/rsc-asset/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rsc-asset",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/use-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "use-router",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/11_fs-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "11_fs-router",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/11_fs-router/src/pages/_components/Counter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import { Link } from 'waku/router/client';
5 |
6 | export const Counter = () => {
7 | const [count, setCount] = useState(0);
8 | return (
9 |
10 |
Count: {count}
11 |
setCount((c) => c + 1)}>Increment
12 |
This is a client component.
13 |
Go to Home
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/examples/31_minimal/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "31_minimal",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/33_promise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "33_promise",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/35_nesting/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "35_nesting",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/53_islands/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "53_islands",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "0.27.5"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/waku/tests/config.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType } from 'ts-expect';
2 | import { expect, test } from 'vitest';
3 | import { type Config, defineConfig } from '../src/config.js';
4 |
5 | // Absolutely meaningless unit and type test examples.
6 | // Only exist to proof that the frameworks are set up correctly.
7 | test('defineConfig', async () => {
8 | expect(defineConfig({})).toEqual({});
9 | });
10 |
11 | expectType(defineConfig({}));
12 |
13 | // @ts-expect-error This is supposed to verify ts-expect works.
14 | expectType(defineConfig({}));
15 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssg-wildcard/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ssg-wildcard",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/ssr-redirect/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ssr-redirect",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/39_api/src/components/App.tsx:
--------------------------------------------------------------------------------
1 | import { Counter } from './Counter';
2 |
3 | const App = ({ name }: { name: string }) => {
4 | return (
5 |
6 |
7 | Waku
8 |
9 |
10 |
13 |
Hello {name}!!
14 | This is a server component.
15 |
16 |
17 |
18 |
19 | );
20 | };
21 |
22 | export default App;
23 |
--------------------------------------------------------------------------------
/packages/waku/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | export const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
2 | export const SRC_CLIENT_ENTRY = 'waku.client';
3 | export const SRC_SERVER_ENTRY = 'waku.server';
4 | export const SRC_PAGES = 'pages'; // only for managed mode
5 | export const SRC_MIDDLEWARE = 'middleware'; // only for managed mode
6 |
7 | // Some file and dir names for dist
8 | // We may change this in the future
9 | export const DIST_PUBLIC = 'public';
10 | export const DIST_SERVER = 'server';
11 | export const BUILD_METADATA_FILE = '__waku_build_metadata.js';
12 |
--------------------------------------------------------------------------------
/.github/workflows/pkg-pr-new.yml:
--------------------------------------------------------------------------------
1 | name: pkg-pr-new
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | types: [opened, synchronize]
8 | merge_group:
9 |
10 | jobs:
11 | publish:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v6
15 | - uses: pnpm/action-setup@v4
16 | - uses: actions/setup-node@v6
17 | with:
18 | node-version: 'lts/*'
19 | cache: 'pnpm'
20 | - run: pnpm install
21 | - run: pnpm run compile
22 | - run: pnpm dlx pkg-pr-new publish packages/waku
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/define-router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "define-router",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "scripts": {
7 | "dev": "waku dev",
8 | "build": "waku build",
9 | "start": "waku start"
10 | },
11 | "dependencies": {
12 | "react": "~19.2.3",
13 | "react-dom": "~19.2.3",
14 | "react-server-dom-webpack": "~19.2.3",
15 | "waku": "latest"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^19.2.7",
19 | "@types/react-dom": "^19.2.3",
20 | "typescript": "^5.9.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------