| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- import { pageMetadata } from "@/lib/page-metadata"
- export const metadata = pageMetadata("docs/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<string, unknown>;
- }
- export function Metric({ label, statePath, data }: MetricProps) {
- const value = data ? getByPath(data, statePath) : undefined;
- return (
- <div>
- <span>{label}</span>
- <span>{formatValue(value)}</span>
- </div>
- );
- }
- ```
- ## 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://dashboard-demo.json-render.localhost:1355
- # Generate a widget, then click "Export Project"
- ```
|