Code Export
Export generated UI as standalone code for your framework.
Overview
While Jsonable 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 Jsonable 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:
import {
traverseTree, // Walk the UI tree
collectUsedComponents, // Get all component types used
collectDataPaths, // 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:
// lib/codegen/generator.ts
import { collectUsedComponents, serializeProps } from '@json-render/codegen';
export function generateNextJSProject(tree: UITree): GeneratedFile[] {
const components = collectUsedComponents(tree);
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 scriptstsconfig.json- TypeScript confignext.config.js- Next.js configapp/layout.tsx- Root layoutapp/globals.css- Global stylesapp/page.tsx- Generated page with datacomponents/ui/*.tsx- Standalone components
Standalone Components
The exported components are standalone with no Jsonable dependencies. They receive data as props instead of using hooks:
// Generated component (standalone)
interface MetricProps {
label: string;
valuePath: string;
data?: Record<string, unknown>;
}
export function Metric({ label, valuePath, data }: MetricProps) {
const value = data ? getByPath(data, valuePath) : undefined;
return (
<div>
<span>{label}</span>
<span>{formatValue(value)}</span>
</div>
);
}Using the Utilities
traverseTree
import { traverseTree } from '@json-render/codegen';
traverseTree(tree, (element, depth, parent) => {
console.log(' '.repeat(depth * 2) + element.type);
});collectUsedComponents
import { collectUsedComponents } from '@json-render/codegen';
const components = collectUsedComponents(tree);
// 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
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:
cd examples/dashboard
pnpm dev
# Open http://localhost:3001
# Generate a widget, then click "Export Project"