"添加前端模板和运行代码模块"

This commit is contained in:
Codex
2026-06-01 13:43:09 +08:00
parent 24045274ad
commit 8092c4b1f8
587 changed files with 99761 additions and 0 deletions

View File

@@ -0,0 +1,627 @@
# Vite Plugin Design Mode
一个为 AppDev 启用设计模式功能的 Vite 插件,为 React 和 Vue 3 项目提供源码映射与可视化编辑能力(不支持 Vue 2
## 特性
- **源码映射**: 在编译时自动向DOM元素注入源码位置信息使用紧凑的 `data-xagi-info` JSON 属性)
- **可视化编辑**: 提供直观的设计模式UI支持实时样式编辑
- **双击编辑**: 双击静态文本元素即可进入编辑模式,实时预览并自动保存到源码
- **静态内容检测**: 智能识别纯静态文本(无变量、表达式或子元素),只有静态内容才能直接编辑
- **列表项同步**: 编辑列表项时自动同步所有相关实例(内容或样式)
- **组件识别**: 识别组件名称、导入路径,区分组件使用位置和定义位置
- **Vue SFC 支持**: 支持 `.vue` 文件模板注入和 AST 安全回写class/text
- **实时修改**: 支持实时编辑样式和内容,并自动持久化到源码文件
- **Tailwind CSS集成**: 内置Tailwind CSS预设提供快速样式编辑
- **桥接通信**: 提供消息桥接机制,支持与外部工具和设计系统集成(支持 iframe 模式)
- **开发服务器集成**: 无缝集成Vite开发服务器支持热重载
- **零配置**: 开箱即用,无需复杂配置即可开始使用
## 框架支持矩阵
- React + Vite支持自动识别或 `framework: 'react'`
- Vue 3 + Vite支持自动识别或 `framework: 'vue'`
- Vue 2 + Vite不支持启动时会直接报错避免出现部分可用的隐性问题
## Installation
### 一键安装(推荐)
使用 CLI 工具一键配置插件:
```bash
npx @xagi/vite-plugin-design-mode install
# 或
pnpm dlx @xagi/vite-plugin-design-mode install
```
这个命令会:
-`package.json``devDependencies` 中添加插件依赖
- 自动在 `vite.config.ts/js/mjs` 中添加插件配置
- 使用默认配置,无需手动传参
CLI 适用前提:
- 项目需为 Vite 项目(`package.json` 中存在 `vite`
- 项目需使用 React 或 Vue 3`package.json` 中存在 `react`,或 `vue@3.x`
**注意:** CLI 只会在配置文件中添加配置,不会执行包管理器安装命令。配置完成后,请手动运行包管理器安装命令来安装依赖:
```bash
pnpm install
# 或
npm install
# 或
yarn install
```
### 一键卸载
使用 CLI 工具一键卸载插件并清理配置:
```bash
npx @xagi/vite-plugin-design-mode uninstall
# 或
pnpm dlx @xagi/vite-plugin-design-mode uninstall
```
这个命令会:
-`package.json` 中移除插件依赖
-`vite.config.ts/js/mjs` 中移除 import 和插件配置
- 自动清理所有相关配置
**注意:** CLI 只会在配置文件中移除配置,不会执行包管理器卸载命令。配置清理完成后,请手动运行包管理器卸载命令来移除依赖:
```bash
pnpm remove @xagi/vite-plugin-design-mode
# 或
npm uninstall @xagi/vite-plugin-design-mode
# 或
yarn remove @xagi/vite-plugin-design-mode
```
### 手动安装
如果需要手动安装:
```bash
npm install @xagi/vite-plugin-design-mode --save-dev
# or
yarn add @xagi/vite-plugin-design-mode --dev
# or
pnpm add @xagi/vite-plugin-design-mode -D
```
### 预发布 / XAGI 集成(推荐)
`1.1.x` 预发布会频繁发 **`1.1.0-beta.N`**registry 上历史 beta 会自然变多。**模板、宿主应用、内部文档请不要写死某个 `beta.N`**,否则每发一版就要改依赖。
集成时请**统一跟 `next` dist-tag**(始终对应当前灰度线):
```bash
pnpm add @xagi/vite-plugin-design-mode@next -D
# 若直接依赖 client 包(少见),同样使用 @next
# pnpm add @xagi/design-mode-client-vue@next -D
```
`package.json` 里可写 **`"^1.1.0-0"`**(接受 `1.1.0` 线下任意预发版本)并定期 `pnpm update`;或在文档与 CI 中约定:**安装/升级一律执行 `pnpm add @xagi/vite-plugin-design-mode@next -D`**,由 lockfile 固定实际解析版本。
稳定正式版发布后仍从 **`latest`** 安装即可(与上面预发布通道互不干扰)。
## 版本发布与 Tag 策略
为避免预发布版本影响生产用户,仓库采用以下 npm dist-tag 规则:
- `latest`:仅用于稳定正式版(如 `1.0.37``1.1.0`
- `next`**集成方应使用的预发布通道**;标签指向当前推荐的 `1.1.0-beta.*`(或其它预发 semver版本号会递增**请勿在对外文档中要求用户锁定某一枚 `beta.N`**
- `beta`:可选的额外 dist-tag历史或兼容新集成优先跟 `next`
### 多包发布 SOP推荐
发布采用统一版本策略,以下 4 个包必须同版本:
- `@xagi/design-mode-shared`
- `@xagi/design-mode-client-react`
- `@xagi/design-mode-client-vue`
- `@xagi/vite-plugin-design-mode`
```bash
# 1) 切换 npm 官方源(强烈建议每次发布前显式执行)
nrm use npm
# 2) 如需升级版本,一次性同步全部包版本和内部依赖(版本号按需替换)
pnpm run release:version:sync -- 1.1.0-beta.12
# 3) 一键发布 next预检 -> 构建 -> 按依赖顺序发布 -> 发布后校验)
pnpm run release:next
# 4) 一键发布 beta与 next 同流程,但写入 beta tag
pnpm run release:beta
# 5) 发布前演练(不真正 publish
pnpm run release:next:dry-run
pnpm run release:beta:dry-run
```
其中 `release:next` / `release:beta` 都会自动执行以下步骤:
1. `release:preflight`:校验 registry、版本一致性、禁止 `workspace:*` 泄露到发布包
2. `release:build`:构建所有包
3. `release:publish:*`:按依赖顺序发布(`shared -> react/vue并发 -> plugin`
4. `release:verify:*`:校验对应 dist-tag`next``beta`)及目标版本可见性;`verify:next` 对 registry 传播做了**有限次重试**(可用环境变量 `VERIFY_NEXT_MAX_TRIES``VERIFY_NEXT_SLEEP_SECS` 调整)
### 常见问题与修复
- 报错 `ERR_PNPM_WORKSPACE_PKG_NOT_FOUND`
原因:发布包中包含 `workspace:*` 依赖。
处理:运行 `release:preflight` 找出问题并改成明确版本号。
- `next` tag 未指向本次版本
处理:
```bash
npm dist-tag add @xagi/vite-plugin-design-mode@1.1.0-beta.5 next
```
## Basic Usage
使用一键安装后,插件已自动配置,`vite.config.ts` 中会包含:
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import appdevDesignMode from '@xagi/vite-plugin-design-mode';
export default defineConfig({
plugins: [
react(),
appdevDesignMode() // 使用默认配置,无需传参
]
});
```
**默认配置说明:**
- `enabled: true` - 启用插件
- `enableInProduction: false` - 仅在开发环境生效,生产构建时自动禁用
- `verbose: true` - 启用详细日志
- `attributePrefix: 'data-xagi'` - 源码映射属性的前缀
- `include: ['src/**/*.{ts,js,tsx,jsx,vue}']` - 处理 src 目录下的 TypeScript/JavaScript/TSX/JSX/Vue 文件
- `exclude: ['node_modules', 'dist']` - 排除指定目录
- `enableBackup: false` - 是否启用备份功能
- `enableHistory: false` - 是否启用历史记录功能
- `framework: 'auto'` - 自动识别 React / Vue 3可显式设置 `react``vue`
## Advanced Usage
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import appdevDesignMode from '@xagi/vite-plugin-design-mode';
export default defineConfig({
plugins: [
react(),
appdevDesignMode({
enabled: true,
enableInProduction: false,
attributePrefix: 'data-appdev',
verbose: true,
exclude: ['node_modules', '.git'],
include: ['**/*.{js,jsx,ts,tsx}']
})
]
});
```
## Vue 3 使用说明
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import appdevDesignMode from '@xagi/vite-plugin-design-mode';
export default defineConfig({
plugins: [
vue(),
appdevDesignMode({
framework: 'vue',
}),
],
});
```
- `framework: 'vue'` 模式下不会注入 React 运行时 UI 脚本,这是预期行为。
- Vue 当前支持模板元素的 `class` 与静态文本回写,复杂动态表达式会被保护性拒绝。
- 如检测到 Vue 2`@vitejs/plugin-vue2`),插件会在启动时抛错并提示升级到 Vue 3。
## 工作原理
1. **编译时转换**: 插件在编译时按框架选择转换链路
- React: 使用 Babel AST 转换 JSX/TSX/JS 文件
- Vue: 使用 `@vue/compiler-sfc` + `@vue/compiler-dom` 解析并转换 `.vue` 模板
2. **抽象语法树分析**: 基于 AST 识别可编辑元素与源码位置信息
- React: 追踪 ImportDeclaration 以解析组件定义和导入路径,并识别 UI 组件components/ui
- React: 静态分析确定内容是否为纯静态文本(`isStaticContent`
- Vue: 在模板 AST 中定位元素节点,进行注入并用于后续 AST 安全回写
3. **源码映射数据注入**: 将源码位置信息作为紧凑的`data-*`属性(默认前缀 `data-xagi`注入到DOM元素
- 主要信息存储在 `data-xagi-info` JSON 属性中(减少 DOM 体积)
- 添加 `data-xagi-element-id` 用于唯一标识和列表项同步
- 添加 `data-xagi-static-content` 标记可编辑的静态内容
4. **虚拟模块加载**: 通过Vite虚拟模块机制动态加载客户端代码
5. **运行时通信**: 设计模式UI通过桥接系统与外部工具通信支持实时编辑
- 支持 iframe 模式,通过 `postMessage` 与父窗口通信
- 支持元素选择、样式更新、内容更新等消息类型
6. **源码持久化**: 修改的样式和内容通过API端点实时写入源码文件
- 使用智能文本替换算法,基于行/列信息安全修改源码
- 支持样式className、内容innerText、属性更新
7. **列表项同步**: 使用 `element-id` 识别相关列表项,编辑一个实例自动同步到所有实例
8. **批量更新**: 支持批量更新多个元素,通过防抖机制优化性能
9. **备份与历史**: 可选启用备份和历史记录功能,支持撤销操作
## API 端点
插件提供以下API端点
### 基础端点
- `GET /__appdev_design_mode/get-source?elementId=xxx` - 获取指定元素的源码信息和文件内容(增强版,包含更多元数据)
- `POST /__appdev_design_mode/modify-source` - 修改源码文件中的样式或内容(兼容旧版本)
- `POST /__appdev_design_mode/update` - 统一更新接口,支持样式、内容、属性更新
- `GET /__appdev_design_mode/health` - 健康检查,返回插件运行状态
### 批量操作端点
- `POST /__appdev_design_mode/batch-update` - 批量更新多个元素的源码(需要 `enableHistory: true` 以保存会话)
- `GET /__appdev_design_mode/batch-update-status?batchId=xxx` - 查询批量更新会话状态(需要 `enableHistory: true`
### 历史记录端点(需要 `enableHistory: true`
- `GET /__appdev_design_mode/get-history` - 获取更新历史记录
- `POST /__appdev_design_mode/undo` - 撤销操作(需要 `enableBackup: true`
- `POST /__appdev_design_mode/redo` - 重做操作(暂未实现)
### 验证端点
- `POST /__appdev_design_mode/validate-update` - 验证更新请求的有效性
## 生成属性
插件处理的元素将具有以下属性(默认前缀为 `data-xagi`,可通过 `attributePrefix` 配置项自定义):
### 核心属性(实际注入)
- **`{prefix}-info`**: 包含完整源码映射信息的 JSON 字符串,包含以下字段:
- `fileName`: 源码文件路径
- `lineNumber`: 源码行号
- `columnNumber`: 源码列号
- `elementType`: 元素类型(标签名)
- `componentName`: 组件名称(如果适用)
- `functionName`: 函数名称(如果适用)
- `elementId`: 唯一元素标识符
- `importPath`: 组件导入路径(用于区分组件使用位置和定义位置)
- `isUIComponent`: 是否是 UI 组件components/ui 目录下的组件)
- **`{prefix}-element-id`**: 唯一元素标识符,格式为 `文件路径:行号:列号_标签名#ID`(如果有 id 属性)或 `文件路径:行号:列号_标签名`(如果没有 id 属性)。用于列表项同步和元素识别。
- **`{prefix}-position`**: 位置信息,格式为 `行号:列号`(简化版位置信息)
- **`{prefix}-static-content`**: 标记元素是否包含纯静态内容(值为 `'true'`),用于判断元素是否可以直接编辑。只有包含纯静态文本(无变量、表达式或子元素)的元素才会被标记。
- **`{prefix}-static-class`**: 标记 className 是否为纯静态字符串(值为 `'true'`),用于判断样式是否可以直接编辑。
- **`{prefix}-children-source`**: 子元素的源码位置信息,格式为 `文件路径:行号:列号`(用于透传组件追踪静态文本子元素的来源位置)
### 优化说明
为了减少 DOM 体积,插件采用了紧凑的属性策略:
- **所有主要信息都包含在 `{prefix}-info` 中**,不再单独注入 `{prefix}-file``{prefix}-line``{prefix}-column``{prefix}-component``{prefix}-function``{prefix}-import` 等属性
- 这些信息可以通过解析 `{prefix}-info` JSON 字符串获取
**注意**:这些属性使用可配置的前缀,默认值为 `data-xagi`。通过设置 `attributePrefix` 选项,可以避免与用户自定义的 `data-*` 属性冲突。例如,设置 `attributePrefix: 'data-appdev'` 后,属性名将变为 `data-appdev-info``data-appdev-element-id``data-appdev-static-content` 等。
## 浏览器集成
### 直接DOM访问
在浏览器开发者工具或外部应用中:
```javascript
// 获取元素源码信息(注意:默认前缀已改为 data-xagi
const element = document.querySelector('.my-element');
// 从全局配置获取前缀,或使用默认值 'data-xagi'
const prefix = window.__APPDEV_DESIGN_MODE_CONFIG__?.attributePrefix || 'data-xagi';
const sourceInfo = element.getAttribute(`${prefix}-info`);
const sourceData = JSON.parse(sourceInfo);
console.log(sourceData);
// {
// fileName: 'src/App.tsx',
// lineNumber: 10,
// columnNumber: 5,
// elementType: 'div',
// componentName: 'App',
// functionName: 'App',
// elementId: 'src/App.tsx:10:5_div',
// importPath: undefined, // 如果是组件,会显示导入路径
// isUIComponent: false // 是否是 UI 组件
// }
// 检查元素是否可以直接编辑(静态内容)
const isEditable = element.getAttribute(`${prefix}-static-content`) === 'true';
if (isEditable) {
// 双击元素即可编辑
element.addEventListener('dblclick', () => {
element.contentEditable = 'true';
});
}
```
### 桥接通信
使用内置桥接系统与设计模式UI交互
```javascript
// 监听元素选择变化
window.addEventListener('message', (event) => {
const { type, payload } = event.data;
if (type === 'SELECTION_CHANGED') {
console.log('选中的元素:', payload);
// payload 包含: tagName, id, className, innerText, source
}
});
// 发送样式更新命令
window.parent.postMessage({
type: 'UPDATE_STYLE',
payload: {
newClass: 'bg-blue-500 text-white p-4 rounded-lg'
}
}, '*');
// 发送内容更新命令
window.parent.postMessage({
type: 'UPDATE_CONTENT',
payload: {
newContent: '更新后的文本内容'
}
}, '*');
```
## 配置选项
| 选项 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `enabled` | boolean | `true` | 是否启用设计模式插件 |
| `enableInProduction` | boolean | `false` | 是否在生产环境启用通常保持false |
| `attributePrefix` | string | `'data-xagi'` | 自定义源码映射属性的前缀 |
| `verbose` | boolean | `true` | 是否启用详细日志输出,便于调试 |
| `exclude` | string[] | `['node_modules', 'dist']` | 排除处理的文件模式和目录 |
| `include` | string[] | `['src/**/*.{ts,js,tsx,jsx}']` | 包含处理的文件模式支持glob语法 |
| `enableBackup` | boolean | `false` | 是否启用备份功能,启用后会在修改源码前创建备份文件 |
| `enableHistory` | boolean | `false` | 是否启用历史记录功能,启用后会保存批量更新会话和历史记录 |
### 配置示例
```typescript
// vite.config.ts
export default defineConfig({
plugins: [
react(),
appdevDesignMode({
enabled: true,
enableInProduction: false,
attributePrefix: 'data-appdev',
verbose: true,
exclude: ['node_modules', '.git', 'dist'],
include: ['src/**/*.{ts,js,tsx,jsx}', 'pages/**/*.{ts,js,tsx,jsx}'],
enableBackup: true, // 启用备份功能
enableHistory: true // 启用历史记录功能
})
]
});
```
## 使用场景
### 1. 设计与开发协作
- 设计师可以直接在浏览器中调整组件样式
- 实时预览设计效果,所见即所得
- 自动生成样式代码,无需手动编写
### 2. 组件库开发
- 快速迭代组件样式和变体
- 可视化调整组件参数和样式
- 生成一致的设计语言
### 3. 原型开发
- 快速构建和调整页面布局
- 实时验证设计想法
- 加速从原型到代码的转换
### 4. 团队协作
- 统一设计系统和代码规范
- 减少设计师和开发者的沟通成本
- 提高开发效率和代码质量
## Tailwind CSS 预设
插件内置了常用的Tailwind CSS类预设
### 背景颜色预设
- `bg-white` - 白色背景
- `bg-slate-50` - 浅灰色背景
- `bg-blue-50` - 浅蓝色背景
- `bg-blue-100` - 中浅蓝色背景
- `bg-blue-600` - 深蓝色背景
- `bg-red-50` - 浅红色背景
- `bg-green-50` - 浅绿色背景
### 文字颜色预设
- `text-slate-900` - 深灰色文字
- `text-slate-600` - 中灰色文字
- `text-blue-600` - 蓝色文字
- `text-white` - 白色文字
- `text-red-600` - 红色文字
### 间距预设
- `p-0` - 无内边距
- `p-2` - 小内边距
- `p-4` - 中等内边距
- `p-6` - 大内边距
- `p-8` - 特大内边距
- `p-12` - 超大内边距
### 圆角预设
- `rounded-none` - 无圆角
- `rounded-sm` - 小圆角
- `rounded-md` - 中等圆角
- `rounded-lg` - 大圆角
- `rounded-full` - 完全圆角
## 设计模式UI使用指南
### 启动设计模式
1. 在页面右下角找到设计模式开关
2. 点击开关启用设计模式
3. 开始选择和编辑页面元素
### 编辑元素样式
1. 点击页面中的任意元素
2. 在右侧编辑面板中选择预设样式
3. 实时预览样式效果
4. 修改会自动保存到源码文件
5. 对于列表项,修改一个实例会自动同步到所有相关实例
### 编辑元素内容
1. **双击**包含静态文本的元素(只有标记了 `data-xagi-static-content="true"` 的元素才能编辑)
2. 进入 `contentEditable` 模式,直接编辑文本
3. 失去焦点时自动保存到源码文件
4. 对于列表项,编辑一个实例会自动同步到所有相关实例
### 重置修改
- 点击“重置所有修改”按钮撤销所有更改
- 页面将重新加载并恢复原始状态
- 如果启用了备份功能(`enableBackup: true`),可以使用撤销功能恢复之前的版本
- 如果启用了历史记录功能(`enableHistory: true`),可以查看和恢复历史更新会话
## 故障排除
### 常见问题
**Q: 设计模式UI没有显示**
A: 检查插件是否正确配置,确保在开发模式下运行
**Q: 点击元素没有反应**
A: 确认已经启用设计模式,检查浏览器控制台是否有错误信息
**Q: 样式修改没有保存**
A: 检查文件权限,确保有写入权限,或者检查开发服务器状态
**Q: 源码映射不准确**
A: 检查是否正确配置了include模式确保源文件被正确处理
### 调试技巧
1. 启用verbose模式查看详细日志
2. 检查浏览器开发者工具的网络面板确认API请求状态
3. 查看元素是否正确生成了源码映射属性
4. 使用健康检查端点验证插件运行状态
```bash
# 检查插件状态
curl http://localhost:3000/__appdev_design_mode/health
```
## 开发指南
### 本地开发
```bash
# 克隆项目
git clone <repository-url>
cd vite-plugin-design-mode
# 安装依赖
npm install
# 运行示例
cd examples/advanced
npm install
npm run dev
```
### 自定义预设
如需自定义样式预设,可以修改客户端配置:
```typescript
// 在 DesignModeUI.tsx 中自定义预设
const CUSTOM_PRESETS = {
bgColors: [
{ label: 'Primary', value: 'bg-blue-600' },
{ label: 'Secondary', value: 'bg-gray-600' },
// 添加更多自定义颜色
]
};
```
## 贡献指南
欢迎提交Issue和Pull Request来改进这个插件
### 开发流程
1. Fork项目
2. 创建功能分支
3. 提交更改
4. 创建Pull Request
### 代码规范
- 使用TypeScript
- 遵循ESLint规则
- 添加适当的测试
- 更新相关文档
## 更新日志
完整变更记录见 [`CHANGELOG.md`](./CHANGELOG.md)。
### v1.1.0-beta.5
- 修复 npm 发布产物中的 workspace 依赖协议问题,确保外部使用 pnpm/npm 安装可正常解析依赖
### v1.1.0-beta.4
- 修复插件发布后客户端运行时入口解析,优先从安装包解析 React/Vue runtime
- 增加路径安全校验,避免通过路径前缀绕过项目根目录限制
- 完成多包迁移后的测试回归修复,测试全量通过
### v1.1.0-beta.3
- 完成项目向 `packages/*` 多包结构迁移
- 保留并迁移 CLI 到 plugin 包内,发布产物包含 CLI
- 调整 examples/test 引用路径,移除根 `src` 目录实现
### v1.1.0-beta.2
- 新增 React/Vue 3 动态识别支持(`framework: 'auto'`
- CLI 支持在 Vue 3 + Vite 项目安装
- 检测到 Vue 2`@vitejs/plugin-vue2`)时快速失败并给出升级提示
- 发布策略调整:`latest` 仅稳定版,预发布使用 `beta/next`
### v1.0.36
- 更新默认属性前缀为 `data-xagi`
- 新增批量更新功能(`/batch-update` 端点)
- 新增历史记录功能(`enableHistory` 配置项)
- 新增备份功能(`enableBackup` 配置项)
- 新增撤销/重做功能(需要启用备份和历史记录)
- 增强 `/get-source` 端点,返回更多元数据
- 新增 `/validate-update` 端点用于验证更新请求
- 支持 TypeScript/JavaScript/TSX/JSX 文件处理
- 优化默认文件包含模式,支持更多文件类型
- 改进CLI工具支持一键安装和卸载
### v1.0.0
- 初始版本发布
- 实现基本的源码映射功能
- 添加可视化设计模式UI
- 支持实时样式编辑和源码修改
- 集成Tailwind CSS预设
## License
MIT