Introduction
Waku (wah-ku) or わく means “framework” in Japanese. As the minimal React framework, it aims to accelerate the work of developers at startups and agencies building small to medium-sized React projects. These include marketing websites, light ecommerce, and web applications.
We recommend other frameworks for heavy ecommerce or enterprise applications. Waku is a lightweight alternative designed to bring a fun developer experience to the modern React server components era. Yes, let’s make React development fun!
NoteWaku is in rapid development and some features are currently missing. Please try it on non-production projects and report any issues you may encounter. Expect that there will be some breaking changes on the road towards a stable v1 release. Contributors are welcome.
Getting started
Start a new Waku project with the create command for your preferred package manager. It will scaffold a new project with our default Waku starter.
Rendering
Let's face it: React is getting complicated. But not without good reason!
While there's a bit of a learning curve to modern React rendering, it introduces powerful new patterns of composability that are only made possible with the advent of React server components. So stick with us.
Future versions of Waku may provide additional APIs to abstract away some of the complexity for an improved developer experience.
Server components
Waku follows React conventions including server components and server actions. Server components can be made async and can securely perform server-side logic and data fetching. They have no interactivity since they run exclusively on the server.
Client components
A 'use client' directive placed at the top of a file will create a server-client boundary when the module is imported into a server component. All components imported below the boundary will be hydrated and run in the browser. They can use all traditional React features such as state, effects, and event handlers.
Shared components
Simple React components that meet all of the rules of both server and client components can be imported to either server or client components without affecting the server-client boundary.
Weaving patterns
Server components can import client components and doing so will create a server-client boundary. Client components cannot import server components, but they can accept server components as props such as children.
Server-side rendering
Waku provides static prerendering (SSG) or server-side rendering (SSR) options for layouts and pages including both their server and client components.
Further reading
To learn more about the modern React architecture, we recommend Making Sense of React Server Components and The Two Reacts: Part 1.
Routing (low-level API)
The entry point for routing in Waku projects is ./src/entries.tsx. Export the createPages function to create your layouts and pages programatically.
Both createLayout and createPage accept a configuration object to specify the route path, React component, and render method. Waku currently supports two options: 'static' for static prerendering (SSG) or 'dynamic' for server-side rendering (SSR).
For example you can statically prerender a global header and footer in the root layout at build time, but dynamically render the rest of a home page at request time for personalized user experiences.
Pages
Single routes
Pages can be rendered as a single route (e.g., /about).
Segment routes
Pages can also render a segment route (e.g., /blog/[slug]). The rendered React component automatically receives a prop named by the segment (e.g, slug) with the value of the rendered route (e.g., 'introducing-waku'). If statically prerendering a segment route at build time, a staticPaths array must also be provided.
Static paths (or other values) could also be generated programatically.
Nested segment routes
Routes can contain multiple segments (e.g., /shop/[category]/[product]).
For static prerendering of nested segment routes, the staticPaths array is instead comprised of ordered arrays.
Catch-all routes
Catch-all or "wildcard" routes (e.g., /app/[...catchAll]) have indefinite segments. Wildcard routes receive a prop with segment values as an ordered array. For example, the /app/profile/settings route would receive a catchAll prop with the value ['profile', 'settings']. These values can then be used to determine what to render in the component.
Layouts
Layouts wrap an entire route and its descendents. They must accept a children prop of type ReactNode. While not required, you will typically want at least a root layout.
Root layout
The root layout rendered at path: '/' is especially useful. It can be used for setting global styles, global metadata, global providers, global data, and global components, such as a header and footer.
Other layouts
Layouts are also helpful further down the tree. For example you could add a layout at path: '/blog to add a sidebar to both the blog index and all blog article pages.
Navigation
Internal links should be made with the Waku <Link /> component. It accepts a to prop for the destination, which is automatically prefetched ahead of the navigation.
Static assets
Static assets such as images, fonts, stylesheets, and scripts can be placed in a special ./public folder of the Waku project root directory. The public directory structure is served relative to the / base path.
For example an image added to ./public/images/logo.svg can be rendered via <img src="/images/logo.svg" />.
Data fetching
Server
All of the wonderful patterns of React server components are supported. For example you can compile MDX files or perform code syntax highlighting on the server with zero impact on the client bundle size.
Client
Data should be fetched on the server when possible for the best user experience, but all data fetching libraries such as React Query should be compatible with Waku.
State management
We recommend Jotai for global React state management based on the atomic model's performance and scalability, but Waku should be compatible with all React state management libraries such as Zustand and Valtio.
We're exploring a deeper integration of atomic state management into Waku to achieve the performance and developer experience of signals while preserving React's declarative programming model.
Metadata
Waku automatically hoists any title, meta, and link tags to the document head. So adding meta tags is as simple as adding it to any of your layout or page components.
Styling
Global styles
Install any required dev dependencies (e.g., npm i -D tailwindcss autoprefixer) and set up any required configuration (e.g., postcss.config.js). Then create your global stylesheet (e.g., ./src/styles.css) and import it into the root layout.
Environment variables
It's important to distinguish environment variables that must be kept secret from those that can be made public.
Private
By default all environment variables are considered private and accessible only in server components, which can be rendered exclusively in a secure environment. You must still take care not to inadvertently pass the variable as props to any client components.
Public
A special WAKU_PUBLIC_ prefix is required to make an environment variable public and accessible in client components. They will be present as cleartext in the production JavaScript bundle sent to users browsers.
Runtime agnostic (recommended)
Environment variables are available on the server via the Waku getEnv function and on the client via import.meta.env.
Node.js
In Node.js environments, process.env may be used for compatibility.
Deployment
Vercel
Waku projects can be deployed to Vercel with the Vercel CLI automatically.
Pure SSG
Adding the --with-vercel-static flag to the build script will produce static sites without serverless functions.
Cloudflare (experimental)
Deno Deploy (experimental)
Community
Please join our friendly GitHub discussions or Discord server to participate in the Waku community. Hope to see you there!
Roadmap
Waku is in active development and we're seeking additional contributors. Check out our roadmap for more information.