11 KiB
CODE-EXPORT: React Code Export System
Overview
A comprehensive code export system that transforms Nodegx (Noodl) projects into clean, maintainable React 19 applications. Unlike a simple "eject with TODOs" approach, this system generates fully functional code by including a small companion library (@nodegx/core) that provides Noodl-like reactive primitives.
Phase: Future (Post Phase 3)
Total Estimated Effort: 12-16 weeks
Strategic Value: Very High - eliminates vendor lock-in concern
Philosophy: The Companion Library Approach
The Problem with Pure Code Export
A naive code export faces a fundamental paradigm mismatch:
| Noodl Model | React Model | Challenge |
|---|---|---|
| Push-based signals | Pull-based rendering | Signals → useEffect chains |
| Global Variables | Component state | Cross-component sync |
| Observable Objects | Plain objects | Change detection |
| Event propagation | Props/callbacks | Parent/child/sibling events |
| Visual states | CSS + useState | Animation transitions |
Attempting to mechanically translate every pattern results in either:
- Unreadable code (nested useEffect chains)
- TODO comments (giving up on hard parts)
The Solution: @nodegx/core
Instead of fighting React's model, we provide a tiny runtime library (~8KB) that preserves Noodl's mental model while generating idiomatic code:
┌─────────────────────────────────────────────────────────────────┐
│ project.json │
│ (Noodl Node Graph) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Code Generator │
│ • Analyze component graph │
│ • Identify state boundaries │
│ • Generate React components │
│ • Preserve Function node code │
│ • Wire up reactive primitives │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Generated Project │
│ │
│ my-app/ │
│ ├── src/ │
│ │ ├── components/ ← Clean React components │
│ │ ├── stores/ ← From Variables/Objects/Arrays │
│ │ ├── logic/ ← Extracted Function node code │
│ │ ├── events/ ← Event channel definitions │
│ │ └── App.tsx ← Root with routing │
│ ├── package.json ← Depends on @nodegx/core │
│ └── vite.config.ts ← Modern build setup │
└─────────────────────────────────────────────────────────────────┘
Task Series
| Task | Name | Effort | Description |
|---|---|---|---|
| CODE-001 | @nodegx/core Library | 2-3 weeks | Companion runtime library |
| CODE-002 | Visual Node Generator | 1-2 weeks | UI components + styling |
| CODE-003 | State Store Generator | 1-2 weeks | Variables, Objects, Arrays |
| CODE-004 | Logic Node Generator | 2-3 weeks | Functions, Expressions, Logic |
| CODE-005 | Event System Generator | 1-2 weeks | Send/Receive Event, Component scope |
| CODE-006 | Project Scaffolding | 1-2 weeks | Routing, entry point, build config |
| CODE-007 | CLI & Integration | 1-2 weeks | Export command, editor integration |
Total: 12-16 weeks
Noodl Feature → Generated Code Mapping
Visual Nodes
| Noodl Node | Generated Code |
|---|---|
| Group | <div> with Flexbox/CSS |
| Text | <span> / <p> with text binding |
| Image | <img> with src binding |
| Button | <button> with onClick |
| TextInput | <input> with onChange + controlled value |
| Checkbox | <input type="checkbox"> |
| Repeater | {array.map(item => <Component key={item.id} />)} |
| Page Router | React Router <Routes> + <Route> |
| Page | Route component |
| Component Children | {children} prop |
State & Data Nodes
| Noodl Node | Generated Code |
|---|---|
| Variable | createVariable() from @nodegx/core |
| Set Variable | variable.set(value) |
| Object | createObject() with Proxy |
| Set Object Properties | object.set(key, value) |
| Array | createArray() reactive array |
| Static Array | Plain const array = [...] |
| Insert Into Array | array.push() / array.insert() |
| Remove From Array | array.remove() / array.filter() |
| Array Filter | useArrayFilter(array, predicate) |
| Array Map | useArrayMap(array, transform) |
Logic Nodes
| Noodl Node | Generated Code |
|---|---|
| Function | Extracted function in /logic/ |
| Expression | Inline expression or useMemo |
| Condition | Ternary or if statement |
| Switch | switch statement or object lookup |
| And / Or / Not | && / ` |
| States | State machine using createStateMachine() |
| Delay | setTimeout wrapped in cleanup |
| Debounce | useDebouncedValue() hook |
Event & Communication Nodes
| Noodl Node | Generated Code |
|---|---|
| Send Event | events.emit(channel, data) |
| Receive Event | useEvent(channel, handler) |
| Component Inputs | Component props |
| Component Outputs | Callback props |
| Navigate | useNavigate() from React Router |
Component Scope Nodes
| Noodl Node | Generated Code |
|---|---|
| Component Object | useComponentStore() hook |
| Parent Component Object | useParentStore() with context |
| Repeater Object | item from map callback |
| For Each Item | item from map callback |
Architecture Decision Records
ADR-001: Companion Library vs Pure Export
Decision: Include @nodegx/core companion library
Rationale:
- Preserves Noodl's mental model (easier for users to understand)
- Generates cleaner, more maintainable code
- Avoids useEffect spaghetti
- Library is small (~8KB) and tree-shakeable
- Enables future multi-framework support (same primitives, different renderers)
Trade-offs:
- Still has a "runtime" dependency
- Not 100% "pure React"
ADR-002: Code Generator Architecture
Decision: AST-based generation with templates
Approach:
- Parse project.json into intermediate representation (IR)
- Analyze component boundaries and dependencies
- Generate TypeScript AST using ts-morph
- Apply formatting with Prettier
- Write files to output directory
Why AST over string templates:
- Type-safe code generation
- Automatic import management
- Easier to maintain and extend
- Better handling of edge cases
ADR-003: Styling Approach
Decision: CSS Modules by default, Tailwind optional
Options considered:
- Inline styles (what Noodl uses internally)
- CSS Modules (clean separation)
- Tailwind CSS (utility-first)
- Styled Components (CSS-in-JS)
Rationale:
- CSS Modules work everywhere, no build config needed
- Easy to migrate to other approaches
- Tailwind can be enabled as an option for users who prefer it
Success Criteria
Functional Requirements
- Visual Parity - Exported app looks identical to Noodl preview
- Behavioral Parity - All interactions work the same
- Data Flow Parity - State changes propagate correctly
- Event Parity - Events trigger correct handlers
Code Quality Requirements
- Readable - A React developer can understand the code
- Maintainable - Code follows React best practices
- Typed - Full TypeScript with proper types
- Formatted - Consistent code style (Prettier)
- Organized - Logical file structure
Performance Requirements
- Bundle Size - @nodegx/core adds < 10KB gzipped
- Runtime Performance - No worse than hand-written React
- Build Time - Export completes in < 30 seconds for typical project
Out of Scope (Phase 1)
The following are explicitly NOT included in the initial implementation:
- Database/Cloud nodes - Query Records, Cloud Functions (placeholder stubs)
- Round-trip editing - Cannot re-import exported code
- Framework targets - Only React 19 initially
- Native targets - No React Native export yet
- SSR/SSG - Client-side only initially
Related Documents
- CODE-001: @nodegx/core Library
- CODE-002: Visual Node Generator
- CODE-003: State Store Generator
- CODE-004: Logic Node Generator
- CODE-005: Event System Generator
- CODE-006: Project Scaffolding
Appendix: What This Enables
Use Cases
-
Prototype → Production Handoff
- Build MVP in Nodegx
- Validate with users
- Export for engineering team
-
Outgrowing Low-Code
- Project needs custom functionality
- Export and continue in code
-
Learning Tool
- See how visual designs become code
- Learn React patterns
-
Component Libraries
- Build UI components visually
- Export for use in other projects
-
Hybrid Development
- Design system in Nodegx
- Export components
- Use in larger codebase
Strategic Benefits
- Eliminates vendor lock-in - Users can always leave
- Builds trust - Transparent about what Nodegx does
- Enables enterprise adoption - IT teams can audit code
- Creates evangelists - Exported code spreads Nodegx patterns