mcpField
M
migrate-lovable

migrate-lovable

github.com/stahura开发24204 次安装26 周前更新
代码仓库

关于 migrate-lovable

这是一份将 Lovable 或 v0 生成的应用调整为符合 Domo 客户端 React 与静态文件要求的指南。它帮助开发者识别服务端代码并按步骤手动迁移,不会自动转换应用。

主要功能

  1. 01识别 SSR 代码和 API 路由
  2. 02用 Domo API 替换后端数据获取
  3. 03调整路由与 Vite 配置
  4. 04移除 Lovable 专用依赖
  5. 05准备清单、缩略图和发布文件

适用场景

  1. 01检查生成应用与 Domo 的不兼容项
  2. 02将原型移植到 Domo 客户端架构
  3. 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-config
  • playwright-fixture.ts — 重新导出 Lovable 测试夹具
  • bun.lock / bun.lockb — Lovable 使用 Bun;统一使用 npm
  • App.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>;
}

评论

支持 Markdown