page.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { Code } from "@/components/code";
  2. export const metadata = {
  3. title: "Code Export | json-render",
  4. };
  5. export default function CodeExportPage() {
  6. return (
  7. <article>
  8. <h1 className="text-3xl font-bold mb-4">Code Export</h1>
  9. <p className="text-muted-foreground mb-8">
  10. Export generated UI as standalone code for your framework.
  11. </p>
  12. <h2 className="text-xl font-semibold mt-12 mb-4">Overview</h2>
  13. <p className="text-sm text-muted-foreground mb-4">
  14. While json-render is designed for dynamic rendering, you can export
  15. generated UI as static code. The code generation is intentionally
  16. project-specific so you have full control over:
  17. </p>
  18. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-2 mb-8">
  19. <li>Component templates (standalone, no json-render dependencies)</li>
  20. <li>Package.json and project structure</li>
  21. <li>Framework-specific patterns (Next.js, Remix, etc.)</li>
  22. <li>How data is passed to components</li>
  23. </ul>
  24. <h2 className="text-xl font-semibold mt-12 mb-4">Architecture</h2>
  25. <p className="text-sm text-muted-foreground mb-4">
  26. Code export is split into two parts:
  27. </p>
  28. <h3 className="text-lg font-semibold mt-8 mb-4">
  29. 1. @json-render/codegen (utilities)
  30. </h3>
  31. <p className="text-sm text-muted-foreground mb-4">
  32. Framework-agnostic utilities for building code generators:
  33. </p>
  34. <Code lang="typescript">{`import {
  35. traverseTree, // Walk the UI tree
  36. collectUsedComponents, // Get all component types used
  37. collectDataPaths, // Get all data binding paths
  38. collectActions, // Get all action names
  39. serializeProps, // Convert props to JSX string
  40. } from '@json-render/codegen';`}</Code>
  41. <h3 className="text-lg font-semibold mt-8 mb-4">
  42. 2. Your Project (generator)
  43. </h3>
  44. <p className="text-sm text-muted-foreground mb-4">
  45. Custom code generator specific to your project and framework:
  46. </p>
  47. <Code lang="typescript">{`// lib/codegen/generator.ts
  48. import { collectUsedComponents, serializeProps } from '@json-render/codegen';
  49. export function generateNextJSProject(tree: UITree): GeneratedFile[] {
  50. const components = collectUsedComponents(tree);
  51. return [
  52. { path: 'package.json', content: '...' },
  53. { path: 'app/page.tsx', content: '...' },
  54. // ... component files
  55. ];
  56. }`}</Code>
  57. <h2 className="text-xl font-semibold mt-12 mb-4">
  58. Example: Next.js Export
  59. </h2>
  60. <p className="text-sm text-muted-foreground mb-4">
  61. See the dashboard example for a complete implementation that exports:
  62. </p>
  63. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-2 mb-4">
  64. <li>
  65. <code className="text-foreground">package.json</code> - Dependencies
  66. and scripts
  67. </li>
  68. <li>
  69. <code className="text-foreground">tsconfig.json</code> - TypeScript
  70. config
  71. </li>
  72. <li>
  73. <code className="text-foreground">next.config.js</code> - Next.js
  74. config
  75. </li>
  76. <li>
  77. <code className="text-foreground">app/layout.tsx</code> - Root layout
  78. </li>
  79. <li>
  80. <code className="text-foreground">app/globals.css</code> - Global
  81. styles
  82. </li>
  83. <li>
  84. <code className="text-foreground">app/page.tsx</code> - Generated page
  85. with data
  86. </li>
  87. <li>
  88. <code className="text-foreground">components/ui/*.tsx</code> -
  89. Standalone components
  90. </li>
  91. </ul>
  92. <h2 className="text-xl font-semibold mt-12 mb-4">
  93. Standalone Components
  94. </h2>
  95. <p className="text-sm text-muted-foreground mb-4">
  96. The exported components are standalone with no json-render dependencies.
  97. They receive data as props instead of using hooks:
  98. </p>
  99. <Code lang="tsx">{`// Generated component (standalone)
  100. interface MetricProps {
  101. label: string;
  102. valuePath: string;
  103. data?: Record<string, unknown>;
  104. }
  105. export function Metric({ label, valuePath, data }: MetricProps) {
  106. const value = data ? getByPath(data, valuePath) : undefined;
  107. return (
  108. <div>
  109. <span>{label}</span>
  110. <span>{formatValue(value)}</span>
  111. </div>
  112. );
  113. }`}</Code>
  114. <h2 className="text-xl font-semibold mt-12 mb-4">Using the Utilities</h2>
  115. <h3 className="text-lg font-semibold mt-8 mb-4">traverseTree</h3>
  116. <Code lang="typescript">{`import { traverseTree } from '@json-render/codegen';
  117. traverseTree(tree, (element, depth, parent) => {
  118. console.log(' '.repeat(depth * 2) + element.type);
  119. });`}</Code>
  120. <h3 className="text-lg font-semibold mt-8 mb-4">collectUsedComponents</h3>
  121. <Code lang="typescript">{`import { collectUsedComponents } from '@json-render/codegen';
  122. const components = collectUsedComponents(tree);
  123. // Set { 'Card', 'Metric', 'Chart', 'Table' }
  124. // Generate only the needed component files
  125. for (const component of components) {
  126. files.push({
  127. path: \`components/ui/\${component.toLowerCase()}.tsx\`,
  128. content: componentTemplates[component],
  129. });
  130. }`}</Code>
  131. <h3 className="text-lg font-semibold mt-8 mb-4">serializeProps</h3>
  132. <Code lang="typescript">{`import { serializeProps } from '@json-render/codegen';
  133. const propsStr = serializeProps({
  134. title: 'Dashboard',
  135. columns: 3,
  136. disabled: true,
  137. });
  138. // 'title="Dashboard" columns={3} disabled'`}</Code>
  139. <h2 className="text-xl font-semibold mt-12 mb-4">Try It</h2>
  140. <p className="text-sm text-muted-foreground mb-4">
  141. Run the dashboard example and click &quot;Export Project&quot; to see
  142. code generation in action:
  143. </p>
  144. <Code lang="bash">{`cd examples/dashboard
  145. pnpm dev
  146. # Open http://localhost:3001
  147. # Generate a widget, then click "Export Project"`}</Code>
  148. </article>
  149. );
  150. }