export const metadata = { title: "Code Export" } # Code Export Export generated UI as standalone code for your framework. ## Overview While json-render is designed for dynamic rendering, you can export generated UI as static code. The code generation is intentionally project-specific so you have full control over: - Component templates (standalone, no json-render dependencies) - Package.json and project structure - Framework-specific patterns (Next.js, Remix, etc.) - How data is passed to components ## Architecture Code export is split into two parts: ### 1. @json-render/codegen (utilities) Framework-agnostic utilities for building code generators: ```typescript import { traverseSpec, // Walk the UI spec collectUsedComponents, // Get all component types used collectStatePaths, // Get all data binding paths collectActions, // Get all action names serializeProps, // Convert props to JSX string } from '@json-render/codegen'; ``` ### 2. Your Project (generator) Custom code generator specific to your project and framework: ```typescript // lib/codegen/generator.ts import { collectUsedComponents, serializeProps } from '@json-render/codegen'; export function generateNextJSProject(spec: Spec): GeneratedFile[] { const components = collectUsedComponents(spec); return [ { path: 'package.json', content: '...' }, { path: 'app/page.tsx', content: '...' }, // ... component files ]; } ``` ## Example: Next.js Export See the dashboard example for a complete implementation that exports: - `package.json` - Dependencies and scripts - `tsconfig.json` - TypeScript config - `next.config.js` - Next.js config - `app/layout.tsx` - Root layout - `app/globals.css` - Global styles - `app/page.tsx` - Generated page with data - `components/ui/*.tsx` - Standalone components ## Standalone Components The exported components are standalone with no json-render dependencies. They receive data as props instead of using hooks: ```tsx // Generated component (standalone) interface MetricProps { label: string; statePath: string; data?: Record; } export function Metric({ label, statePath, data }: MetricProps) { const value = data ? getByPath(data, statePath) : undefined; return (
{label} {formatValue(value)}
); } ``` ## Using the Utilities ### traverseSpec ```typescript import { traverseSpec } from '@json-render/codegen'; traverseSpec(spec, (element, key, depth, parent) => { console.log(' '.repeat(depth * 2) + `${key}: ${element.type}`); }); ``` ### collectUsedComponents ```typescript import { collectUsedComponents } from '@json-render/codegen'; const components = collectUsedComponents(spec); // Set { 'Card', 'Metric', 'Chart', 'Table' } // Generate only the needed component files for (const component of components) { files.push({ path: `components/ui/${component.toLowerCase()}.tsx`, content: componentTemplates[component], }); } ``` ### serializeProps ```typescript import { serializeProps } from '@json-render/codegen'; const propsStr = serializeProps({ title: 'Dashboard', columns: 3, disabled: true, }); // 'title="Dashboard" columns={3} disabled' ``` ## Try It Run the dashboard example and click "Export Project" to see code generation in action: ```bash cd examples/dashboard pnpm dev # Open http://localhost:3001 # Generate a widget, then click "Export Project" ```