Waku Documentation

repository·main·Indexed 27 days ago

https://github.com/wakujs/waku

A minimal React framework designed for high performance and developer experience. Waku supports React 19 features including Server Components, Actions, and a file-based router. It provides tools for static prerendering (SSG), server-side rendering (SSR), lazy slices, and type-safe routing via PageProps.

Tokens
59.2K
Snippets
182
Records
269
Agent score
89%

What's inside Waku

  1. Overview of the Waku Minimal API

    main

    The Minimal API is the lowest-level public surface in Waku, designed for library authors, custom runtimes, and advanced users requiring direct control over routing, request dispatch, and build output.

    Note: If you are building a standard application, use waku/router instead. The Minimal API does not provide filesystem routing, automatic route-to-component mapping, or page conventions like layout.tsx or page.tsx.

  2. Overview of Waku features

    main

    Waku is a minimal React framework built around React Server Components and server actions. Key features include:

    • File-based routing: Files in src/pages define routes, including layouts, dynamic segments, catch-all routes, and API routes.
    • Hybrid Rendering: Pages, layouts, and slices can independently declare static (prerendered at build time) or dynamic (executed on every request) rendering modes.
    • Server and Client Components: Use await directly in server components for data fetching, and add the 'use client' directive for interactive components.
    • Standard React: Uses standard React patterns and component formats without introducing new programming models.
    • Deployment Adapters: Supports deployment to Node.js, Vercel, Netlify, Cloudflare, AWS Lambda, Deno, or Bun.
  3. Compare Waku with other frameworks

    main

    Waku's architectural position is defined by its focus on a small framework-owned surface with direct execution semantics and a React-native mental model. Use the following comparison to determine if Waku fits your project requirements:

    FeatureWakuNext.jsAstroReact RouterTanStack Start
    React Server Components🧪🧪
    Static pages with dynamic regions
    Framework-managed caching
    UI libraries beyond React
    Deployment adapters🧪

    Legend: ✅ supported, 🧪 experimental, ➖ not part of the design.

    Key Architectural Distinctions

    • Waku vs. Next.js: Next.js provides an integrated platform with a heavy caching/revalidation model. Waku provides a minimal surface with no implicit cache, giving you more control over application decisions.
    • Waku vs. Astro: Astro is content-first and supports multiple UI libraries via islands. Waku is React-native throughout (Server Components, Client Components, Slices), allowing a site to grow from static to complex server-driven behavior without changing the UI model.
    • Waku vs. React Router: React Router is routing-centric with data flowing through loaders/actions. Waku is component-centric, using the React Server Component model as the primary architecture with routing in a supporting role.
    • Waku vs. TanStack Start: TanStack Start is centered around an elaborate type-safe router and server-function model. Waku is centered around React itself, using server components as the core architecture.
  4. Understand the Waku project structure

    main

    A standard Waku starter project follows this directory structure:

    • public/: Static assets (images, fonts, etc.) served directly to the root.
    • src/components/: Reusable React components.
    • src/middleware/: Optional Hono middleware. The default setup automatically picks up middleware defined here.
    • src/pages/: The file-based router. Each file represents a route.
      • _layout.tsx: A special file that wraps all other pages in the directory.
    • src/pages.gen.ts: Automatically generated file containing route types for type-safe linking. Do not edit this file manually.
    • waku.config.ts: Configuration file for Waku and Vite (e.g., enabling Tailwind CSS or React Compiler).
    • src/styles.css: Global styles.
  5. Understand Waku's Static and Dynamic Rendering modes

    main

    Waku uses two rendering modes for pages and layouts, which are declared via the getConfig export.

    • 'static' (default): The page is prerendered once at build time. The HTML and component output are served as-is until the next build. This is ideal for content that is the same for every visitor (e.g., marketing pages, blogs).
    • 'dynamic': The page is executed on every request. This allows the page to access request-specific information like cookies, headers, and current data.

    Note that Waku does not implicitly cache dynamic rendering. If you need caching for expensive operations, you must implement it explicitly.

  6. Quickstart: New Waku project with Cloudflare support

    main

    Use the Cloudflare template to scaffold a new project with @hiogawa/node-loader-cloudflare pre-configured.

    1. Scaffold: npm create waku@latest -- --template 07_cloudflare
    2. Develop: npm run dev (includes Cloudflare bindings)
    3. Build: npm run build (for Cloudflare Workers)
    4. Test locally: npx wrangler dev
    5. Deploy: npx wrangler deploy
    npm create waku@latest -- --template 07_cloudflare
  7. Avoid duplicate React installs in a monorepo

    main

    To prevent errors like TypeError: Cannot read properties of null (reading 'use') or React hook errors caused by multiple React instances, manage your dependencies carefully in a monorepo:

    1. Shared Workspace Packages: Declare react and react-dom as peerDependencies to avoid bundling their own runtime copies. Use devDependencies for local development.
    2. Waku App: The main Waku application should hold the actual runtime dependencies for react, react-dom, react-server-dom-webpack, and waku.
    // In a shared workspace package
    {
      "peerDependencies": {
        "react": "latest",
        "react-dom": "latest"
      },
      "devDependencies": {
        "react": "latest",
        "react-dom": "latest"
      }
    }
    
    // In the Waku app
    {
      "dependencies": {
        "react": "latest",
        "react-dom": "latest",
        "react-server-dom-webpack": "latest",
        "waku": "latest"
      }
    }
  8. Author a custom Waku adapter

    main

    Write a custom adapter when you need to integrate Waku with a runtime or deployment target not covered by built-in adapters (e.g., waku/adapters/node, waku/adapters/cloudflare).

    An adapter's responsibilities include:

    • Translating platform requests into Waku request processing.
    • Serving static assets.
    • Wiring middleware.
    • Exposing platform-specific default exports.
    • Injecting platform environment bindings.
    • Adding deployment-specific files after waku build.

    Note: The APIs used in this guide use unstable_ names and are subject to change.

  9. Disable SSR for a Programmatic Route

    main

    When using createPages to define your routes, you can disable document SSR for a specific page by setting the unstable_disableSSR option to true.

    When SSR is disabled, the server returns Waku's fallback HTML shell instead of a fully rendered document. The client router then fetches the RSC payload to render the route in the browser. This is useful for authenticated app areas or browser-only experiences where initial HTML content is not required or desired.

    Note: unstable_disableSSR is currently experimental and its API may change.

    // src/waku.server.tsx
    import { createPages } from 'waku';
    import adapter from 'waku/adapters/default';
    import { AppPage } from './templates/app-page';
    
    const pages = createPages(async ({ createPage }) => [
      createPage({
        render: 'static',
        path: '/app',
        component: AppPage,
        unstable_disableSSR: true,
      }),
    ]);
    
    export default adapter(pages);
  10. Deploy to Vercel

    main

    Waku projects can be deployed to Vercel using the Vercel CLI.

    Command:

    vercel

    Pure SSG on Vercel

    To deploy as Pure SSG (avoiding Vercel Functions), use the Vercel adapter in ./src/waku.server.tsx and set the static option to true.

    import { fsRouter } from 'waku';
    import adapter from 'waku/adapters/vercel';
    
    export default adapter(fsRouter(import.meta.glob('./pages/**/*.{tsx,ts}')), {
      static: true,
    });