关于 migrate-lovable
这是一份将 Lovable 或 v0 生成的应用调整为符合 Domo 客户端 React 与静态文件要求的指南。它帮助开发者识别服务端代码并按步骤手动迁移,不会自动转换应用。
主要功能
- 01识别 SSR 代码和 API 路由
- 02用 Domo API 替换后端数据获取
- 03调整路由与 Vite 配置
- 04移除 Lovable 专用依赖
- 05准备清单、缩略图和发布文件
适用场景
- 01检查生成应用与 Domo 的不兼容项
- 02将原型移植到 Domo 客户端架构
- 03准备 Domo 发布所需的构建产物
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ stahura/ domo-ai-vibe-rules --skill migrate-lovable安装后在 Claude Code 中输入/migrate-lovable确认已加载。
详细介绍
将 Lovable 迁移到 Domo
将生成的应用(Lovable/v0)转换为 Domo
许多开发者使用 Lovable、v0 或类似的基于大模型的生成器等 AI 工具来创建应用原型。然而,这些工具通常生成带有服务端渲染(SSR)的应用,这些应用与 Domo 仅客户端架构不兼容。
转换挑战
生成的应用通常包含:
- 服务端渲染(Next.js、Remix、SvelteKit、Nuxt)
- API 路由(
pages/api/或app/api/目录) - 服务端数据获取(
getServerSideProps、loader 等) - 框架特定的路由(Next.js App Router、Remix routes)
Domo 应用必须:
- 纯客户端 React - 无服务端渲染
- 基于静态文件 - Domo 仅提供静态文件
- 集成 Domo API - 使用
domo.get()、Query、AppDBClient等,而不是后端端点
推荐的转换模式
DA CLI 不是转换工具 - 它不会自动转换应用。不过,你可以将其用作参考结构和起点。
步骤 1:生成参考结构
# Create a fresh Domo app to use as reference
da new my-converted-app
cd my-converted-app
# This gives you the correct structure to compare against
步骤 2:检测并移除 SSR 代码
检查 SSR 标志:
getServerSideProps、getStaticProps(Next.js)loader、action函数(Remix)+page.server.js、+server.js(SvelteKit)pages/api/或app/api/目录- 服务端
process.env使用 - 组件中的数据库连接
操作: 移除所有服务端代码。Domo 应用完全在浏览器中运行。
步骤 3:替换数据获取
之前(Next.js 示例):
// ❌ Server-side data fetching
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data } };
}
// ❌ API route
// pages/api/users.ts
export default async function handler(req, res) {
const users = await db.users.findMany();
res.json(users);
}
之后(Domo):
// ✅ Client-side with Domo APIs
import domo from 'ryuu.js';
import Query from '@domoinc/query';
import { AppDBClient } from '@domoinc/toolkit';
// Fetch from Domo dataset
const data = await domo.get('/data/v1/sales');
// Or use Query API for filtered/aggregated data
const summary = await new Query()
.select(['region', 'sales'])
.groupBy('region', { sales: 'sum' })
.fetch('sales-dataset');
// Or use AppDB for document storage
const tasksClient = new AppDBClient.DocumentsClient('Tasks');
const tasks = await tasksClient.get();
步骤 4:更新路由
之前(Next.js):
// ❌ Next.js routing
import Link from 'next/link';
<Link href="/dashboard">Dashboard</Link>
之后(Domo):
// ✅ HashRouter for client-side routing
import { HashRouter, Routes, Route } from 'react-router-dom';
import domo from 'ryuu.js';
// Use HashRouter (works without server rewrites)
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</HashRouter>
// For Domo navigation, use domo.navigate()
domo.navigate('/page/123456789');
步骤 5:修复构建配置
之前(Next.js):
// next.config.js
module.exports = {
// Next.js config
}
之后(Domo - Vite):
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
base: './', // CRITICAL: Relative paths for Domo
plugins: [react()],
});
移除 Lovable 特定的 Vite 插件,例如 lovable-tagger:
// ❌ Remove this
import { componentTagger } from "lovable-tagger";
plugins: [react(), mode === "development" && componentTagger()].filter(Boolean),
// ✅ Replace with
plugins: [react()],
步骤 6:移除 Lovable 特定的依赖
Lovable/v0 应用包含必须移除的工具:
要移除的依赖:
next-themes— SSR 主题提供器;将useTheme()替换为硬编码的主题字符串(例如"light")lovable-tagger— Lovable 仅用于开发的组件标记工具
要删除的文件:
playwright.config.ts— 使用lovable-agent-playwright-configplaywright-fixture.ts— 重新导出 Lovable 测试夹具bun.lock/bun.lockb— Lovable 使用 Bun;统一使用 npmApp.css— 在生成的应用中通常未使用(请先确认)
修复 Sonner toaster 中 next-themes 的使用:
// ❌ Before (depends on next-themes)
import { useTheme } from "next-themes";
const { theme = "system" } = useTheme();
<Sonner theme={theme as ToasterProps["theme"]} />
// ✅ After (hardcoded, no SSR dependency)
<Sonner theme="light" />
步骤 7:创建 Domo 清单
Domo 要求在发布目录中提供 manifest.json:
{
"name": "My App Name",
"version": "1.0.0",
"size": {
"width": 10,
"height": 10
},
"mapping": [],
"fileName": "index.html",
"id": "",
"proxyId": ""
}
name— Domo 中的显示名称size— 卡片尺寸(Domo 仪表板网格中的列 x 行)mapping— 数据集映射(如果使用模拟数据或 AppDB,则为空数组)fileName— 入口 HTML 文件(始终为index.html)id— 留空;domo publish在首次发布时填充此字段
步骤 8:创建缩略图
必需 — 没有它 domo publish 将会失败。
在项目根目录放置一个名为 thumbnail.png 的 300x300 PNG。它用于 Domo Appstore 和移动应用。
# Generate a simple thumbnail programmatically (Python + Pillow)
python3 -c "
from PIL import Image, ImageDraw, ImageFont
img = Image.new('RGB', (300, 300), color=(15, 23, 42))
draw = ImageDraw.Draw(img)
draw.rectangle([0, 0, 300, 6], fill=(99, 102, 241))
try:
font = ImageFont.truetype('/System/Library/Fonts/Helvetica.ttc', 72)
except: font = ImageFont.load_default()
bbox = draw.textbbox((0, 0), 'EF', font=font)
draw.text(((300-(bbox[2]-bbox[0]))/2, 110), 'EF', fill='white', font=font)
img.save('thumbnail.png')
"
或使用任何 300x300 的 PNG 图片。
步骤 9:从 dist/ 目录发布
关键 — 从项目根目录运行 domo publish 会导致 400: Unable to parse form content 错误,因为 CLI 会尝试上传 node_modules、源文件和配置文件,从而产生过大的载荷。
解决方案: 将 manifest.json 和 thumbnail.png 复制到 dist/,然后从那里发布:
# Manual publish
npm run build
cp manifest.json thumbnail.png dist/
cd dist && domo publish
自动化它,通过更新 package.json 脚本:
{
"scripts": {
"build": "vite build && cp manifest.json thumbnail.png dist/",
"publish": "npm run build && cd dist && domo publish"
}
}
这确保只上传构建后的资源、清单和缩略图。
步骤 10:移植组件
使用 DA CLI 生成具有正确结构的新组件,然后移植逻辑:
# Generate component structure
da generate component SalesChart
# Copy component logic from generated app
# Replace data fetching with Domo APIs
# Update imports and dependencies
DA CLI 能提供哪些帮助
✅ 参考结构 - 展示正确的 Domo 应用组织方式
✅ 组件生成 - 创建结构正确的组件
✅ 模式示例 - 演示 Domo 约定
✅ 从头开始 - 如果转换过于复杂,可以新建项目并移植逻辑
DA CLI 不做什么
❌ 不自动转换 - 不会将 SSR 转换为客户端渲染
❌ 没有迁移向导 - 没有逐步转换工具
❌ 不转换代码 - 不会重写特定框架的代码
❌ 不迁移 API - 不会自动替换后端调用
完整转换清单
- 检测并移除所有 SSR 代码
- 移除 API 路由(
pages/api/、app/api/) - 将对后端的
fetch()调用替换为 Domo API - 将路由从
BrowserRouter更新为HashRouter - 使用
base: './'配置 Vite - 从 Vite 配置中移除 Lovable 专用插件(
lovable-tagger) - 移除
next-themes,并将useTheme()替换为硬编码主题 - 删除 Lovable 文件(
playwright.config.ts、playwright-fixture.ts、bun.lock*) - 添加
ryuu.js依赖以集成 Domo API - 替换环境变量(改用 Domo API)
- 更新导入(移除 Next.js/Remix/Lovable 专用导入)
- 创建包含应用名称、版本和大小的
manifest.json - 在项目根目录创建
thumbnail.png(300x300 PNG) - 更新构建脚本,将
manifest.json+thumbnail.png复制到dist/ - 测试所有数据获取在 Domo API 下正常工作
- 验证应用可在本地构建并运行(
npm run build) - 从
dist/目录发布(cd dist && domo publish)
示例:转换一个简单仪表板
原始版本(Lovable/Next.js):
// pages/dashboard.tsx
export async function getServerSideProps() {
const sales = await fetch('http://api.company.com/sales').then(r => r.json());
return { props: { sales } };
}
export default function Dashboard({ sales }) {
return <div>{/* Render sales data */}</div>;
}
转换后(Domo):
// src/components/Dashboard/Dashboard.tsx
import { useEffect, useState } from 'react';
import domo from 'ryuu.js';
export default function Dashboard() {
const [sales, setSales] = useState([]);
useEffect(() => {
// Fetch from Domo dataset instead of backend
domo.get('/data/v1/sales').then(setSales);
}, []);
return <div>{/* Render sales data */}</div>;
}