7.9 KiB
Root Cause Analysis: JSON-Based React Component System
Executive Summary
The repository is attempting to transition from a traditional TypeScript React component architecture to a JSON-based declarative UI system. The build is currently failing because the transition is incomplete - some TypeScript components were deleted but their imports remain, and the JSON component system cannot yet fully replace them.
Current State: Hybrid System Failure
What Was Attempted
- 123 TypeScript components were deleted (commit aa51074) and marked as "json-compatible" in the registry
- JSON component registry created with 375+ component definitions
- JSON UI rendering system built with component-renderer.tsx, expression evaluator, data binding, etc.
- Wrapper components created for complex molecules that need special handling
What's Broken
The build fails with these errors:
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "NavigationItem"
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "PageHeaderContent"
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "TreeCard"
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "TreeListHeader"
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "preloadMonacoEditor"
✘ [ERROR] No matching export in "src/components/molecules/index.ts" for import "LoadingFallback"
Root Causes
1. Incomplete Conversion Strategy
Components were marked as JSON-compatible and deleted, but:
- The consuming code still imports them as TypeScript modules
- No migration was done to convert consumers to use the JSON renderer
- The JSON system exists but isn't wired into the main application flow
2. Misunderstanding of JSON Component Architecture
The JSON system is designed for declarative page configurations, not as a drop-in replacement for React components. Example:
Traditional React:
import { TreeCard } from '@/components/molecules'
<TreeCard tree={data} onSelect={handleSelect} />
JSON System:
{
"type": "TreeCard",
"bindings": {
"tree": { "source": "currentTree" }
},
"events": {
"onSelect": { "action": "selectTree" }
}
}
The JSON system requires:
- JSON configuration files
- JSONSchemaPageLoader or PageRenderer wrapper
- Data sources defined in JSON
- Event handlers defined in JSON
- Cannot be imported like a normal React component
3. Deleted Components Still Referenced
Components deleted but still imported:
- TreeCard - Used in TreeListPanel.tsx
- TreeListHeader - Used in TreeListPanel.tsx
- LoadingFallback - Used in JSONSchemaPageLoader.tsx and routes.tsx
- NavigationItem - File exists but not exported from index.ts
- PageHeaderContent - File exists but not exported from index.ts
- preloadMonacoEditor - Function exists but not exported from index.ts
4. Module System vs Component Registry Mismatch
The component-registry.ts uses import.meta.glob to load ALL .tsx files:
const moleculeModules = import.meta.glob('@/components/molecules/*.tsx', { eager: true })
This means:
- It CAN dynamically load TreeCard, TreeListHeader, etc. IF they exist as .tsx files
- But they were DELETED, so they can't be found
- The registry says they're "json-compatible" but provides no fallback
- The JSON renderer can use them IF loaded via JSON config, but direct imports fail
The Fundamental Problem: No Working JSON System Examples
Key Issue: While the JSON UI infrastructure exists, there are NO working examples of pages that successfully:
- Define a complex page entirely in JSON
- Handle state management in JSON
- Wire up all events in JSON
- Replace an existing TypeScript page
The infrastructure exists but hasn't been proven to work end-to-end.
Architecture Deep Dive
JSON UI System Components
src/lib/json-ui/
├── component-renderer.tsx # Renders individual components from JSON
├── page-renderer.tsx # Renders full pages from JSON
├── component-registry.ts # Maps component names to React components
├── expression-evaluator.ts # Evaluates data binding expressions
├── hooks.ts # Data source hooks
├── schema.ts # TypeScript types
└── wrappers/ # Special wrappers for complex components
How It Should Work (Theory)
- Create JSON page definition in
src/config/ui-examples/my-page.json - Load it with
<JSONSchemaPageLoader schemaPath="/config/ui-examples/my-page.json" /> - JSON renderer looks up components in registry
- Registry loads them via import.meta.glob
- Components render with data bindings and events
Why It Doesn't Work (Reality)
- Deleted components can't be loaded - glob can't find non-existent files
- Existing TypeScript pages import components directly - they don't use JSON loader
- No migration path - can't gradually convert pages
- Registry assumes all components exist as .tsx files - no JSON-only components
Two Possible Solutions
Option A: Restore Components (Backward Compatibility)
Goal: Make the build work by restoring deleted components
Steps:
- Restore TreeCard, TreeListHeader, LoadingFallback as .tsx files
- Export NavigationItem, PageHeaderContent, preloadMonacoEditor
- Keep JSON system for future use
- Gradual migration when JSON system proven
Pros: Quick fix, maintains compatibility, low risk Cons: Delays JSON transition, maintains technical debt
Option B: Full JSON Transition (Forward-Looking)
Goal: Convert consuming pages to use JSON system
Steps:
- Convert TreeListPanel.tsx to use JSON renderer
- Convert routes.tsx to load JSON configs
- Create JSON definitions for missing components
- Delete rigid TypeScript components
- Prove JSON system works end-to-end
Pros: Achieves goal of JSON system, modern architecture Cons: High risk, requires extensive testing, may reveal more issues
Recommendation
Start with Option A, then gradually move toward Option B:
-
Immediate Fix (Option A):
- Restore the 3 deleted components (TreeCard, TreeListHeader, LoadingFallback)
- Fix exports for existing components (NavigationItem, PageHeaderContent, preloadMonacoEditor)
- Get the build working
-
Validation Phase:
- Create 1-2 complete working examples of JSON pages
- Test all JSON system features (data binding, events, conditionals, loops)
- Document the conversion process
- Identify limitations
-
Gradual Migration (Option B):
- Convert simple pages first
- Build tooling to help convert TypeScript to JSON
- Only delete TypeScript after JSON proven working
- Keep wrappers for complex components
Files Requiring Immediate Attention
src/components/molecules/TreeCard.tsx- RESTORE from aa51074~1src/components/molecules/TreeListHeader.tsx- RESTORE from aa51074~1src/components/molecules/LoadingFallback.tsx- RESTORE from aa51074~1src/components/molecules/index.ts- ADD exports for NavigationItem, PageHeaderContentsrc/components/molecules/LazyMonacoEditor.tsx- Already exports preloadMonacoEditor, just needs index.ts export
Testing Plan
After fixes:
- Run
npm run dev- should start without errors - Run
npm run build- should complete successfully - Run
npm run test:e2e- should pass - Manually test pages that use restored components
- Test JSON UI showcase page to verify JSON system still works
Long-Term Vision Questions
- Can complex state management work in JSON?
- How do we handle TypeScript types and intellisense for JSON configs?
- What about component composition and reusability?
- Performance implications of JSON parsing and dynamic loading?
- How do non-developers edit JSON configs safely?
- Can we generate JSON from existing TypeScript components?
- What's the migration path for 250+ existing pages?