diff --git a/.claude/skills/funstack-router-knowledge/SKILL.md b/.claude/skills/funstack-router-knowledge/SKILL.md new file mode 100644 index 0000000..a3f70d4 --- /dev/null +++ b/.claude/skills/funstack-router-knowledge/SKILL.md @@ -0,0 +1,23 @@ +--- +name: funstack-router-knowledge +description: Use this skill when you need information about `@funstack/router` (the React router your app uses). What it is, API references, best practices, etc. +metadata: + internal: true +--- + +# FUNSTACK Router Knowledge + +**FUNSTACK Router** (`@funstack/router`) is a modern React router built on the [Navigation API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API) (not the History API). It uses the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) for path matching. + +## Entrypoints + +- `@funstack/router` — Main entrypoint. Provides `Router`, `Outlet`, hooks (`useNavigate`, `useRouteParams`, etc.), and route definition utilities (`route()`, `routeState()`). +- `@funstack/router/server` — Entrypoint for Server context when you are using React Server Components. Provides `route()` and `routeState()` utilities for defining routes in server modules. + +## FUNSTACK Router Docs + +More detailed documentation (including API references and best practices) can be found at: + +``` +node_modules/@funstack/router/dist/docs/index.md +``` diff --git a/packages/docs/package.json b/packages/docs/package.json index 9930fe5..6c7724a 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -11,14 +11,15 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@funstack/router": "0.0.7", + "@funstack/router": "^0.0.9", "@funstack/static": "workspace:*", "@shikijs/rehype": "^3.22.0", "@types/node": "catalog:", "react": "catalog:", "react-dom": "catalog:", "rehype-slug": "^6.0.0", - "shiki": "^3.22.0" + "shiki": "^3.22.0", + "urlpattern-polyfill": "^10.1.0" }, "devDependencies": { "@mdx-js/rollup": "^3.1.1", diff --git a/packages/docs/src/App.tsx b/packages/docs/src/App.tsx index 189cb82..9209a96 100644 --- a/packages/docs/src/App.tsx +++ b/packages/docs/src/App.tsx @@ -19,7 +19,7 @@ import { Home } from "./pages/Home"; import { NotFound } from "./pages/NotFound"; import { Router } from "./Router"; -const routes: RouteDefinition[] = [ +export const routes: RouteDefinition[] = [ route({ path: import.meta.env.BASE_URL.replace(/\/$/, ""), component: , @@ -132,6 +132,6 @@ const routes: RouteDefinition[] = [ }), ]; -export default function App() { - return ; +export default function App({ ssrPath }: { ssrPath: string }) { + return ; } diff --git a/packages/docs/src/entries.tsx b/packages/docs/src/entries.tsx new file mode 100644 index 0000000..33a79fb --- /dev/null +++ b/packages/docs/src/entries.tsx @@ -0,0 +1,29 @@ +import "urlpattern-polyfill"; +import type { EntryDefinition } from "@funstack/static/entries"; +import type { RouteDefinition } from "@funstack/router/server"; +import App, { routes } from "./App"; + +function collectPaths(routes: RouteDefinition[]): string[] { + const paths: string[] = []; + for (const route of routes) { + if (route.children) { + paths.push(...collectPaths(route.children)); + } else if (route.path !== undefined && route.path !== "*") { + paths.push(route.path); + } + } + return paths; +} + +function pathToEntryPath(path: string): string { + if (path === "/") return "index.html"; + return `${path.slice(1)}/index.html`; +} + +export default function getEntries(): EntryDefinition[] { + return collectPaths(routes).map((pathname) => ({ + path: pathToEntryPath(pathname), + root: () => import("./root"), + app: , + })); +} diff --git a/packages/docs/vite.config.ts b/packages/docs/vite.config.ts index cf6958e..0cc5aed 100644 --- a/packages/docs/vite.config.ts +++ b/packages/docs/vite.config.ts @@ -12,8 +12,8 @@ export default defineConfig(async () => { const config: UserConfig = { plugins: [ funstackStatic({ - root: "./src/root.tsx", - app: "./src/App.tsx", + entries: "./src/entries.tsx", + ssr: true, }), { // to make .mdx loading lazy diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0440e78..d04a42d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,8 +39,8 @@ importers: packages/docs: dependencies: '@funstack/router': - specifier: 0.0.7 - version: 0.0.7(react@19.2.4) + specifier: ^0.0.9 + version: 0.0.9(react@19.2.4) '@funstack/static': specifier: workspace:* version: link:../static @@ -62,6 +62,9 @@ importers: shiki: specifier: ^3.22.0 version: 3.22.0 + urlpattern-polyfill: + specifier: ^10.1.0 + version: 10.1.0 devDependencies: '@mdx-js/rollup': specifier: ^3.1.1 @@ -617,8 +620,8 @@ packages: '@noble/hashes': optional: true - '@funstack/router@0.0.7': - resolution: {integrity: sha512-iqdNkCUu7PovXMJjPydFCoZSxz9d37dR/zCLnbfp8TZ9MweXNk+105v1gHHzdpOWEr7PFZWb1vrgsO92hXf8vg==} + '@funstack/router@0.0.9': + resolution: {integrity: sha512-d+tUZEoBQA0/m06ANLQ3/iATLu4F3ZGY7aDeVGZEwAK07SR9AF1nmG8hBCDDJY4tlwk++xWsViXSZ/gEtnbB5Q==} hasBin: true peerDependencies: react: ^18.0.0 || ^19.0.0 @@ -2399,6 +2402,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + urlpattern-polyfill@10.1.0: + resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -2880,7 +2886,7 @@ snapshots: '@exodus/bytes@1.14.1': {} - '@funstack/router@0.0.7(react@19.2.4)': + '@funstack/router@0.0.9(react@19.2.4)': dependencies: '@funstack/skill-installer': 1.0.0 react: 19.2.4 @@ -4954,6 +4960,8 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + urlpattern-polyfill@10.1.0: {} + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3