最近在尝试将设计稿自动转换为前端代码时发现手动从 Figma 复制属性、测量间距、提取颜色值的过程极其繁琐且容易出错。尤其是在处理复杂组件库或设计系统时这种重复劳动不仅效率低下还难以保证代码与设计稿的一致性。为了解决这个痛点我开始探索如何通过自动化工具连接 Figma 与开发流程。本文将聚焦于一个高效的解决方案利用Figma 的 MCPModel Context Protocol协议和Codex API实现从 Figma 设计文件中批量、精准地读取所有设计节点并将其转换为结构化的 JSON 数据。这套方法不仅适用于生成设计标注文档更能直接为代码生成、样式提取、设计资产同步等自动化流程提供可靠的数据源。无论你是希望搭建设计到代码Design-to-Code管道的前端开发者还是需要频繁与设计稿打交道的全栈工程师都能从本文中获得一套完整的、可落地的实战方案。1. 背景与核心概念为什么需要连接 Figma 与代码在深入实战之前我们有必要厘清几个核心概念理解它们如何共同作用来解决设计稿数据化的问题。1.1 Figma不仅仅是设计工具Figma 早已超越传统设计软件成为一个基于云的协作平台。其核心价值在于所有设计文件包括图层、组件、样式等本质上都是一系列可以通过 API 访问的结构化数据。这意味着设计稿不再是一个封闭的“图片”而是一个开放的、可编程的“数据源”。前端开发者可以通过 API 获取到每个元素的精确位置、尺寸、颜色、字体、圆角等属性这为自动化提供了可能。1.2 MCP (Model Context Protocol)数据访问的桥梁MCP即模型上下文协议是 Figma 提供的一套用于与设计文件内容进行交互的协议。你可以将它理解为 Figma 内部数据模型的“驱动程序”或“访问规范”。通过 MCP外部应用如我们的脚本或服务可以查询节点获取画板Frames、组件Components、实例Instances、图形Vectors、文本Text等所有类型的设计节点。读取属性获取节点的详细属性如x,y,width,height,fills填充,strokes描边,effects效果,characters文本内容等。遍历结构按照设计文件的树形结构父子关系、兄弟关系进行深度或广度遍历。简单说MCP 定义了“如何问 Figma 要数据”的规则。我们后续的代码将基于此协议构建请求。1.3 Codex APIFigma 的官方 REST API如果说 MCP 是协议那么 Codex API 就是实现这个协议的具体 HTTP 接口。它是 Figma 官方提供的 RESTful API允许开发者通过发送 HTTP 请求来操作 Figma 文件。我们本文的核心操作——读取文件节点主要依赖于 Codex API 的/v1/files/{file_key}/nodes端点。重要关系我们通过向 Codex API 发送符合 MCP 语义的请求来获取 Figma 文件的数据。因此本文的“实战”本质上是教你如何正确使用 Codex API 来执行 MCP 定义的操作。1.4 JSON通用数据交换格式最终我们从 Figma 获取到的庞杂的节点数据需要以一种通用、可读、易于程序处理的形式输出。JSONJavaScript Object Notation因其轻量级和与 JavaScript 的天生亲和性成为前后端数据交换的事实标准。将 Figma 节点转换为 JSON 后我们可以直接用于生成 CSS-in-JS 样式对象。导入到低代码平台自动生成页面骨架。与后端服务同步建立设计令牌Design Tokens系统。进行设计差异对比和版本管理。理解了这些概念我们就明确了目标编写脚本通过 Figma Codex API遵循 MCP 协议获取设计节点并输出为结构化的 JSON。2. 环境准备与前置条件在开始编码前你需要准备好以下环境和资源。请确保每一步都配置正确这是后续操作成功的基础。2.1 获取 Figma 个人访问令牌 (Personal Access Token)访问令牌是你脚本的“身份证”用于向 Codex API 证明你有权访问特定的 Figma 文件。登录你的 Figma 账号。点击右上角个人头像进入 “Settings”设置。在左侧菜单栏找到 “Account”账户下的 “Personal access tokens”个人访问令牌。点击 “Create new token”创建新令牌。为令牌起一个描述性的名字例如 “Figma-to-JSON-Script”。创建成功后务必立即复制并妥善保存这个令牌字符串。页面关闭后将无法再次查看。安全警告此令牌拥有对你 Figma 账户和文件的访问权限请像保护密码一样保护它。不要将其硬编码在客户端代码或提交到公开的版本控制系统如 GitHub。推荐使用环境变量管理。2.2 获取目标 Figma 文件 Key文件 Key 是 Figma 文件的唯一标识符存在于文件的 URL 中。在浏览器中打开你想要读取的 Figma 文件。观察地址栏URL 格式通常为https://www.figma.com/file/{FILE_KEY}/{File-Name}复制{FILE_KEY}部分。例如如果 URL 是https://www.figma.com/file/abc123DEF456/my-design那么文件 Key 就是abc123DEF456。2.3 开发环境与工具准备本文将使用 Node.js 环境进行演示因为其异步和非阻塞 I/O 特性非常适合处理网络请求。你也可以使用 Python、Go 等任何能发送 HTTP 请求的语言。Node.js: 请确保已安装 Node.js版本 14 或以上。可以在终端运行node --version检查。代码编辑器: VS Code, WebStorm 等任选。HTTP 客户端 (可选): 用于测试 API如 Postman 或 Insomnia。项目初始化 在空目录下初始化一个新的 Node.js 项目并安装必要的依赖。mkdir figma-mcp-demo cd figma-mcp-demo npm init -y npm install axios dotenvaxios: 一个流行的、基于 Promise 的 HTTP 客户端用于发起 API 请求。dotenv: 用于从.env文件加载环境变量安全地管理令牌。2.4 创建环境变量文件在项目根目录创建.env文件用于存储敏感信息。# .env FIGMA_ACCESS_TOKENyour_personal_access_token_here FIGMA_FILE_KEYyour_figma_file_key_here请将your_personal_access_token_here和your_figma_file_key_here替换为你在 2.1 和 2.2 步获取的实际值。重要将.env添加到.gitignore文件中避免意外提交。# .gitignore node_modules/ .env3. 核心原理Figma Codex API 节点查询详解要“一次拿全”所有节点我们需要深入理解 Codex API 的节点查询机制。3.1 API 端点与基础请求核心端点是GET https://api.figma.com/v1/files/{file_key}/nodes?ids{node_ids}{file_key}: 你的 Figma 文件 Key。{node_ids}: 一个或多个用逗号分隔的节点 ID。关键点来了如果你想获取整个文件的所有节点这里应该传入什么3.2 节点的 ID 与 “根节点” 概念Figma 文件是一个树形结构。每个节点画板、组件、图形、文本等都有一个唯一的id。要获取所有节点你需要知道这棵树的“根”在哪里。实际上一个 Figma 文件的“根”就是整个文档Document。它的 ID 是一个特殊的字符串0:0。你可以将其理解为整个文件树的入口点。所以要获取文件中的所有节点你需要查询的 ID 就是0:0。3.3 深度depth与几何geometry参数仅仅传入ids0:0可能不会返回所有层级的细节数据。这时就需要用到两个重要的查询参数depth(可选): 指定要返回的节点层级深度。例如depth1只返回直接子节点。要获取所有后代节点可以传入一个较大的数字如99或者更常见的做法是不传此参数API 默认会返回所有层级的节点。geometry(可选): 决定返回的节点数据中是否包含absoluteBoundingBox绝对边界框等几何信息。对于需要精确位置和尺寸的场景如生成代码必须将其设置为geometrypaths或直接不传默认行为可能包含几何信息但显式声明更稳妥。根据最新 API 文档推荐使用geometrypaths来获取最完整的矢量路径和边界框数据。因此一个完整的、用于获取文件中所有节点数据的请求 URL 可能如下https://api.figma.com/v1/files/{FILE_KEY}/nodes?ids0:0depth99geometrypaths3.4 响应数据结构分析API 成功响应后会返回一个 JSON 对象。其核心结构如下{ name: “文件名, lastModified: “时间戳, nodes: { “0:0”: { “document”: { “id”: “0:0”, “name”: “Document”, “type”: “DOCUMENT”, “children”: [ // 这是一个数组包含了第一级页面Page节点 { “id”: “1:2”, “name”: “Page 1”, “type”: “CANVAS”, “children”: [ // 页面下的画板Frame、组件等节点 // 每个节点可能又包含自己的 children形成树 ] } ] } } } }你需要遍历这个嵌套的children数组才能访问到每一个设计元素。节点的type字段如FRAME,RECTANGLE,TEXT,COMPONENT,INSTANCE决定了它包含哪些具体的属性如fills,strokes,characters等。4. 完整实战从零构建 Figma 节点提取脚本现在我们将把理论付诸实践编写一个完整的 Node.js 脚本。4.1 项目结构与入口文件创建项目主文件index.js。// index.js require(‘dotenv’).config(); // 加载 .env 文件中的环境变量 const axios require(‘axios’); const fs require(‘fs’).promises; // 从环境变量读取配置 const FIGMA_ACCESS_TOKEN process.env.FIGMA_ACCESS_TOKEN; const FIGMA_FILE_KEY process.env.FIGMA_FILE_KEY; // 检查配置是否加载成功 if (!FIGMA_ACCESS_TOKEN || !FIGMA_FILE_KEY) { console.error(‘错误请确保在 .env 文件中配置了 FIGMA_ACCESS_TOKEN 和 FIGMA_FILE_KEY’); process.exit(1); } // Figma API 的基础配置 const FIGMA_API_BASE ‘https://api.figma.com/v1’; const headers { ‘X-Figma-Token’: FIGMA_ACCESS_TOKEN }; async function fetchAllFigmaNodes() { console.log(‘开始获取 Figma 文件节点数据...’); const url ${FIGMA_API_BASE}/files/${FIGMA_FILE_KEY}/nodes; try { // 构建查询参数查询根节点深度设为足够大请求几何路径信息 const params { ids: ‘0:0’, // 查询文档根节点 depth: 99, // 深度确保获取所有层级 geometry: ‘paths’ // 获取几何信息 }; const response await axios.get(url, { headers, params }); if (response.status 200) { console.log(‘API 请求成功’); return response.data; // 返回完整的 API 响应数据 } else { throw new Error(API 返回错误状态码: ${response.status}); } } catch (error) { console.error(‘获取 Figma 节点数据失败:’, error.message); if (error.response) { // 输出更详细的 API 错误信息 console.error(‘错误详情:’, error.response.data); } process.exit(1); } }这个fetchAllFigmaNodes函数完成了最核心的一步向 Figma API 发起请求获取整个文件树的原始数据。4.2 递归遍历与数据提取获取到原始数据后我们需要一个函数来递归遍历整棵树提取我们关心的信息并构建一个更简洁、实用的 JSON 结构。// index.js (接上文) /** * 递归遍历 Figma 节点树提取关键信息 * param {Object} node - Figma 节点对象 * param {string} parentId - 父节点ID * returns {Object} 提取后的节点信息 */ function extractNodeInfo(node, parentId null) { // 基础信息 const nodeInfo { id: node.id, name: node.name || ‘Unnamed’, type: node.type, parentId: parentId, visible: node.visible ! false // 默认为 true }; // 根据节点类型提取特定属性 switch (node.type) { case ‘FRAME’: case ‘GROUP’: case ‘COMPONENT’: case ‘INSTANCE’: case ‘RECTANGLE’: case ‘ELLIPSE’: case ‘VECTOR’: // 提取几何信息 if (node.absoluteBoundingBox) { nodeInfo.absoluteBoundingBox node.absoluteBoundingBox; nodeInfo.width node.absoluteBoundingBox.width; nodeInfo.height node.absoluteBoundingBox.height; nodeInfo.x node.absoluteBoundingBox.x; nodeInfo.y node.absoluteBoundingBox.y; } // 提取样式信息 nodeInfo.styles { fills: node.fills || [], strokes: node.strokes || [], cornerRadius: node.cornerRadius, effects: node.effects || [] }; break; case ‘TEXT’: // 提取文本信息 nodeInfo.text { characters: node.characters || ‘’, style: { fontFamily: node.style?.fontFamily, fontWeight: node.style?.fontWeight, fontSize: node.style?.fontSize, lineHeightPx: node.style?.lineHeightPx, textAlignHorizontal: node.style?.textAlignHorizontal, fills: node.fills || [] } }; if (node.absoluteBoundingBox) { nodeInfo.absoluteBoundingBox node.absoluteBoundingBox; } break; // 可以继续添加其他类型的处理如 LINE, STAR, POLYGON 等 } // 递归处理子节点 if (node.children Array.isArray(node.children) node.children.length 0) { nodeInfo.children node.children.map(child extractNodeInfo(child, node.id)); } return nodeInfo; } /** * 处理原始 API 响应构建结构化的节点树 * param {Object} apiResponse - fetchAllFigmaNodes 返回的原始数据 * returns {Array} 结构化的节点数组 */ function processFigmaData(apiResponse) { console.log(‘开始处理并提取节点数据...’); const rootNode apiResponse.nodes[‘0:0’]?.document; if (!rootNode) { throw new Error(‘未找到有效的文档根节点’); } const processedData { fileName: apiResponse.name, lastModified: apiResponse.lastModified, // 从根节点开始递归提取 pages: rootNode.children ? rootNode.children.map(page extractNodeInfo(page)) : [] }; console.log(数据处理完成。共处理了 ${processedData.pages.length} 个页面。); return processedData; }extractNodeInfo函数是核心的数据转换器。它递归地访问每个节点根据其type提取最相关的属性如尺寸、位置、文本内容、样式并保留树形的children关系。4.3 保存数据与主流程最后我们将处理好的数据保存到本地 JSON 文件并编写主函数串联所有步骤。// index.js (接上文) /** * 将数据保存为 JSON 文件 * param {Object} data - 要保存的数据 * param {string} filename - 输出文件名 */ async function saveDataToFile(data, filename ‘figma-nodes-output.json’) { try { const jsonString JSON.stringify(data, null, 2); // 缩进2个空格美化输出 await fs.writeFile(filename, jsonString, ‘utf8’); console.log(数据已成功保存至文件: ${filename}); } catch (error) { console.error(‘保存文件失败:’, error); } } /** * 主函数协调整个流程 */ async function main() { try { // 1. 从 Figma API 获取原始数据 const rawData await fetchAllFigmaNodes(); // 2. 处理原始数据提取关键信息并构建结构 const structuredData processFigmaData(rawData); // 3. 将处理后的数据保存到本地文件 await saveDataToFile(structuredData); // 4. (可选) 在控制台打印一些统计信息 let totalNodes 0; function countNodes(nodes) { nodes.forEach(node { totalNodes; if (node.children) { countNodes(node.children); } }); } countNodes(structuredData.pages); console.log(总计提取了 ${totalNodes} 个设计节点。); } catch (error) { console.error(‘主流程执行失败:’, error); } } // 执行主函数 if (require.main module) { main(); } // 导出函数方便其他模块引用 module.exports { fetchAllFigmaNodes, extractNodeInfo, processFigmaData, saveDataToFile };4.4 运行与验证在终端中运行你的脚本node index.js如果一切配置正确你将看到类似以下的输出开始获取 Figma 文件节点数据... API 请求成功 开始处理并提取节点数据... 数据处理完成。共处理了 2 个页面。 数据已成功保存至文件: figma-nodes-output.json 总计提取了 347 个设计节点。同时项目根目录下会生成一个figma-nodes-output.json文件。用编辑器打开它你就能看到整个 Figma 文件被转换成的、层次分明的 JSON 数据结构。每个节点都包含了你在extractNodeInfo函数中定义的关键属性。5. 进阶应用与数据加工示例拿到结构化的 JSON 数据只是第一步。如何利用这些数据创造价值以下是几个常见的应用场景和代码片段。5.1 生成 CSS 样式代码片段你可以遍历 JSON 数据将 Figma 中的样式属性转换为 CSS 规则。// generate-css.js const fs require(‘fs’).promises; const { processFigmaData, fetchAllFigmaNodes } require(‘./index’); // 引入之前的函数 async function generateCSSFromFigma() { const rawData await fetchAllFigmaNodes(); const structuredData processFigmaData(rawData); let cssContent ‘/* 自动生成的 CSS源自 Figma 设计稿 */\n\n’; function processNodeForCSS(node, classNamePrefix ‘’) { const className ${classNamePrefix}${node.name.toLowerCase().replace(/\s/g, ‘-’)}-${node.id.slice(-4)}; if (node.type ‘RECTANGLE’ || node.type ‘FRAME’) { let cssRule .${className} {\n; cssRule position: absolute;\n; cssRule left: ${node.x}px;\n; cssRule top: ${node.y}px;\n; cssRule width: ${node.width}px;\n; cssRule height: ${node.height}px;\n; // 处理背景色取第一个纯色填充 if (node.styles.fills node.styles.fills.length 0) { const solidFill node.styles.fills.find(fill fill.type ‘SOLID’); if (solidFill) { const { r, g, b } solidFill.color; const a solidFill.opacity ! undefined ? solidFill.opacity : 1; cssRule background-color: rgba(${Math.round(r*255)}, ${Math.round(g*255)}, ${Math.round(b*255)}, ${a});\n; } } // 处理圆角 if (node.styles.cornerRadius) { cssRule border-radius: ${node.styles.cornerRadius}px;\n; } cssRule ‘}\n\n’; cssContent cssRule; } // 递归处理子节点 if (node.children) { node.children.forEach(child processNodeForCSS(child, ${className}__)); } } structuredData.pages.forEach(page { cssContent /* Page: ${page.name} */\n; if (page.children) { page.children.forEach(child processNodeForCSS(child)); } }); await fs.writeFile(‘styles-from-figma.css’, cssContent, ‘utf8’); console.log(‘CSS 文件已生成: styles-from-figma.css’); } generateCSSFromFigma().catch(console.error);5.2 提取设计令牌 (Design Tokens)设计令牌是存储设计决策如颜色、字体、间距的单一事实来源。你可以从 JSON 中提取这些值。// extract-tokens.js const fs require(‘fs’).promises; const { processFigmaData, fetchAllFigmaNodes } require(‘./index’); async function extractDesignTokens() { const rawData await fetchAllFigmaNodes(); const structuredData processFigmaData(rawData); const tokens { colors: new Set(), typography: new Set(), spacing: new Set(), radii: new Set() }; function collectTokens(node) { // 收集颜色 if (node.styles node.styles.fills) { node.styles.fills.forEach(fill { if (fill.type ‘SOLID’ fill.color) { const { r, g, b, a 1 } fill.color; const colorStr rgba(${Math.round(r*255)}, ${Math.round(g*255)}, ${Math.round(b*255)}, ${a}); tokens.colors.add(colorStr); } }); } // 收集文字样式 if (node.type ‘TEXT’ node.text node.text.style) { const { fontFamily, fontWeight, fontSize } node.text.style; if (fontFamily fontSize) { const typeStr ${fontFamily}-${fontWeight || ‘regular’}-${fontSize}; tokens.typography.add(typeStr); } } // 收集间距和尺寸示例收集所有宽度 if (node.width) { tokens.spacing.add(${node.width}px); } if (node.styles node.styles.cornerRadius) { tokens.radii.add(${node.styles.cornerRadius}px); } // 递归 if (node.children) { node.children.forEach(collectTokens); } } structuredData.pages.forEach(page { if (page.children) page.children.forEach(collectTokens); }); // 转换为数组并排序 const result { colors: Array.from(tokens.colors).sort(), typography: Array.from(tokens.typography).sort(), spacing: Array.from(tokens.spacing).sort((a,b) parseFloat(a) - parseFloat(b)), radii: Array.from(tokens.radii).sort((a,b) parseFloat(a) - parseFloat(b)) }; await fs.writeFile(‘design-tokens.json’, JSON.stringify(result, null, 2), ‘utf8’); console.log(‘设计令牌已提取至: design-tokens.json’); console.log(‘统计:’, { 颜色数: result.colors.length, 字体样式数: result.typography.length, 间距值数: result.spacing.length, 圆角值数: result.radii.length }); } extractDesignTokens().catch(console.error);6. 常见问题与排查思路在实际操作中你可能会遇到一些问题。以下是常见问题的排查指南。问题现象可能原因排查步骤与解决方案API 请求返回 403 或 401 错误1. 访问令牌无效或已过期。2. 令牌权限不足。3. 文件 Key 错误或无权访问该文件。1. 检查.env文件中的FIGMA_ACCESS_TOKEN值是否正确是否包含多余空格。2. 前往 Figma 设置页面确认令牌状态正常。3. 确认文件 Key 来自正确的 URL并确保该文件存在于你的团队或你有访问权限。API 请求返回 404 错误1. 文件 Key 错误。2. API 端点 URL 拼写错误。1. 仔细核对文件 URL 中的 Key。2. 检查代码中的FIGMA_API_BASE和端点路径是否正确。返回的节点数据为空或缺少子节点1. 查询参数ids未设置为0:0。2.depth参数值太小。3. 请求的节点 ID 不存在。1. 确保params.ids为‘0:0’。2. 增大depth参数值如 99。3. 可以先尝试请求一个已知存在的具体节点 ID 进行测试。脚本运行时报错Cannot read property ‘document’ of undefinedAPI 响应格式与预期不符nodes[‘0:0’]为undefined。1. 在fetchAllFigmaNodes函数中打印response.data检查完整的 API 响应结构。2. 确认文件是否为空或已被删除。生成的 JSON 文件非常大难以查看设计文件非常复杂节点数量极多。1. 在extractNodeInfo函数中过滤不需要的节点类型或属性。2. 考虑分页或按需提取例如只提取特定页面或画板的节点。3. 使用代码编辑器或jq命令行工具来查看大型 JSON 文件。网络请求超时文件过大或网络连接不稳定。1. 为axios请求增加超时配置axios.get(url, { headers, params, timeout: 30000 })。2. 考虑使用分批次查询节点通过多个ids的策略但这需要更复杂的逻辑。无法获取组件Component的详细属性默认查询可能只返回组件实例Instance的浅层信息。对于COMPONENT或INSTANCE类型节点如果需要其主组件master component的详细属性可能需要额外调用/v1/files/{file_key}端点获取完整的文件数据或使用ids参数查询特定的组件节点 ID。7. 最佳实践与工程建议将 Figma 数据集成到开发流程中时遵循以下最佳实践可以提升效率、可靠性和可维护性。7.1 安全与密钥管理永远不要硬编码令牌始终使用环境变量.env或安全的密钥管理服务如 AWS Secrets Manager, Azure Key Vault。使用最小权限令牌如果 Figma 支持创建仅具有“文件读取”权限的令牌降低安全风险。轮换令牌定期更新访问令牌特别是在脚本泄露或人员变动时。7.2 性能优化按需提取不要每次都拉取整个文件。如果只关心特定页面或组件使用具体的节点 ID 列表进行查询例如ids1:23,4:56,7:89。实现缓存机制设计稿不会每分钟都变更。可以将 API 响应缓存到本地文件或数据库并设置一个合理的过期时间如 1 小时避免频繁请求 API 触发速率限制。增量更新利用 Figma API 返回的lastModified时间戳判断文件是否已更新再决定是否重新拉取全部数据。7.3 错误处理与健壮性添加重试机制网络请求可能失败。使用axios-retry等库为axios添加指数退避的重试逻辑。处理速率限制Figma API 有调用频率限制。在代码中检查响应头中的X-RateLimit-*信息并在接近限制时添加延迟或暂停。验证数据完整性在处理 JSON 数据前检查必需字段是否存在避免因数据结构变化导致脚本崩溃。7.4 集成到 CI/CD 流程自动化检查在拉取请求Pull Request环节运行脚本对比设计稿 JSON 与现有代码生成的设计令牌确保开发未偏离设计。生成资产流水线将本脚本作为 CI/CD 流水线的一环自动从 Figma 提取最新的颜色、字体、间距变量并生成对应的 CSS/Sass/JS 变量文件直接供项目使用。版本化设计数据将定期生成的figma-nodes-output.json提交到仓库或专用存储可以追踪设计稿的历史变化方便进行设计审计或回滚。7.5 代码结构优化配置文件化将需要提取的节点类型、属性映射关系、CSS 生成规则等抽离到单独的配置文件中使核心脚本更通用。插件化处理参考示例中的extractNodeInfo函数可以为不同的下游用途生成 CSS、提取令牌、生成 Sketch 符号映射编写不同的“处理器”Processor使架构更清晰。添加日志与监控使用winston或pino等日志库替代console.log记录脚本运行状态、提取的节点数量、API 耗时等便于监控和调试。通过本文的实战你已经掌握了利用 Figma MCP 协议和 Codex API 将设计稿转化为结构化 JSON 数据的完整能力。这套方法的价值远不止于生成一份数据报告它为你打开了设计开发一体化DesignOps的大门。你可以在此基础上构建自动化的样式同步系统、设计版本对比工具甚至与 AI 结合探索智能生成前端组件代码的可能性。下一步尝试将提取的数据与你项目中的 Tailwind CSS 配置、Styled-components 主题或任何现有的设计系统连接起来让设计与代码的协作真正变得高效且无缝。