Skip to content

Jiangultimo/react-visual-edit-vite

Repository files navigation

English | 中文

Visual Edit

What is Visual Edit?

A React visual editor based on Babel AST transformation that supports editing component styles and text directly in the browser, with changes written back to source code.

Why Visual Edit?

With the rapid advancement of large language models, many people (including non-programmers) have started using AI to build their own Web Apps. However, AI-generated results don't always meet our expectations - sometimes you just want to change a font color but have to re-generate everything. In such cases, a simple style code change would suffice. With visual editing capabilities integrated as part of an AI-generated Web App boilerplate, you can simply switch to edit mode after AI generates the code, easily modify page styles (background color, font size, etc.), significantly reducing token consumption while achieving WYSIWYG precise control.

Note

This repository is just a technical proof-of-concept.

Features

  • Visual Editing - Edit component styles and text directly in the browser
  • Live Preview - Changes are reflected immediately
  • Inline Styles - Styles are written as style={{ ... }} in source code
  • Code Writeback - Automatically updates source files on save
  • Hot Module Replacement - No page refresh needed
  • Dynamic Content Protection - Elements containing state are marked as non-editable

Technical Approach

Core Principles

  1. Compile-time Injection - Vite plugin parses JSX via Babel during the transform phase, injecting unique data-vid identifiers into each element while recording VID to source location mappings

  2. AST Path Positioning - Uses AST paths (e.g., body.4.body.body.1.argument) instead of line numbers to locate elements, ensuring accurate node targeting even after code formatting

  3. Runtime Editing - Identifies editable elements via data-vid in the browser, style modifications directly manipulate DOM for live preview

  4. Backend AST Writeback - On save, backend looks up mapping by VID, re-parses source file into AST, locates target node and updates style attribute, then generates new code and writes to file

  5. Hot Update Sync - File write triggers Vite HMR for seamless page updates

Overall Flow Diagram

┌─────────────────────────────────────────────────────────────────┐
│                    Compile Time (Vite Plugin)                    │
├─────────────────────────────────────────────────────────────────┤
│  JSX Source                                                      │
│  <h1 className="title">Hello</h1>                               │
│                           ↓                                      │
│  Babel AST Parse + Traverse                                      │
│                           ↓                                      │
│  Inject data-vid attribute + Detect dynamic content              │
│                           ↓                                      │
│  <h1 className="title" data-vid="App.tsx:h1:0">Hello</h1>       │
│                                                                  │
│  Also record VID → source location mapping (vidMap)              │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                      Runtime (Browser)                           │
├─────────────────────────────────────────────────────────────────┤
│  User clicks element                                             │
│        ↓                                                         │
│  Get data-vid → Show edit panel                                  │
│        ↓                                                         │
│  User modifies styles → Live preview (direct el.style changes)   │
│        ↓                                                         │
│  Click save → Send request to /__visual_edit                     │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                  Backend Processing (Vite Middleware)            │
├─────────────────────────────────────────────────────────────────┤
│  Receive request { vid, styles, newText }                        │
│        ↓                                                         │
│  Get file path and AST path from vidMap                          │
│        ↓                                                         │
│  Read source file → Babel parse → Locate JSX node                │
│        ↓                                                         │
│  Update style attribute (AST operation)                          │
│        ↓                                                         │
│  Generate new code → Write to file                               │
│        ↓                                                         │
│  Trigger HMR hot update                                          │
└─────────────────────────────────────────────────────────────────┘

Quick Start

# Install dependencies
npm install

# Start development server
npm run dev

Visit http://localhost:5173

Project Structure

