Code Export
The @nuforge/codegen package turns a program into a clean, standalone React component — with no nuforge at runtime. The result is plain .tsx you can drop into any React project.
import { toReact } from '@nuforge/codegen';
const tsx = toReact(nu.state.program); // a .tsx component string
What it maps
- A component becomes
function Name(props: Props) { ... }, plus aPropsinterface generated from its props. - A
valstate becomesconst [x, setX] = useState(init); an assignmentx = ...becomessetX(...). @if={c}becomes{c && (<jsx/>)}.@each={(item, i) in list}becomes{list.map((item, i) => <jsx key={i} />)}.classand@classListbecomeclassName={[...].filter(Boolean).join(' ')}.- A two-way binding becomes
value={x} onChange={(e) => setX(e.target.value)}. ==and!=become===and!==.
Example
Input DSL:
component App() {
val name = "nuforge";
} => (
<div>
<input value:={name} />
<strong>{name}</strong>
</div>
)
Generated output:
import { useState } from 'react';
export function App() {
const [name, setName] = useState("nuforge");
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<strong>{name}</strong>
</div>
);
}
This powers an "export to real code" feature: a no-code builder can hand the user a real, framework-native component instead of locking them into a proprietary runtime. It is a key differentiator — the output owes nothing to nuforge once exported.
Next.js: 'use client' only when needed
The output follows the App Router convention. toReact adds the leading 'use client' directive only when the module actually needs the client — a component with state, an event handler, or a two-way binding. A purely presentational page stays a React Server Component (no directive, and no useState import):
// static page → Server Component
export function Card(props: CardProps) {
const { title = 'Card' } = props;
return <h3 className="card">{title}</h3>;
}
// has state → client module
'use client';
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Pass toReact(program, { useClient: true }) to force the directive, or imports: false to inline into an existing module.
External components & imports
If your page uses components from another package — e.g. an external <$Motion/>
backed by motion/react, or an icon component — map their names so the export
stays self-contained. Only names actually used (and not defined locally) are
imported, grouped per module:
const tsx = toReact(program, {
componentImports: {
Motion: { from: 'motion/react', named: 'motion' }, // import { motion as Motion } from 'motion/react'
Icon: 'lucide-react', // import { Icon } from 'lucide-react'
Chart: { from: './chart', default: true }, // import Chart from './chart'
},
});
'use client';
import { motion as Motion } from 'motion/react';
export function App() {
return (
<Motion animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4 }}>
Hello
</Motion>
);
}
This is what keeps an animated page (Motion / GSAP wrappers / design-system components) intact once exported.
Other targets: HTML and Vue
Export is not limited to React.
toHtml(frame.view) renders an evaluated View tree to a static HTML string — no JavaScript, no nuforge runtime. Good for static export, email templates, and previews. Event handlers and external (host React) components are omitted.
import { Nu } from '@nuforge/core';
import { toHtml } from '@nuforge/codegen';
const nu = Nu.fromSource(SOURCE);
const frame = nu.createFrame({ component: { name: 'App' } });
const html = toHtml(frame.view); // a static HTML string
toVue(program, opts?) emits a Vue 3 Single-File Component: val becomes ref, @if/@each become v-if/v-for, two-way bindings become v-model, and events become @event.
import { toVue } from '@nuforge/codegen';
const sfc = toVue(program, { component: 'App' });
<script setup lang="ts">
import { ref } from 'vue';
const name = ref("nuforge");
</script>
<template>
<input v-model="name" />
<strong>{{ name }}</strong>
</template>
Reactive-props destructure in the generated SFC requires Vue 3.5+.
Next steps
- React Rendering — render a Frame's reactive View tree live with React.
- Editor SDK — build the visual editing experience around a program.