qwen-code/packages/webui/docs/WEBUI_MIGRATION_PLAN_EN.md

18 KiB

WebUI Component Library Extraction Plan

1. Background and Goals

1.1 Background

packages/vscode-ide-companion is a VSCode extension whose core content is a WebView page with UI components provided by React. As the product line expands, more scenarios require building products with Web UI:

  • Chrome Browser Extension - Sidebar chat interface
  • Web Chat Page - Pure web application
  • Conversation Share Page - Render conversations as static HTML

For excellent software engineering architecture, we need to unify and reuse UI components across products.

1.2 Goals

  1. Extract components from vscode-ide-companion/src/webview/ into an independent @qwen-code/webui package
  2. Establish a layered architecture: Pure UI components + Business UI components
  3. Use Vite + Storybook for development and component showcase
  4. Abstract platform capabilities through Platform Context for cross-platform reuse
  5. Provide Tailwind CSS preset to ensure UI consistency across products

2. Current State Analysis

2.1 Current Code Structure

packages/vscode-ide-companion/src/webview/ contains 77 files:

webview/
├── App.tsx                    # Main entry
├── components/
│   ├── icons/                 # 8 icon components
│   ├── layout/                # 8 layout components
│   │   ├── ChatHeader.tsx
│   │   ├── InputForm.tsx
│   │   ├── SessionSelector.tsx
│   │   ├── EmptyState.tsx
│   │   ├── Onboarding.tsx
│   │   └── ...
│   ├── messages/              # Message display components
│   │   ├── UserMessage.tsx
│   │   ├── Assistant/
│   │   ├── MarkdownRenderer/
│   │   ├── ThinkingMessage.tsx
│   │   ├── Waiting/
│   │   └── toolcalls/         # 16 tool call components
│   ├── PermissionDrawer/      # Permission request drawer
│   └── Tooltip.tsx
├── hooks/                     # Custom hooks
├── handlers/                  # Message handlers
├── styles/                    # CSS styles
└── utils/                     # Utility functions

2.2 Key Dependency Analysis

Platform Coupling Points:

  • useVSCode hook - Calls acquireVsCodeApi() for message communication
  • handlers/ - Handles VSCode message protocol
  • Some type definitions come from ../types/ directory
┌─────────────────────────────────────────────────────────┐
│                    App.tsx (Entry)                       │
├─────────────────────────────────────────────────────────┤
│  hooks/          │  handlers/       │  components/      │
│  ├─useVSCode ◄───┼──────────────────┼──────────────────┤
│  ├─useSession    │  ├─MessageRouter │  ├─icons/        │
│  ├─useFileContext│  ├─AuthHandler   │  ├─layout/       │
│  └─...           │  └─...           │  ├─messages/     │
│                  │                  │  └─PermDrawer/   │
├─────────────────────────────────────────────────────────┤
│            VSCode API (acquireVsCodeApi)                │
└─────────────────────────────────────────────────────────┘

3. Target Architecture

3.1 Layered Architecture Design

┌─────────────────────────────────────────────────────────┐
│              Layer 3: Platform Adapters                 │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐    │
│  │VSCode Adapter│ │Chrome Adapter│ │ Web Adapter  │    │
│  └──────┬───────┘ └──────┬───────┘ └──────┬───────┘    │
├─────────┼────────────────┼────────────────┼────────────┤
│         │                │                │             │
│         ▼                ▼                ▼             │
│  ┌─────────────────────────────────────────────────┐   │
│  │           Platform Context Provider              │   │
│  └─────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────┤
│              Layer 2: Chat Components                   │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐          │
│  │ MessageList│ │ ChatHeader │ │ InputForm  │          │
│  └────────────┘ └────────────┘ └────────────┘          │
├─────────────────────────────────────────────────────────┤
│              Layer 1: Primitives (Pure UI)              │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐          │
│  │ Button │ │ Input  │ │ Icons  │ │Tooltip │          │
│  └────────┘ └────────┘ └────────┘ └────────┘          │
└─────────────────────────────────────────────────────────┘

3.2 Platform Context Design

// @qwen-code/webui/src/context/PlatformContext.ts
interface PlatformContext {
  // Message communication
  postMessage: (message: unknown) => void;
  onMessage: (handler: (message: unknown) => void) => () => void;