visual-edit-demo-for-vite/
├── src/
│   ├── plugins/                    # Vite plugin (compile-time + backend)
│   │   ├── index.ts                # Plugin entry point
│   │   └── utils/
│   │       ├── ast.ts              # AST operation utilities
│   │       └── types.ts            # Type definitions
│   ├── utils/
│   │   └── overlay/                # Frontend edit interface
│   │       ├── index.ts            # Export entry
│   │       ├── domElements.ts      # UI element creation
│   │       └── visualEditOverlay.ts # Interaction logic
│   ├── App.tsx                     # Demo application
│   ├── main.tsx                    # App entry point
│   └── index.css                   # Global styles
├── vite.config.ts                  # Vite configuration
└── package.json

Core Module Details

1. Vite Plugin (plugins/index.ts)

The plugin processes JSX files in Vite's transform hook:

// Main functions:
// 1. Inject data-vid attribute into each JSX element
// 2. Detect dynamic content, mark with data-has-state
// 3. Build VID → source location mapping
// 4. Provide /__visual_edit API endpoint for edit requests

VID Format: filename:elementName:index, e.g., App.tsx:h1:0

VID Map Structure:

interface VidMapEntry {
  file: string;           // Source file path
  astPath: string;        // AST navigation path
  elementName: string;    // Element name
  classLiteralStart: number;
  classLiteralEnd: number;
}

Dynamic Content Detection:

// Check if JSX children contain expressions
// <button>{count}</button> → data-has-state="true"
for (const child of jsxElement.children) {
  if (t.isJSXExpressionContainer(child)) {
    hasDynamicContent = true;
  }
}

2. AST Operations (plugins/utils/ast.ts)

Provides precise source code modification capabilities:

// Core functions:

// Generate AST path (compile-time)
generateASTPath(path)  "body.4.body.body.1.argument.children.3"

// Locate node by path (runtime)
findNodeByPath(ast, pathString)  JSXElement

// Update code
updateCodeWithAST(code, astPath, {
  newClassName?: string,
  newText?: string,
  newStyles?: StyleConfig  // inline styles
})

Style Update Logic:

// Update or create style attribute
// If style={{ ... }} exists, merge styles
// Example output:
// style={{ color: "#ff0000", fontSize: "18px" }}

3. Frontend Edit Interface (utils/overlay/)

domElements.ts - UI element factory:

createHighlightBox()     // Highlight box
createFileLabel()        // Element name label
createToggleButton()     // Edit mode toggle button
createStylePanel()       // Right-side drawer panel
showToast()              // Toast notifications

visualEditOverlay.ts - Interaction logic:

// State management
let enabled = false;
let currentEditingElement: HTMLElement | null = null;

// Core functions
highlight(el)            // Highlight element
enterEditMode(el)        // Enter edit mode
exitEditMode()           // Exit edit mode
saveStyles()             // Save to backend

Data Flow

Edit Save Flow

User clicks save
      ↓
Collect data: { vid, styles, newText }
      ↓
POST /__visual_edit
      ↓
Backend parses vid → Get VidMapEntry
      ↓
Read source file → Parse to AST with Babel
      ↓
findNodeByPath() locates JSX node
      ↓
updateStyleAttribute() updates style attribute
      ↓
generate() produces new code
      ↓
Write to file → Trigger HMR

Request/Response Format

Request Body:

interface EditRequest {
  vid: string;
  currentClassName?: string;
  newText?: string;
  styles?: {
    color?: string;
    backgroundColor?: string;
    fontSize?: string;
    fontWeight?: string;
  };
}

Response:

{ "ok": true }

Tech Stack

Category Technology
UI Framework React 19
Build Tool Vite 7
AST Parsing @babel/parser
AST Traversal @babel/traverse
AST Generation @babel/generator
Type System TypeScript
Styling Tailwind CSS 4

Notes

  1. Development Mode Only - Edit functionality is only available when running npm run dev
  2. Version Control - Changes are written directly to source files, Git usage is recommended
  3. Dynamic Content - Elements containing {state} expressions cannot be edited
  4. Text Elements - Only supports p, span, button, h1-h6, a, label, div and similar text elements

License

MIT

About

Visual editor for AI-generated React apps - WYSIWYG style editing with source code writeback via Vite plugin

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors