Skip to content

Commit 8c3b2b6

Browse files
rsbhclaude
andauthored
feat: migrate from Next.js to Vite + Nitro (#24)
* feat: remove Next.js deps, add Vite + Nitro stack, delete app router - Remove next, remark-attr, zod, react-device-detect from deps - Add vite, nitro, react-router-dom, gray-matter, minisearch, satori - Add fumadocs remark/rehype plugins (remark-gfm, remark-frontmatter, etc.) - Delete src/app/ (Next.js App Router), source.config.ts, next.config.mjs - Replace react-device-detect with navigator.platform check Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Vite + Nitro server structure, pages, and source rewrite - src/server/: Nitro route handlers (api/, routes/), SSR catch-all, vite-config.ts with Nitro + fumadocs-mdx/vite (index: false) - src/server/api/: health, search, specs, apis-proxy - src/server/routes/: og, robots.txt, sitemap.xml, llms.txt, [...] SSR - src/pages/: DocsLayout, DocsPage, ApiLayout, ApiPage, NotFound - src/lib/source.ts: rewrite with fs/promises + gray-matter + fumadocs-core loader() - src/lib/head.tsx, page-context.tsx: SSR meta and React context - src/types/globals.d.ts: Vite build-time constant types - Add nitro, h3, remark-parse to deps - Add .gitignore and lint script to chronicle package Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: rewrite CLI commands for Vite/Nitro, remove Next.js scaffolding - CLI dev/build/start/serve: use Vite programmatic API (no child process) - CLI init: remove .chronicle/ scaffolding, .next from gitignore - Remove process.ts (attachLifecycleHandlers), resolveNextCli - Strip scaffold.ts to detectPackageManager() + getChronicleVersion() - lib/config.ts: replace env vars with __CHRONICLE_* build-time constants - cli/utils/config.ts: remove env var fallback from resolveContentDir - tsconfig.json: remove .source paths and source.config.ts include Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: replace Next.js imports with React Router - next/link → react-router-dom Link - next/navigation usePathname → useLocation - next/navigation useRouter → useNavigate - next/image → native img tag - next/font/google → removed (font.ts deleted) - Remove 'use client' directives (not needed with Vite) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: symlink content into package root, fix SSR + client hydration - Symlink user's content dir to PACKAGE_ROOT/.content/ before starting - Vite root stays as package root, content accessible via symlink - SSR: use renderToPipeableStream for Suspense support - Client: import MDX via /.content/ symlink path for hydration - loadPageComponent uses symlink path for Vite module resolution - openapi.ts: async with fs/promises, resolve specs from project root - scaffold.ts: fully async (detectPackageManager, getChronicleVersion, linkContent) - build-cli.ts: externalize all dependencies - Add __CHRONICLE_PACKAGE_ROOT__ build-time constant - Graceful fallback when API spec files are missing - Add data-article-content attribute to default theme Page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: simplify init command to content + config only Remove package.json creation, dependency installation, and detectPackageManager/getChronicleVersion usage from init. Init now only creates content dir, chronicle.yaml, sample MDX, and .gitignore. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove unused detectPackageManager and getChronicleVersion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: server-side page API, remove source.ts from client bundle - Add /api/page/:slug endpoint — returns frontmatter + rendered contentHtml - page-context.tsx: fetch from /api/page on client navigation instead of importing source.ts (removes fs/gray-matter from client bundle) - entry-client.tsx: use SSR content HTML for initial hydration - Extract renderToHtml utility (shared by catch-all route and page API) - Fixes buffer/node:fs/promises client warnings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: MDX import on client, /api/page endpoint, fix duplicate React - Client imports MDX via /.content/ symlink (matches SSR React tree) - /api/page/:slug returns frontmatter + relativePath for client navigation - page-context.tsx: fetch /api/page then import MDX (no source.ts on client) - entry-client.tsx: import MDX for initial hydration - Remove render-to-html utility (page API returns path, not HTML) - Embed relativePath instead of filePath in __PAGE_DATA__ - Add .content to .gitignore - Remove cacheDir and React alias hacks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: inject CSS and JS assets into SSR HTML head Use Nitro ?assets=client/ssr virtual imports to collect CSS/JS assets and inject as <link> tags in HTML <head>. Fixes unstyled flash on initial page load. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add .output to gitignore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: fix production build and entry-server SSR pattern - build.ts: use createBuilder() + buildApp() for multi-environment build (client, SSR, Nitro all build correctly) - entry-server.tsx: rewrite as Nitro server entry with export default { fetch } using renderToReadableStream, asset injection via ?assets imports - source.ts: use @content/ alias in import() so Vite bundles MDX at build time (removes @vite-ignore, fixes ERR_UNKNOWN_FILE_EXTENSION in production) - source.ts: check file exists before import to prevent crashes - Remove index.html template (entry-server renders full HTML) - Remove catch-all route (entry-server handles SSR) - Remove serverDir from Nitro config (entry-server pattern) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ci: add canary release workflow for PR builds Publishes canary npm release on every PR commit with version format 0.1.0-canary.<short-sha> using --tag canary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve @content alias in Nitro dev SSR worker - Add @content alias to Nitro config (mirrors Vite resolve.alias) - Use @content/ alias in loadPageComponent import (works in both dev via Nitro alias and build via Vite alias) - Remove @vite-ignore from dynamic imports - Add fs.access check before import to prevent crashes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use resolveId plugin for @content alias across all Vite environments resolve.alias doesn't propagate to Nitro's SSR worker fetchModule. A custom Vite plugin with resolveId hook runs in all environments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add preserveSymlinks to prevent symlink resolution outside Vite root Node resolves symlinks to real paths, which may be outside the Vite root. preserveSymlinks keeps the .content/ symlink path as-is. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use relative ../../.content/ path for MDX imports Remove @content alias, resolveId plugin, and preserveSymlinks. Use relative path from source file to .content/ symlink instead. Vite statically analyzes the ../../.content/ prefix to glob and bundle all MDX files at build time. Works in both dev and production. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add remark plugins for callouts and mermaid diagrams Configure fumadocs-mdx/vite with remark-directive, remarkDirectiveAdmonition, remarkMdxMermaid, and remarkUnusedDirectives. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add ReactRouterProvider from fumadocs-core, fix remark plugin config - Wrap app with ReactRouterProvider in both SSR and client entry - Fix fumadocs-mdx/vite config: pass mdxOptions via defineConfig as default export - Enables fumadocs-core Link, usePathname, useRouter, search integration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: replace custom PageTree/TocItem types with fumadocs-core re-exports - Re-export Root, Node, Item, Folder, Separator from fumadocs-core/page-tree - Re-export TOCItemType, TableOfContents from fumadocs-core/toc - Update ThemeLayoutProps/ThemePageProps to use Root instead of PageTree - Keep custom Frontmatter and Page types (Page.toc now uses TableOfContents) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: use fumadocs loader API directly in source.ts and api-routes.ts - Remove SourcePage interface and buildPageTree(), use loader().pageTree with order-based sort - getPages()/getPage() now return fumadocs Page types directly - loadPageComponent() takes relativePath string instead of SourcePage - Rename _absolutePath to _relativePath in scanFiles (stored relative path was misnamed) - buildApiPageTree() returns fumadocs Root instead of custom PageTree - Update entry-server, entry-client, page-context, sitemap, api route consumers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: update components to use fumadocs-core types and utilities - breadcrumbs.tsx: use getBreadcrumbItems() from fumadocs-core/breadcrumb - Toc.tsx: use AnchorProvider + useActiveAnchor from fumadocs-core/toc - ReadingProgress.tsx: TocItem → TOCItemType - Layout.tsx: PageTreeItem → Node with type narrowing for Item/Folder - ChapterNav.tsx: PageTree/PageTreeItem → Root/Node from fumadocs-core/page-tree - paper/Page.tsx: use flattenTree + getBreadcrumbItems from fumadocs-core Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: add max-width to content images in default and paper themes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: render mermaid code blocks as diagrams MdxPre detects language-mermaid code blocks and renders them with the Mermaid component instead of plain code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: sidebar sorting — root pages before folders, ghost button for details/summary - Remove fallback to first child order for folders without index page - Folders without explicit order sort after root pages - Restyle <details><summary> as inline ghost button with border and hover Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: style raw HTML details/summary via content CSS selectors Raw HTML <details> in MDX bypasses component mapping, so style them directly in .content selector using Apsara design tokens. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use import.meta.glob for nested MDX dynamic imports Vite variable dynamic imports only work one level deep. Nested content paths like authn/session.mdx failed on client navigation. Use import.meta.glob to pre-map all .content files for reliable deep imports. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove unused __CHRONICLE_PACKAGE_ROOT__ constant Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: pass TOC data from compiled MDX modules to page components - loadPageModule returns both default component and toc array - PageData includes toc field (TableOfContents) - entry-client and page-context extract toc from import.meta.glob modules - DocsPage uses page.toc instead of hardcoded empty array Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: extract shared mdx-loader and frontmatter helpers - Create lib/mdx-loader.ts — single import.meta.glob + loadMdxModule() - Remove duplicate glob/loader from page-context.tsx and entry-client.tsx - Add extractFrontmatter() and getRelativePath() to source.ts - Remove duplicate frontmatter reconstruction from entry-server and api/page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove unnecessary @ts-expect-error directives Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: output build artifacts to project cwd instead of package dir Nitro's vercel preset resolves output from rootDir which defaults to Vite's root (packageRoot). Override output.dir and publicDir via nitro config to resolve from projectRoot (cwd). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review — path traversal, JSON parse, 404 status - Wrap meta.json parse in try/catch for malformed files - Reject relativePath with .. segments and validate resolved path stays within contentDir - Return 404 status for missing doc pages in SSR Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: hydration mismatch and SSR nested path imports - Pass loadMdx as prop to PageProvider to avoid import.meta.glob in SSR bundle - Use import.meta.glob in source.ts for SSR nested MDX imports - Skip Tabs SSR to avoid Radix useId mismatch (ClientOnly wrapper) - Add path traversal guard and meta.json parse safety Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * revert: remove mdx-loader.ts, restore inline import.meta.glob Extracting import.meta.glob to a shared module caused hydration mismatch — SSR and client Vite environments compiled MDX differently. Restore inline globs in entry-client.tsx (client-only) and source.ts (SSR-only) to keep each environment's compilation isolated. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace runtime fs calls with build-time data for serverless compatibility Runtime fs.readdir/readFile calls break on Vercel serverless where content files don't exist in the function bundle. Replace with import.meta.glob (build-time) for page tree and baked-in config for chronicle.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * revert: remove canary build GitHub Action Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove conditional useMemo hook in SidebarNode useMemo was called after early returns, violating Rules of Hooks. Replaced with plain JSX since memoization is unnecessary here. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: strip .md/.mdx extensions from internal links in MDX content Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: treat README.md/README.mdx as folder index pages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: suppress nitro preview message, show chronicle start hint after build Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: force light theme for paper theme, disable dark mode Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c959147 commit 8c3b2b6

86 files changed

Lines changed: 2541 additions & 1883 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 251 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/chronicle/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
dist
3+
.source
4+
.content
5+
.output

packages/chronicle/biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"extends": ["@raystack/tools-config/biome.json"]
2+
"extends": ["@raystack/tools-config/biome"]
33
}

