React 导出到 Figma Make
概述
本技能将帮助你把任意 React 组件或应用转换为符合 Figma Make 项目规范的标准结构。转换完成后,项目将具备:
- Figma Make 可编辑性:可在 Figma Make 平台中打开、编辑和迭代
.fig导出能力:生成可下载的.fig文件- 双入口架构:同时支持独立运行和 Figma Make 导出
- 设计 Token 保留:保持原始设计系统的 CSS 变量和主题定义
- 资产完整性:包含
meta.json、ai_chat.json、images/等 Figma Make 要求的元文件
本技能产出一个完整的 Figma Make 兼容项目目录,而非单个组件文件。
何时使用
- 你有一个现成的 React 项目,希望导入 Figma Make 进行可视化编辑
- 你需要从 React 代码生成
.fig文件用于设计交付 - 你希望在 Figma Make 和代码编辑器之间双向协作
- 你有一个 V0 / AI Studio / 自建 React 项目,想把它纳入 Figma Make 生态
环境要求
本技能分为两部分:
- 项目结构转换(通用):将 React 项目改造为 Figma Make 目录规范 — 任何环境均可执行
- canvas.fig 生成与验证:本技能内置了相关的操作脚本,位于技能自身的目录下:
- scripts/canvas-fig-sync.mjs:canvas.fig 回写与检查工具 - assets/empty-canvas.fig:空白 canvas 模板 (运行脚本前,请先在技能的 scripts 目录下执行 npm install 安装依赖 pako 和 kiwi-schema。)
如果有额外的页面渲染验收脚本,也可以在此阶段执行。
引用文件
本技能附带以下参考文件,在转换特定技术领域时按需查阅:
references/project-structure.md:Figma Make 项目的完整目录结构和文件职责说明references/meta-json-spec.md:meta.json的完整字段定义和示例references/style-migration.md:从各种 CSS 方案迁移到 Figma Make 样式体系的指南
转换工作流程
第 1 步:分析源项目
分析目标 React 项目的以下方面:
- 框架识别:
- 纯 React(Vite / CRA / 自定义) - Next.js(需要移除 SSR、"use client"、next/image 等) - AI Studio(Import Map + CDN 模式) - 其他元框架
- 入口结构:
- 主应用组件在哪里(通常是 App.tsx 或 page.tsx) - 挂载入口在哪里(main.tsx / index.tsx) - 是否有路由(多路由需收敛为单入口)
- 样式方案:
- Tailwind CSS(CDN / PostCSS / v4) - CSS Modules - Styled Components / Emotion - 纯 CSS / SCSS - CSS 变量 / 设计 Token
- 依赖分析:
- 核心依赖(React、ReactDOM — 外部化,不打包) - UI 框架(Ant Design、shadcn/ui、Radix 等 — 保留) - 图表库、动画库等 — 保留并确认兼容性 - 框架特定依赖(Next.js、Vercel — 移除)
- 静态资源盘点(对大型项目尤其重要):
- 图片:格式、数量、总大小、引用方式(import / public / CDN) - 字体:本地文件 vs CDN 引用 - 视频/音频等其他媒体 - SVG:是否作为 React 组件使用
输出一份转换清单,列出需要处理的各项转换任务。
第 2 步:创建 Figma Make 项目结构
在目标目录 <output-dir>/<page-name>/ 下创建以下固定结构:
<page-name>/
├── index.tsx # 项目主入口
├── style.css # 根入口样式(桥接层)
├── canvas.fig # Figma 二进制设计数据(第 5 步生成)
├── meta.json # 项目元数据
├── ai_chat.json # AI 聊天历史(可为空 {})
├── canvas.code-manifest.json # CODE_FILE 索引清单(第 5 步生成)
├── package.json # Vite 项目依赖声明
├── vite.config.ts # Vite 构建配置
├── index.html # Vite HTML 入口
├── images/ # 设计稿图片资源
└── src/
├── App.tsx # Figma Make 导出薄壳(导出入口)
├── main.tsx # Vite 挂载层
├── index.css # Figma Make 入口样式
├── components/ # 页面视觉与交互主体
├── pages/ # 多页面(如需要)
└── styles/
└── globals.css # 全局样式 / 设计 Token职责分层约束(这是验收约束,不是建议):
| 文件 | 职责 | 不应包含 |
|---|---|---|
index.tsx | 项目主入口 | 页面视觉实现 |
src/App.tsx | Figma 导出薄壳,复用共享组件 | 独立于根入口的业务逻辑 |
src/main.tsx | Vite 开发挂载,ReactDOM.createRoot | 业务代码 |
src/components/** | 页面视觉与交互的真实主体 | 入口适配逻辑 |
style.css | 根入口样式转发 | 大量业务样式 |
src/index.css | Figma 入口样式层 | 独立于 style.css 的独立样式 |
第 3 步:迁移和改造源代码
3.1 收敛入口
将源项目的所有页面逻辑收敛为两个薄入口 + 一套共享组件。
根目录 index.tsx(项目主入口):
/**
* 项目主入口
*/
import './style.css';
import React from 'react';
import AppContent from './src/components/AppContent';
export default function PageName() {
return <AppContent />;
}src/App.tsx(Figma Make 导出壳):
/**
* Figma Make 导出薄壳
* 复用 components/ 中的共享组件,保持与根目录 index.tsx 同步
*/
import React from 'react';
import AppContent from './components/AppContent';
export default function App() {
return <AppContent />;
}src/main.tsx(Vite 挂载层):
/**
* Vite 开发挂载层
* 仅用于 Figma Make 独立开发预览
*/
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);关键原则:
- 两个入口(
index.tsx和src/App.tsx)必须渲染相同的页面内容 - 页面真实视觉和交互主体应沉淀到
src/components/** - 若源项目有多页路由,收敛为单页面或选择核心页面
3.2 处理框架特定代码
根据源项目的框架类型,进行针对性清理:
Next.js 项目:
// ❌ 移除
"use client"
import { useRouter } from 'next/navigation'
import Image from 'next/image'
import Link from 'next/link'
import type { Metadata } from 'next'
// ✅ 替换
// 删除 "use client"
// 删除 useRouter,改用 useState 管理页面状态
<img> 替代 <Image>
<a> 替代 <Link>AI Studio 项目:
// ❌ 移除
// Import Map 依赖(CDN URL)
// index.html 中的 <script type="importmap">
// ✅ 替换
// CDN 导入改为 npm 包导入
// process.env.* 改为 import.meta.env.VITE_*通用清理:
// ❌ 移除
import { Analytics } from '@vercel/analytics/next'
// 所有 SSR 相关代码
// ✅ 保留
// React Hooks
// 第三方 UI 组件
// 样式文件导入3.3 处理路径别名
将所有非标准路径别名转换为相对路径:
// 源代码中的 @/ 别名
import { Button } from '@/components/ui/button'
// 转换为相对路径(基于文件位置)
import { Button } from './components/ui/button' // 从 src/App.tsx
import { Button } from '../components/ui/button' // 从 src/pages/xxx.tsx如果源项目使用 package@version 格式的导入(Figma Make 导出特征),改为裸包名:
// ❌
import { motion } from 'framer-motion@11.0.0'
// ✅
import { motion } from 'framer-motion'3.4 处理大型静态资源
React 项目通常包含大量图片、字体和其他二进制文件。转换时需要妥善处理这些资源:
图片资源迁移:
| 源项目引用方式 | 迁移策略 |
|---|---|
import logo from './assets/logo.png' | 保留在 src/assets/,import 路径不变 |
<img src="/images/hero.png"> (public 目录) | 复制到 images/,更新路径为 ./images/hero.png |
<img src="https://cdn.example.com/img.png"> (CDN) | 保留 CDN 链接不变 |
SVG 作为 React 组件 (import {ReactComponent as Icon}) | 保留在 src/components/ 或 src/assets/ |
CSS 中的 url('./bg.png') | 保持相对路径正确即可 |
images/ 目录规则:
- Figma Make 的
images/目录存放设计稿关联图片,通常以 hash 命名(如a3f2c1d.png) - 源项目的业务图片优先保留在
src/assets/,不必强制移到images/ - 只有从 Figma Make 导入时自带的
images/内容才需要保留原始 hash 名
字体文件:
- 本地字体文件放入
src/assets/fonts/ - 在
src/styles/globals.css中用@font-face引用 - Google Fonts 等 CDN 字体直接保留
@import url(...)链接
大文件注意事项:
canvas.fig是二进制文件(通常几百 KB 到几 MB),不能手动编辑,只能通过工具生成- 不要把源项目的
node_modules/、build/、.next/等目录复制到产物中 - 如果源项目的图片总量超过 50 张或 10 MB,考虑精简为核心页面所需的子集
3.5 迁移样式
目标:根入口 style.css 和导出入口 src/index.css 使用同一套样式来源。
style.css(根入口样式):
@import "tailwindcss";
/* 如果有 globals.css,通过 import 引入 */
@import "./src/styles/globals.css";src/index.css(Figma 导出样式):
@import "tailwindcss";
/* 保持与 style.css 一致的样式来源 */
@import "./styles/globals.css";src/styles/globals.css(主样式文件):
将源项目中的以下内容迁移到此文件:
- CSS 变量 / 设计 Token
@theme定义(Tailwind v4)- 全局基础样式
- 自定义字体引用
- 自定义动画定义
样式迁移策略(详细指南见 references/style-migration.md):
| 源样式方案 | 迁移方式 |
|---|---|
| Tailwind CSS v4 | 直接保留 @import "tailwindcss" + @theme |
| Tailwind CSS v3 | 迁移到 v4 语法,@theme inline 替代 @apply |
| CSS Modules | 合并到组件同级 CSS 文件,改用带前缀的普通类名 |
| Styled Components / Emotion | 提取为 CSS 类,移除 JS-in-CSS 依赖 |
| 纯 CSS / SCSS | 直接迁移,SCSS 编译为 CSS |
| CSS 变量 | 保留到 globals.css 的 :root 或 @theme 中 |
大型样式文件注意事项:
- Figma Make 导出的
src/index.css有时是 Tailwind 的完整编译产物(可达数万行),不要直接使用它作为最终样式 - 应以
src/styles/globals.css为主样式源,src/index.css仅做样式桥接
第 4 步:创建 Figma Make 元文件
4.1 meta.json
{
"client_meta": {
"background_color": { "r": 0.96, "g": 0.96, "b": 0.96, "a": 1 },
"thumbnail_size": { "width": 400, "height": 300 },
"render_coordinates": { "x": 0, "y": 0, "width": 1280, "height": 960 }
},
"file_name": "<项目显示名称>",
"developer_related_links": [],
"exported_at": "<ISO 8601 时间>"
}file_name:最终导出的.fig文件显示名称render_coordinates:页面视口尺寸,根据实际页面调整width和height(详见references/meta-json-spec.md)exported_at:使用当前 ISO 8601 时间(new Date().toISOString())
4.2 ai_chat.json
{}新建项目时为空对象即可。
4.3 package.json
{
"name": "<page-name>",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
},
"devDependencies": {
"vite": "^6.0.0",
"@vitejs/plugin-react": "^4.0.0",
"typescript": "^5.0.0"
}
}依赖规则:
- 排除:
react、react-dom、next、next-*、@vercel/*、next-themes - 保留:所有其他运行时依赖(UI 库、工具库、图标库等)
- 使用项目所用的包管理器安装依赖(npm / yarn / pnpm 均可)
4.4 vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': '/src'
}
}
});4.5 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><项目名称></title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>4.6 images/ 目录
创建空的 images/ 目录。此目录用于存放 Figma Make 设计稿关联的图片资源。
- 如果是从 Figma Make 导入的项目,保留
images/下已有的 hash 命名图片 - 源项目的业务图片建议保留在
src/assets/中,不必移入images/
第 5 步:生成 canvas.fig
运行本步骤前,请确保已经在技能包的scripts/目录下执行过npm install以安装依赖。
使用本技能自带的 canvas-fig-sync.mjs 脚本生成可导出的 .fig 文件。
以下命令假设你当前在终端中定位在目标项目根目录,且本技能的存放位置为 <skill-dir>:
首次生成(没有现有 canvas.fig):
# ① 从模板创建基础 canvas.fig
cp <skill-dir>/assets/empty-canvas.fig <output-dir>/<page-name>/canvas.fig
# ② 将源码回写到 canvas.fig
node <skill-dir>/scripts/canvas-fig-sync.mjs pack \
--fig <output-dir>/<page-name>/canvas.fig \
--from <output-dir>/<page-name> \
--prune-missing \
--sanitize-for-export
# ③ 生成 manifest
node <skill-dir>/scripts/canvas-fig-sync.mjs inspect \
--fig <output-dir>/<page-name>/canvas.fig \
--manifest <output-dir>/<page-name>/canvas.code-manifest.json参数说明:
<output-dir>:项目输出目录,根据你的项目约定选择(如src/prototypes、src/pages等)--prune-missing:裁掉磁盘上不存在的旧CODE_FILE节点--sanitize-for-export:清空旧聊天/历史缓存,重建importedCodeFiles
canvas.fig 关键特性:
- 二进制 ZIP 格式文件,内含 Figma 节点树和 CODE_FILE 节点
- 不可手动编辑,仅能通过
canvas-fig-sync.mjs的 pack / inspect / extract 命令操作 - 文件大小通常在几百 KB 到几 MB,取决于代码文件数量
- 每次页面内容变更后需要重新 pack,否则导出的
.fig会与当前页面不一致
第 6 步:验证清单
转换完成后,逐项检查:
结构验证:
- 项目目录符合固定结构(
index.tsx+src/App.tsx+src/main.tsx+src/components/) index.tsx顶部有职责注释src/App.tsx顶部有职责注释:"Figma Make 导出薄壳"src/main.tsx顶部有职责注释:"Vite 挂载层"- 两个入口渲染同一套
src/components/**中的共享组件
元文件验证:
meta.json存在,包含file_name、exported_at、client_metaai_chat.json存在(至少为{})package.json存在,不包含react/react-dom依赖vite.config.ts存在index.html存在images/目录存在
canvas.fig 验证:
canvas.fig存在canvas.code-manifest.json存在- inspect 命令可成功执行
样式验证:
style.css和src/index.css使用同一套样式来源- 不直接搬运 Tailwind 构建产物作为最终样式
依赖验证:
- 不依赖
@/或package@version别名才能运行 - 不残留 Next.js / Vercel 特定代码
- 所有必要依赖已安装
资源完整性验证:
- 所有图片引用路径正确(无 404 断链)
- 字体文件已复制或 CDN 链接可访问
- 不包含
node_modules/、build/、.next/等冗余目录
渲染验证:
在目标项目目录中:
cd <output-dir>/<page-name>
npm install # 或 yarn / pnpm install
npm run dev # 启动 Vite 开发服务器
# 浏览器中检查页面渲染是否正常- 页面正常渲染
- 无控制台错误
- 主视觉与原项目基本一致
常见场景
场景 A:纯 React + Vite 项目
这是最简单的场景,因为源项目和目标结构都基于 Vite。
- 复制
src/目录内容到目标src/ - 将
App.tsx改造为薄壳模式 - 创建根目录
index.tsx - 迁移样式到
src/styles/globals.css - 补齐元文件
- 生成
canvas.fig
场景 B:Next.js 项目(V0 等)
- 移除所有 Next.js 特定代码(
"use client"、next/image、next/link、路由等) - 将
app/page.tsx或pages/index.tsx的内容迁移到src/components/ - 将
app/globals.css迁移到src/styles/globals.css - 将
public/下的静态资源迁移到src/assets/或images/ - 排除 Next.js 专属依赖(
next、@vercel/*),保留 UI 组件依赖 - 创建双入口(
index.tsx+src/App.tsx),补齐元文件
场景 C:AI Studio 项目
- 从
index.html的 Import Map 提取依赖,转为 npm 包安装 - 提取
<style>标签内容到src/styles/globals.css process.env.*改为import.meta.env.VITE_*- CDN 图片引用可保留,或下载到
src/assets/ - 创建双入口,补齐元文件
场景 D:已有 Figma Make 导入的项目(补齐导出能力)
此时重点不是从头创建结构,而是确保现有项目的导出壳子与当前页面同步。
- 检查
index.tsx(根入口)和src/App.tsx(导出壳子)是否同步 - 如果不同步,让
src/App.tsx复用根入口的共享组件 - 不要删除已有的
canvas.fig、meta.json、images/等原始资产 - 重新执行 pack 回写
canvas.fig - 刷新
canvas.code-manifest.json和meta.json.exported_at
常见注意点
产物和资源
- 不要把
src/index.css(Figma Make 的 Tailwind 构建产物)直接当最终style.css,它可能有数万行 - 如果目录内已有
canvas.fig、meta.json、images/等原始资产,不要删除它们 images/下的文件通常是 hash 命名的 Figma 关联图片,不要随意重命名canvas.fig是二进制文件,不能手动编辑
入口同步
- 修改根目录页面后,必须同步更新
src/App.tsx,否则导出的.fig会与当前页面不一致 - 两个入口长期不同步是最常见的"漂移"问题 — 保持
src/App.tsx尽量薄,只做包装
依赖和路径
- 不要继续保留对
package@versionalias 的运行时依赖 - 不要把多页面路由壳层原封不动塞进最终页面组件
@/别名应通过vite.config.ts的resolve.alias配置,而非依赖外部构建环境