page.mdx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import { pageMetadata } from "@/lib/page-metadata"
  2. export const metadata = pageMetadata("docs/api/next")
  3. # @json-render/next
  4. Next.js renderer. JSON becomes full Next.js applications with routes, layouts, metadata, and SSR.
  5. ## Installation
  6. ```bash
  7. npm install @json-render/core @json-render/react @json-render/next
  8. ```
  9. ## schema
  10. The Next.js app schema for multi-page specs. Use with `defineCatalog` from core.
  11. ```typescript
  12. import { defineCatalog } from '@json-render/core';
  13. import { schema } from '@json-render/next/server';
  14. import { z } from 'zod';
  15. const catalog = defineCatalog(schema, {
  16. components: {
  17. Card: {
  18. props: z.object({ title: z.string() }),
  19. description: 'Card container',
  20. },
  21. NavBar: {
  22. props: z.object({ links: z.array(z.object({ href: z.string(), label: z.string() })) }),
  23. description: 'Navigation bar',
  24. },
  25. },
  26. actions: {},
  27. });
  28. ```
  29. ## createNextApp
  30. Create all exports needed for a Next.js `[[...slug]]` catch-all route.
  31. ```typescript
  32. import { createNextApp } from '@json-render/next/server';
  33. const { Page, generateMetadata, generateStaticParams } = createNextApp({
  34. spec: myAppSpec,
  35. loaders: {
  36. loadPost: async ({ slug }) => {
  37. const post = await db.post.findUnique({ where: { slug } });
  38. return { post };
  39. },
  40. },
  41. });
  42. ```
  43. ### Options
  44. <table>
  45. <thead>
  46. <tr>
  47. <th>Option</th>
  48. <th>Type</th>
  49. <th>Description</th>
  50. </tr>
  51. </thead>
  52. <tbody>
  53. <tr>
  54. <td><code>spec</code></td>
  55. <td><code>{'NextAppSpec | (() => NextAppSpec | Promise<NextAppSpec>)'}</code></td>
  56. <td>The application spec (static or dynamic)</td>
  57. </tr>
  58. <tr>
  59. <td><code>loaders</code></td>
  60. <td><code>{'Record<string, LoaderFn>'}</code></td>
  61. <td>Server-side data loaders keyed by name</td>
  62. </tr>
  63. </tbody>
  64. </table>
  65. ### Returns
  66. <table>
  67. <thead>
  68. <tr>
  69. <th>Export</th>
  70. <th>Description</th>
  71. </tr>
  72. </thead>
  73. <tbody>
  74. <tr>
  75. <td><code>Page</code></td>
  76. <td>Async Server Component for <code>page.tsx</code></td>
  77. </tr>
  78. <tr>
  79. <td><code>generateMetadata</code></td>
  80. <td>Metadata generator for Next.js SEO</td>
  81. </tr>
  82. <tr>
  83. <td><code>generateStaticParams</code></td>
  84. <td>Static params for pre-rendering at build time</td>
  85. </tr>
  86. </tbody>
  87. </table>
  88. ## NextAppSpec
  89. The top-level spec defining an entire Next.js application.
  90. ```typescript
  91. interface NextAppSpec {
  92. metadata?: NextMetadata;
  93. routes: Record<string, NextRouteSpec>;
  94. layouts?: Record<string, Spec>;
  95. state?: Record<string, unknown>;
  96. }
  97. ```
  98. ### Route Patterns
  99. Routes use Next.js URL conventions:
  100. <table>
  101. <thead>
  102. <tr>
  103. <th>Pattern</th>
  104. <th>Example Match</th>
  105. <th>Params</th>
  106. </tr>
  107. </thead>
  108. <tbody>
  109. <tr>
  110. <td><code>/</code></td>
  111. <td><code>/</code></td>
  112. <td><code>{'{}'}</code></td>
  113. </tr>
  114. <tr>
  115. <td><code>/about</code></td>
  116. <td><code>/about</code></td>
  117. <td><code>{'{}'}</code></td>
  118. </tr>
  119. <tr>
  120. <td><code>/blog/[slug]</code></td>
  121. <td><code>/blog/hello</code></td>
  122. <td><code>{'{ slug: "hello" }'}</code></td>
  123. </tr>
  124. <tr>
  125. <td><code>/docs/[...path]</code></td>
  126. <td><code>/docs/a/b/c</code></td>
  127. <td><code>{'{ path: ["a","b","c"] }'}</code></td>
  128. </tr>
  129. <tr>
  130. <td><code>/app/[[...path]]</code></td>
  131. <td><code>/app</code> or <code>/app/x/y</code></td>
  132. <td><code>{'{ path: [] }'}</code> or <code>{'{ path: ["x","y"] }'}</code></td>
  133. </tr>
  134. </tbody>
  135. </table>
  136. ## NextAppProvider
  137. Client component that provides the component registry and action handlers to all pages.
  138. ```tsx
  139. import { NextAppProvider } from '@json-render/next';
  140. export default function Layout({ children }) {
  141. return (
  142. <NextAppProvider registry={registry} handlers={handlers}>
  143. {children}
  144. </NextAppProvider>
  145. );
  146. }
  147. ```
  148. ## Built-in Components
  149. ### Slot
  150. Placeholder in layouts where page content is rendered. Every layout MUST include a Slot.
  151. ```json
  152. { "type": "Slot", "props": {}, "children": [] }
  153. ```
  154. ### Link
  155. Client-side navigation wrapping `next/link`.
  156. ```json
  157. { "type": "Link", "props": { "href": "/about" }, "children": ["link-text"] }
  158. ```
  159. ## Built-in Actions
  160. <table>
  161. <thead>
  162. <tr>
  163. <th>Action</th>
  164. <th>Params</th>
  165. <th>Description</th>
  166. </tr>
  167. </thead>
  168. <tbody>
  169. <tr>
  170. <td><code>setState</code></td>
  171. <td><code>{'{ statePath, value }'}</code></td>
  172. <td>Update a value in state</td>
  173. </tr>
  174. <tr>
  175. <td><code>pushState</code></td>
  176. <td><code>{'{ statePath, value, clearStatePath? }'}</code></td>
  177. <td>Append to array in state</td>
  178. </tr>
  179. <tr>
  180. <td><code>removeState</code></td>
  181. <td><code>{'{ statePath, index }'}</code></td>
  182. <td>Remove from array by index</td>
  183. </tr>
  184. <tr>
  185. <td><code>navigate</code></td>
  186. <td><code>{'{ href }'}</code></td>
  187. <td>Client-side navigation</td>
  188. </tr>
  189. </tbody>
  190. </table>
  191. ## Server Utilities
  192. ### matchRoute
  193. Match a pathname against a spec's routes.
  194. ```typescript
  195. import { matchRoute } from '@json-render/next/server';
  196. const matched = matchRoute(spec, '/blog/hello-world');
  197. // { route: NextRouteSpec, pattern: '/blog/[slug]', params: { slug: 'hello-world' } }
  198. ```
  199. ### resolveMetadata
  200. Resolve merged metadata for a route.
  201. ```typescript
  202. import { resolveMetadata } from '@json-render/next/server';
  203. const metadata = resolveMetadata(spec, matchedRoute?.route);
  204. ```
  205. ### slugToPath
  206. Convert catch-all slug array to pathname.
  207. ```typescript
  208. import { slugToPath } from '@json-render/next/server';
  209. slugToPath(undefined); // "/"
  210. slugToPath(['blog', 'hello']); // "/blog/hello"
  211. ```
  212. ## Entry Points
  213. <table>
  214. <thead>
  215. <tr>
  216. <th>Import</th>
  217. <th>Contents</th>
  218. </tr>
  219. </thead>
  220. <tbody>
  221. <tr>
  222. <td><code>@json-render/next</code></td>
  223. <td>Client components (NextAppProvider, PageRenderer, Link)</td>
  224. </tr>
  225. <tr>
  226. <td><code>@json-render/next/server</code></td>
  227. <td>Server utilities (createNextApp, matchRoute, schema)</td>
  228. </tr>
  229. </tbody>
  230. </table>