Files
wukuang/重构计划-25-12.md
T

107 lines
5.3 KiB
Markdown
Raw Normal View History

2026-05-23 14:05:22 +08:00
# Monorepo Refactoring Plan: Decoupling Designer, Engines, and Materials
This document outlines the step-by-step plan to refactor the current `form-designer` monolithic structure into a clean, decoupled Monorepo architecture.
**Core Philosophy:** Separation of Concerns. The Designer acts as a shell, Engines enforce logic, and Materials provide UI implementation.
---
## 🏗 Architecture Overview
| Layer | Package | Responsibility |
| :---------------- | :----------------------- | :--------------------------------------------------------------------------------------------------- |
| **Foundation** | `@lingshu/types` | Shared interfaces, DSL definitions, and constants. |
| | `@lingshu/core-utils` | Pure JS utilities (framework agnostic). |
| **Logic Engines** | `@lingshu/user-script` | Runtime for standard User Scripts (Hooks, Actions) and Rule Engine (Low-code logical linkage). |
| **Materials** | `@lingshu/widget-pc` | PC Vue components, widget configurations, and property panels. |
| | `@lingshu/widget-mobile` | Mobile Vue components (Future). |
| **Host/Editor** | `@lingshu/form-designer` | The visual editor shell. Implements adapters for engines and exposes extension points for materials. |
| **Application** | `apps/lcdp` | The assembler entry point that wires everything together. |
---
## 📅 Phased Execution Plan
The refactoring is divided into 3 autonomous phases. **At the end of each phase, the project MUST be buildable and runnable.**
### Phase 1: Foundation Construction (Infrastructure)
**Goal**: Establish a shared language (`types`) to break circular dependencies and prepare for code migration.
- **Boundary**: No functional logic changes. Only moving definitions and constants.
- **Deliverable**: Codebase uses `@lingshu/types` for shared entities instead of relative imports.
- **Verification**:
1. `pnpm build` passes for all packages.
2. `npm run dev` in `form-designer` works exactly as before.
**Tasks:**
1. **Define Shared Types**: Extract `WidgetSchema`, `UserScriptContext`, `RuntimeEventApiBO` to `@lingshu/types`.
2. **Define Injection Keys**: Extract `USER_SCRIPT_EVENT_BUS_KEY` to `@lingshu/types`.
3. **Refactor Imports**: Update `form-designer` and `widget-pc` to import from `@lingshu/types`.
---
### Phase 2: Logic Engine Extraction (The Brain)
**Goal**: Isolate the "User Script" and "Rule Engine" logic into a standalone package that doesn't depend on UI stores directly.
- **Boundary**: `packages/user-script` contains pure logic. Access to Store/API is done via **Dependency Injection**.
- **Deliverable**: A new `@lingshu/user-script` package. `form-designer` initializes this engine by injecting its internal state adapters.
- **Verification**:
1. User Scripts (e.g., `onClick` logs) work in the Designer preview.
2. Rule Linkages (e.g., input A changes -> input B hides) work in the Designer preview.
**Tasks:**
1. **Create Package**: Set up `packages/user-script` workspace.
2. **Migrate Logic**: Move `src/config/user-script` (Definitions) and `src/utils/user-script` (Runtime) to the new package.
3. **Refactor for DI**: Transform functions that directly import `PageStore` to accept `context` or `adapter` arguments.
4. **Wire Up**: In `form-designer/main.ts` (or boot sequence), call `initScriptEngine(adapters)` from the new package.
---
### Phase 3: Material Decoupling (The Body)
**Goal**: Move all PC-specific widget configurations and implementations out of the Designer.
- **Boundary**: `form-designer` becomes unaware of specific widgets. It loads whatever is passed to its `.use()` method.
- **Deliverable**: `packages/widget-pc` contains all material definitions (`config/*`) and components components.
- **Verification**:
1. Designer starts empty initially (theoretically).
2. After injecting `WidgetPC`, the left palette shows PC components.
3. Dragging components to canvas works correctly.
**Tasks:**
1. **Move Configs**: Relocate `form-designer/src/config` (Materials, Settings) to `packages/widget-pc/src/config`.
2. **Refactor Hooks**: Move specific widget hooks (like `components/anchor/useCompEvent`) to `widget-pc`.
3. **Plugin Architecture**: create a `registerWidgets` export in `widget-pc`.
4. **Injection**: In the App Entry/Main, import `registerWidgets` and pass it to the Designer instance.
---
## 🔄 Dependency Injection Strategy (Crucial)
To achieve decoupling, we use standard **Dependency Injection**.
**1. Service Injection (Logic Layer)**
Instead of importing `axios` or `pinia` in `user-script`:
```typescript
// packages/user-script/src/index.ts
export function initEngine(context: IScriptContext) {
// context.network.request(...)
// context.store.getFieldValue(...)
}
```
**2. Event Injection (Material Layer)**
Widgets use `inject` to communicate with the engine, without importing it.
```typescript
// packages/widget-pc/src/hooks/useCompEvent.ts
const bus = inject(USER_SCRIPT_EVENT_BUS_KEY);
bus.emit("CLIENT_EVENT", payload);
```