packages/chronicle/build-cli.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import path from 'path'
1+
import pkg from './package.json';
22

33
const result = await Bun.build({
44
entrypoints: ['src/cli/index.ts'],
55
outdir: 'dist/cli',
66
target: 'node',
77
format: 'esm',
8-
})
8+
external: Object.keys(pkg.dependencies),
9+
});
910

1011
if (!result.success) {
11-
for (const log of result.logs) console.error(log)
12-
process.exit(1)
12+
for (const log of result.logs) console.error(log);
13+
process.exit(1);
1314
}

packages/chronicle/next.config.mjs

Lines changed: 0 additions & 10 deletions
This file was deleted.

packages/chronicle/package.json

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@
99
"dist",
1010
"src",
1111
"templates",
12-
"next.config.mjs",
13-
"source.config.ts",
1412
"tsconfig.json"
1513
],
1614
"bin": {
1715
"chronicle": "./bin/chronicle.js"
1816
},
1917
"scripts": {
20-
"build:cli": "bun build-cli.ts"
18+
"build:cli": "bun build-cli.ts",
19+
"lint": "biome lint src/"
2120
},
2221
"devDependencies": {
2322
"@biomejs/biome": "^2.3.13",
@@ -37,27 +36,36 @@
3736
"@codemirror/theme-one-dark": "^6.1.3",
3837
"@codemirror/view": "^6.39.14",
3938
"@heroicons/react": "^2.2.0",
40-
"@raystack/apsara": "^0.56.0",
41-
"@types/unist": "^3.0.3",
39+
"@raystack/apsara": "0.55.1",
40+
"@shikijs/rehype": "^4.0.2",
41+
"@vitejs/plugin-react": "^6.0.1",
4242
"chalk": "^5.6.2",
4343
"class-variance-authority": "^0.7.1",
4444
"codemirror": "^6.0.2",
4545
"commander": "^14.0.2",
4646
"fumadocs-core": "16.6.15",
4747
"fumadocs-mdx": "^14.2.6",
48+
"glob": "^11.0.0",
49+
"gray-matter": "^4.0.3",
50+
"h3": "^2.0.1-rc.16",
4851
"lodash": "^4.17.23",
4952
"mermaid": "^11.13.0",
50-
"next": "16.1.6",
53+
"minisearch": "^7.2.0",
54+
"nitro": "latest",
55+
"openapi-types": "^12.1.3",
5156
"react": "^19.0.0",
52-
"react-device-detect": "^2.2.3",
5357
"react-dom": "^19.0.0",
54-
"remark-attr": "^0.11.1",
58+
"react-router": "^7.13.1",
5559
"remark-directive": "^4.0.0",
60+
"remark-parse": "^11.0.0",
61+
"remark-frontmatter": "^5.0.0",
62+
"remark-gfm": "^4.0.1",
63+
"remark-mdx-frontmatter": "^5.2.0",
64+
"satori": "^0.25.0",
5665
"slugify": "^1.6.6",
5766
"unified": "^11.0.5",
5867
"unist-util-visit": "^5.1.0",
59-
"openapi-types": "^12.1.3",
60-
"yaml": "^2.8.2",
61-
"zod": "^4.3.6"
68+
"vite": "^8.0.0",
69+
"yaml": "^2.8.2"
6270
}
6371
}

packages/chronicle/source.config.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

packages/chronicle/src/app/[[...slug]]/layout.tsx

Lines changed: 0 additions & 15 deletions
This file was deleted.

packages/chronicle/src/app/[[...slug]]/page.tsx

Lines changed: 0 additions & 106 deletions
This file was deleted.

packages/chronicle/src/app/api/apis-proxy/route.ts

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)