Router

Practices

Waku provides a router built on top of the minimal API, and it serves as a reference implementation. While other router implementations can be used with Waku, this page focuses on the waku/router implementation.

Client API

To use the router, it is required to use the Router component instead of using serve directly. The following code demonstrates how to use the Router component as the root component:

import { createRoot } from "react-dom/client";
import { Router } from "waku/router/client";

const root = createRoot(document.getElementById("root")!);

root.render(<Router />);

The Router component internally uses serve and handles nested routes.

Server API

In entries.ts, we use defineRouter to export getEntry and getBuildConfig at once. Here's a simple example code without builder:

import { defineRouter } from "waku/router/server";

export default defineRouter(
(id) => {
switch (id) {
case 'index':
return import('./routes/index.tsx');
case 'foo':
return import('./routes/foo.tsx');
default:
throw new Error("no such route");
}
}
);

The implementation of the defineRouter is config-based. However, it isn't too difficult to make a file-based router. Here's a file-based example code with builder:

import path from "node:path";
import fs from "node:fs";

import { glob } from "glob";
import { defineRouter } from "waku/router/server";
import { unstable_rootDir as rootDir } from "waku/config";

export default defineRouter(
(id) => {
const items = id.split("/");
switch (items.length) {
case 1:
return import(`./routes/${items[0]}.tsx`);
case 2:
return import(`./routes/${items[0]}/${items[1]}.tsx`);
default:
throw new Error("too deep route");
}
},
async () => {
const root = rootDir();
const routesDir = path.join(root, "routes");
const files = await glob("**/*.tsx", { cwd: routesDir });
return files.map((file) => {
const name = file.slice(0, file.length - path.extname(file).length);
const stat = fs.statSync(path.join(routesDir, name), {
throwIfNoEntry: false,
});
return stat?.isDirectory() ? name + "/" : name;
});
}
);

Due to the limitation of bundler, we cannot automatically allow infinite depth of routes.

How to try it

You can try an example app in the repository by cloning it and running the following commands:

git clone https://github.com/dai-shi/waku.git
cd waku
npm install
npm run examples:dev:07_router

Alternatively, you could create a project with something like npm create waku@latest and copy files from the example folder in the repository.