  // File operations
  openFile?: (path: string) => void;
  attachFile?: () => void;

  // Authentication
  login?: () => void;

  // Platform info
  platform: 'vscode' | 'chrome' | 'web' | 'share';
}

4. Technical Solution

4.1 Build Configuration (Vite Library Mode)

Output formats:

  • ESM (dist/index.js) - Primary format
  • CJS (dist/index.cjs) - Compatibility
  • TypeScript declarations (dist/index.d.ts)
// vite.config.ts
export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      formats: ['es', 'cjs'],
      fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`,
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
    },
  },
});

4.2 Tailwind Preset Solution

// @qwen-code/webui/tailwind.preset.js
module.exports = {
  theme: {
    extend: {
      colors: {
        'app-primary': 'var(--app-primary)',
        'app-background': 'var(--app-primary-background)',
        'app-foreground': 'var(--app-primary-foreground)',
      },
    },
  },
};

// Consumer's tailwind.config.js
module.exports = {
  presets: [require('@qwen-code/webui/tailwind.preset')],
  content: [
    './src/**/*.{ts,tsx}',
    './node_modules/@qwen-code/webui/dist/**/*.js',
  ],
};

4.3 Storybook Configuration

packages/webui/
├── .storybook/
│   ├── main.ts      # Storybook config
│   ├── preview.ts   # Global decorators
│   └── manager.ts   # UI config
└── src/
    └── stories/     # Story files

5. Component Migration Classification

5.1 Batch 1: No-dependency Components (Ready to migrate)

Component Source Path Complexity Notes
Icons components/icons/ Low 8 icon components, pure SVG
Tooltip components/Tooltip.tsx Low Pure UI
WaitingMessage messages/Waiting/ Low Loading state display
InterruptedMessage messages/Waiting/ Low Interrupted state display

5.2 Batch 2: Light-dependency Components (Need props abstraction)

Component Source Path Dependency Refactoring
UserMessage messages/UserMessage.tsx onFileClick Props injection
AssistantMessage messages/Assistant/ onFileClick Props injection
ThinkingMessage messages/ThinkingMessage.tsx onFileClick Props injection
MarkdownRenderer messages/MarkdownRenderer/ None Direct migration
EmptyState layout/EmptyState.tsx None Direct migration
ChatHeader layout/ChatHeader.tsx callbacks Props injection

5.3 Batch 3: Medium-dependency Components (Need Context)

Component Source Path Dependency Refactoring
InputForm layout/InputForm.tsx Multiple callbacks Context + Props
SessionSelector layout/SessionSelector.tsx session data Props injection
CompletionMenu layout/CompletionMenu.tsx items data Props injection
PermissionDrawer PermissionDrawer/ callbacks Context + Props
ToolCall components messages/toolcalls/ Various tool displays Modular migration

5.4 Batch 4: Heavy-dependency (Keep in platform package)

Component/Module Notes
App.tsx Main entry, contains business orchestration logic
hooks/ Most require platform adaptation
handlers/ VSCode message handling
Onboarding Authentication related, platform-specific

6. Incremental Migration Strategy

6.1 Migration Principles

  1. Bidirectional compatibility: During migration, vscode-ide-companion can import from both webui and local
  2. One-by-one replacement: For each migrated component, replace import path in VSCode extension and verify
  3. No breaking changes: Ensure the extension builds and runs normally after each migration

6.2 Migration Workflow

Developer ──► @qwen-code/webui ──► vscode-ide-companion
  │              │                      │
  │   1. Copy component to webui        │
  │   2. Add Story for verification     │
  │   3. Export from index.ts           │
  │              │                      │
  │              └──────────────────────┤
  │                                     │
  │                      4. Update import path
  │                      5. Delete original component
  │                      6. Build and test

6.3 Example: Migrating Icons

// Before: vscode-ide-companion/src/webview/components/icons/index.ts
export { FileIcon } from './FileIcons.js';

// After: Update import
import { FileIcon } from '@qwen-code/webui';
// or import { FileIcon } from '@qwen-code/webui/icons';

7. Task Breakdown

Phase 0: Infrastructure Setup (Prerequisites)

  • T0-1: Vite build configuration
  • T0-2: Storybook configuration
  • T0-3: Tailwind preset creation
  • T0-4: Platform Context definition
  • T0-5: Shared types migration

Phase 1: Pure UI Components Migration

  • T1-1: Icons components migration (8 files)
  • T1-2: Tooltip component migration
  • T1-3: WaitingMessage / InterruptedMessage migration
  • T1-4: Basic Button/Input components refinement

Phase 2: Message Components Migration

  • T2-1: MarkdownRenderer migration
  • T2-2: UserMessage migration
  • T2-3: AssistantMessage migration
  • T2-4: ThinkingMessage migration

Phase 3: Layout Components Migration

  • T3-1: ChatHeader migration
  • T3-2: EmptyState migration
  • T3-3: InputForm migration (requires Context)
  • T3-4: SessionSelector migration
  • T3-5: CompletionMenu migration

Phase 4: Complex Components Migration

  • T4-1: PermissionDrawer migration
  • T4-2: ToolCall series components migration (16 files)

Phase 5: Platform Adapters

  • T5-1: VSCode Adapter implementation
  • T5-2: Chrome Extension Adapter
  • T5-3: Web/Share Page Adapter

8. Risks and Considerations

8.1 Common Pitfalls

  1. Tailwind Class Name Tree Shaking

    • Problem: Tailwind class names may be removed after library bundling
    • Solution: Consumer's content config needs to include node_modules/@qwen-code/webui
  2. CSS Variable Scope

    • Problem: Variables like var(--app-primary) need to be defined by consumers
    • Solution: Provide default CSS variables file, or define fallbacks in Tailwind preset
  3. React Version Compatibility

    • Current vscode-ide-companion uses React 19, webui's peerDependencies is React 18
    • Need to update peerDependencies to "react": "^18.0.0 || ^19.0.0"
  4. ESM/CJS Compatibility

    • VSCode extensions may require CJS format
    • Vite needs to be configured for dual format output

8.2 Industry References

  • Radix UI: Pure Headless components, styles completely controlled by consumers
  • shadcn/ui: Copy components into project, rather than importing as dependency
  • Ant Design: Complete component library, customization through ConfigProvider

8.3 Acceptance Criteria

Each migration task completion requires:

  1. Component has corresponding Storybook Story
  2. Import in vscode-ide-companion has been updated
  3. Extension builds successfully (npm run build:vscode)
  4. Extension functionality works (manual testing or existing tests pass)

9. Time Estimation

Phase Tasks Estimated Days Parallelizable
Phase 0 5 2-3 days Partially
Phase 1 4 1-2 days Fully
Phase 2 4 2-3 days Fully
Phase 3 5 3-4 days Partially
Phase 4 2 3-4 days Yes
Phase 5 3 2-3 days Yes

Total: Approximately 13-19 person-days (sequential execution), can be reduced to 1-2 weeks with parallel work


10. Development and Debugging Workflow

10.1 Component Development Flow

┌─────────────────────────────────────────────────────────────────┐
│                    Development Workflow                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. Develop/Modify Component                                     │
│     └── Edit files in @qwen-code/webui/src/                     │
│                                                                  │
│  2. Debug with Storybook                                         │
│     └── npm run storybook (port 6006)                           │
│     └── View component in isolation                              │
│     └── Test different props/states                              │
│                                                                  │
│  3. Build Library                                                │
│     └── npm run build                                            │
│     └── Outputs: dist/index.js, dist/index.cjs, dist/index.d.ts │
│                                                                  │
│  4. Use in VSCode Extension                                      │
│     └── import { Component } from '@qwen-code/webui'            │
│     └── No UI code modifications in vscode-ide-companion        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

10.2 Debugging Commands

# Start Storybook for component development
cd packages/webui
npm run storybook

# Watch mode for library development
npm run dev

# Build library for production
npm run build

# Type checking
npm run typecheck

10.3 Key Principles

  1. Single Source of Truth: All UI components live in @qwen-code/webui
  2. Storybook First: Debug and validate components in Storybook before integration
  3. No UI Code in Consumers: vscode-ide-companion only imports and uses components
  4. Platform Abstraction: Use PlatformContext for platform-specific behaviors