一、介绍

1.1 插件概述

FigmaToCode 是一款开源 Figma 设计转代码插件,可一键将设计稿转换为标准响应式前端代码,原生支持 HTML、React(JSX)、Svelte 等主流开发框架与样式方案。

1.2 核心能力清单

能力 说明
节点转换 提取 Figma 原生 BaseNode / SceneNode,导出保留尺寸、样式、完整层级的结构化 JSON 数据。
中间描述 IR(Intermediate Representation) IR 是插件自定义的虚拟节点格式 AltNodes(非 Figma 官方原生类型),具备可控、精简、可扩展增强特性。
布局优化 基于 IR 层预处理布局逻辑,识别 AutoLayout、Group、Frame 容器,优化嵌套层级、对齐方式与间距。
代码生成 将 IR 层的 AltNodes 映射为目标框架原生代码,各框架转换逻辑均遵循对应开发最佳实践。

二、原理分析

2.1 核心转换详细流程

开始:用户选中 Figma 节点

阶段 1:节点转换

导出 JSON_REST_V1 格式

预处理:GROUP 转 FRAME/过滤无效节点

属性标准化:旋转修正/尺寸校准

阶段 2:中间表示层(IR)生成

转换为 AltNodes 虚拟节点

完善层级:绑定父子关系/生成唯一名称

特性优化:颜色变量处理/SVG 扁平化标记

阶段 3:布局优化

检测布局模式:AutoLayout/混合模式

响应式约束转换:FILL/HUG/FIXED 适配

优化层级:调整子节点顺序/容器适配

阶段 4:多框架代码生成

适配器模式:选择目标框架

按框架规范生成代码:HTML/React/Flutter 等

结束:输出可直接使用的目标代码

FigmaToCode 核心转换遵循「节点转换→IR 生成→布局优化→代码生成」四阶段流程,以下结合流程图,拆解各环节核心操作,明确流程落地细节与各环节关联。

2.1.1 核心转换流程拆解(四阶段落地)

流程以「选中节点」为起点,经四阶段核心处理输出目标代码,核心代码及步骤如下,与整体流程图完全对应:

基本流程代码
// 1. 获取数据源:用户选中的 Figma 原生节点
const selectedNodes = figma.currentPage.selection;
// 2. 节点转换+IR 生成:生成标准化中间表示层(AltNodes)
const standardizedAltNodes = await nodesToJSON(selectedNodes, pluginSettings);
// 3. 布局优化:对 AltNodes 进行 AutoLayout 检测、约束转换
const optimizedAltNodes = await optimizeLayout(standardizedAltNodes, pluginSettings);
// 4. 代码生成:通过适配器模式输出目标框架代码
const targetCode = await convertToCode(optimizedAltNodes, pluginSettings);
步骤说明
  1. 获取选中节点:通过 figma.currentPage.selection 获取数据源,对应流程图「开始」环节;
  2. 节点转换与 IR 生成:调用 nodesToJSON,完成原生节点转 JSON、预处理及属性标准化,生成 AltNodes(详见 2.2 节、2.3 节),对应流程图「节点转换→IR 生成」阶段;
  3. 布局优化:调用 optimizeLayout,完成 AutoLayout 识别、响应式约束转换(详见 2.4 节),对应流程图「布局优化」阶段;
  4. 生成目标代码:调用 convertToCode,通过适配器模式生成多框架代码(详见 2.5 节),对应流程图「代码生成→结束」环节。

2.2 原生节点转换解析

Figma 文件以节点树形式组织,根节点为 DOCUMENT,衍生所有 CANVAS 节点;每个 CANVAS 对应一个页面,包含图形、文本、组件等子节点,节点属性分为全局通用属性与节点专属属性。原生节点转换作为 FigmaToCode 四阶段转换的第一阶段,核心是将 Figma 原生节点标准化,为后续流程奠定基础,具体解析如下。

2.2.1 原生节点转换概述

原生节点转换是 FigmaToCode 四阶段转换的第一阶段,核心是将 Figma 原生 SceneNode 节点,转换为可后续处理的标准化数据,为中间表示层(AltNodes)生成和布局优化奠定基础。核心流程为:Figma 原生节点→导出 JSON_REST_V1 格式→预处理→属性标准化→生成 AltNodes 雏形,核心依赖 nodesToJSON 方法,节点矩形化作为关键预处理步骤辅助完成转换。

2.2.2 nodesToJSON 实现

nodesToJSON 是节点转换的核心中转方法,核心职责是将 Figma 原生 SceneNode 节点转为可后续处理的 JSON 格式,完成预处理与属性标准化,为 AltNode 生成奠定基础,主要包含两大核心模块。

2.2.2.1 JSON 导出与初步预处理

该模块负责批量导出节点 JSON_REST_V1 格式数据,同时预处理 GROUP 节点(转为 FRAME)、修正旋转角度,避免子节点继承异常,为后续属性标准化奠定基础。

GROUP 转 FRAME 是节点矩形化的核心操作,先在 nodeToJSON 方法中完成基础转换,后续在 processNodePair 方法的节点类型转换中,通过 GROUP 扁平化完成节点矩形化完整落地;同时节点矩形化同步规范背景矩形、对齐元素格式,统一节点结构以规避后续处理异常。

// 核心方法:将 Figma 原生节点转为可处理 JSON,完成预处理与属性标准化
// 入参:nativeNodes(Figma 原生节点数组)、pluginSettings(插件配置)
// 出参:标准化后的 AltNode 数组(中间表示层节点)
async function nodesToJSON(nativeNodes: SceneNode[], pluginSettings: PluginSettings): Promise<AltNode[]> {
  nameCounter.clear(); // 重置名称计数器,保证节点唯一名称不重复
  // 批量导出 JSON,建立原生节点与 JSON 节点的配对,并行处理提升效率
  const nodeExportPairs = await Promise.all(
    nativeNodes.map(async (nativeNode) => {
      // 导出 JSON_REST_V1 格式(Figma 节点交互标准格式),取 document 节点
      const jsonNode = (await nativeNode.exportAsync({ format: "JSON_REST_V1" })) as any).document;
      let cumulativeRotation = 0; // 累积旋转角度,用于修正子节点继承父节点旋转的偏差
      // 预处理:GROUP 节点转为 FRAME,避免子节点旋转继承异常
      // 【节点矩形化核心代码 1】GROUP 转 FRAME,对应 2.2.4 节 GROUP 转 FRAME 规则
      if (nativeNode.type === "GROUP") {
        jsonNode.type = "FRAME";
        if (jsonNode.rotation) {
          // 弧度转角度并取反,抵消 GROUP 旋转对於子节点定位的影响
          cumulativeRotation = -jsonNode.rotation * (180 / Math.PI);
          jsonNode.rotation = 0; // 重置 GROUP 旋转角度,避免重复计算
        }
      }
      return { jsonNode, nativeNode, cumulativeRotation };
    })
  );
  // 调用 processNodePair 完成属性标准化,生成中间表示层 AltNode(核心调用)
  // 遍历所有节点配对,逐个调用 processNodePair 处理,最终得到标准化 AltNode 数组
  const processedAltNodes = await Promise.all(
    nodeExportPairs.map(pair => processNodePair(pair.jsonNode, pair.nativeNode, pluginSettings, null, pair.cumulativeRotation))
  );
  // 过滤无效节点(null),返回标准化后的 AltNode 数组
  return processedAltNodes.filter(node => node !== null) as AltNode[];
}
2.2.2.2 核心逻辑:processNodePair 方法详解

processNodePair 是 nodesToJSON 的核心依赖,负责配对原生节点与 JSON 数据,贯穿节点过滤、类型转换、属性标准化等全流程,通过自身递归调用处理子节点,最终生成标准 AltNode,核心分为 5 个步骤,各步骤均围绕该方法的核心逻辑展开。

第一步:节点过滤与验证

核心作用:筛选有效节点,避免转换异常,仅保留有唯一 ID、可见且非 SLICE 类型的节点,减少无效计算。

// 过滤无效节点,避免转换异常,保障流程稳定
// 过滤条件:无唯一 ID、节点不可见、不支持的 SLICE 切片节点
if (!jsonNode.id || !jsonNode.visible || jsonNode.type === "SLICE") {
  return null;
}

逻辑解读:过滤无唯一 ID、不可见及 SLICE 节点,保障转换流程稳定。

第二步:节点类型转换

核心作用:优化节点结构、统一格式,避免后续属性处理异常,主要包含空容器优化与 GROUP 节点扁平化两个核心操作。

const currentNodeType = jsonNode.type;
// 2.1 空容器优化:无子女的容器节点转为 RECTANGLE(简化节点结构)
const containerNodeTypesArr = ["FRAME", "INSTANCE", "COMPONENT", "COMPONENT_SET"];
if (containerNodeTypesArr.includes(currentNodeType) && !jsonNode.children?.length) {
  jsonNode.type = "RECTANGLE";
  // 重新调用自身(processNodePair),处理转换后的 RECTANGLE 节点,确保属性标准化
  return processNodePair(jsonNode, nativeNode, pluginSettings, parentNode, cumulativeRotation);
}

// 2.2 GROUP 扁平化:转为 FRAME,子节点提升至父级,简化节点层级
// 【节点矩形化核心代码 2】GROUP 扁平化+转 FRAME,对应 2.2.4 节 GROUP 转 FRAME 规则
if (currentNodeType === "GROUP" && jsonNode.children) {
  const processedChildNodes: AltNode[] = []; // 存储处理后的子节点
  // 筛选可见子节点(过滤不可见节点,减少无效计算)
  const visibleChildNodes = jsonNode.children.filter(child => child.visible !== false);
  // 建立原生子节点映射,便于快速匹配 JSON 子节点与原生子节点
  const nativeChildNodeMap = new Map(nativeNode.children.map(child => [child.id, child]));
  for (const childNode of visibleChildNodes) {
    const nativeChildNode = nativeChildNodeMap.get(childNode.id);
    if (!nativeChildNode) continue; // 跳过无匹配原生节点的子节点
    // 递归调用 processNodePair 处理子节点,继承 GROUP 的旋转角度(累积计算)
    const processedChildNode = await processNodePair(
      childNode, nativeChildNode, pluginSettings, parentNode, cumulativeRotation + (jsonNode.rotation || 0)
    );
    // 收集有效子节点(兼容数组/单个节点返回格式)
    processedChildNode && processedChildNodes.push(...(Array.isArray(processedChildNode) ? processedChildNode : [processedChildNode]));
  }
  return processedChildNodes; // 移除 GROUP 节点,直接返回子节点(扁平化)
}
第三步:属性标准化

核心作用:统一属性格式、补充默认值、修正定位偏差,为后续处理提供统一的数据基础,涵盖父子关联、命名规范、文本处理等关键操作。

// 3.1 父子关联与旋转继承:明确节点层级,修正子节点定位偏差
if (parentNode) {
  (jsonNode as any).parent = parentNode; // 绑定父节点,明确层级关系
  jsonNode.cumulativeRotation = cumulativeRotation; // 继承累积旋转角度
}

// 3.2 唯一名称生成:避免代码中节点名称冲突,保证命名规范
const currentNodeName = jsonNode.name.trim(); // 去除节点名称前后空格
const currentNameOccurrence = nameCounter.get(currentNodeName) || 0; // 当前名称出现次数
nameCounter.set(currentNodeName, currentNameOccurrence + 1); // 更新名称计数
// 生成唯一名称:首次出现用原名,重复则加两位序号(补零保证格式统一)
jsonNode.uniqueName = currentNameOccurrence === 0
  ? currentNodeName
  : `${currentNodeName}_${currentNameOccurrence.toString().padStart(2, "0")}`;
  
// 3.3 文本节点特殊处理:解析富文本样式,处理颜色变量(适配主题化)
if (nativeNode.type === "TEXT") {
  // 获取文本富文本片段(包含字体、颜色、字号等关键样式)
  let styledTextSegments = nativeNode.getStyledTextSegments([
    "fontName", "fills", "fontSize", "fontWeight",
    "hyperlink", "indentation", "letterSpacing", "lineHeight"
  ]);
  // 批量处理富文本片段,统一颜色变量(若开启主题化配置)
  styledTextSegments = await Promise.all(
    styledTextSegments.map(async (styledSegment, index) => {
      const styledSegmentCopy = { ...styledSegment }; // 深拷贝,避免修改原数据
      // 开启颜色变量时,处理片段填充色的变量标准化
      if (pluginSettings.useColorVariables && styledSegment.fills) {
        styledSegmentCopy.fills = await Promise.all(
          styledSegment.fills.map(async (fill) => {
            const processedFill = { ...fill } as Paint;
            await processColorVariables(processedFill); // 颜色变量标准化
            return processedFill;
          })
        );
      }
      // 生成片段唯一 ID:单个片段用 span,多个片段加两位序号
      const segmentIdSuffix = styledTextSegments.length === 1
        ? "span"
        : `span_${(index + 1).toString().padStart(2, "0")}`;
      styledSegmentCopy.uniqueId = `${currentNodeName}_${segmentIdSuffix}`;
      return styledSegmentCopy;
    })
  );
  jsonNode.styledTextSegments = styledTextSegments; // 挂载处理后的富文本片段
}

// 3.4 尺寸位置计算:修正旋转影响,计算子节点相对父节点的位置
if (jsonNode.absoluteBoundingBox) {
  const absoluteBoundingBox = jsonNode.absoluteBoundingBox; // 节点绝对边界框
  if (parentNode) {
    // 计算子节点相对父节点的边界框(抵消父节点位置影响)
    const relativeBoundingBox = {
      width: absoluteBoundingBox.width,
      height: absoluteBoundingBox.height,
      x: absoluteBoundingBox.x - (parentNode.absoluteBoundingBox?.x || 0),
      y: absoluteBoundingBox.y - (parentNode.absoluteBoundingBox?.y || 0)
    };
    // 旋转修正角度:抵消自身旋转和父级累积旋转的影响
    const rotationCorrectionAngle = -((jsonNode.rotation || 0) + (jsonNode.cumulativeRotation || 0));
    // 计算修正后的边界框,确保尺寸和位置精准
    const correctedBoundingRect = calculateRectangleFromBoundingBox(relativeBoundingBox, rotationCorrectionAngle);
    // 赋值标准化后的尺寸和位置
    jsonNode.width = correctedBoundingRect.width;
    jsonNode.height = correctedBoundingRect.height;
    jsonNode.x = correctedBoundingRect.left;
    jsonNode.y = correctedBoundingRect.top;
  } else {
    // 顶层节点:统一定位基准(x/y 设为 0),直接使用绝对尺寸
    jsonNode.width = absoluteBoundingBox.width;
    jsonNode.height = absoluteBoundingBox.height;
    jsonNode.x = 0;
    jsonNode.y = 0;
  }
}

// 3.5 布局属性标准化:补充默认值,避免 undefined 导致的转换异常
jsonNode.layoutMode ??= "NONE"; // 布局模式默认:无布局
jsonNode.layoutGrow ??= 0; // 布局拉伸权重默认:不拉伸
jsonNode.layoutSizingHorizontal ??= "FIXED"; // 水平尺寸默认:固定
jsonNode.layoutSizingVertical ??= "FIXED"; // 垂直尺寸默认:固定
const hasChildNodes = jsonNode.children?.length > 0;
// 无子节点时,取消 HUG 布局模式(防止无内容节点出现拉伸异常),变更为 FIXED
if (jsonNode.layoutSizingHorizontal === "HUG" && !hasChildNodes) jsonNode.layoutSizingHorizontal = "FIXED";
if (jsonNode.layoutSizingVertical === "HUG" && !hasChildNodes) jsonNode.layoutSizingVertical = "FIXED";
// 有布局模式时,补充内边距默认值(避免 undefined 报错)
if (jsonNode.layoutMode) {
  jsonNode.paddingLeft ??= 0;
  jsonNode.paddingRight ??= 0;
  jsonNode.paddingTop ??= 0;
  jsonNode.paddingBottom ??= 0;
}
第四步:递归子节点处理

核心作用:构建完整节点树,优化子节点层级与渲染顺序,确保与 Figma 原生节点树结构、显示效果一致。

// 有子节点时,递归调用 processNodePair 处理所有可见子节点,构建完整节点树
if (jsonNode.children?.length) {
  // 筛选可见子节点,过滤不可见节点(减少无效计算)
  const visibleChildNodes = jsonNode.children.filter(child => child.visible !== false) as AltNode[];
  // 建立原生子节点映射,快速匹配 JSON 子节点与原生子节点
  const nativeChildNodeMap = new Map(nativeNode.children.map(child => [child.id, child]));
  const processedChildNodes: AltNode[] = []; // 存储处理后的子节点
  for (const childNode of visibleChildNodes) {
    const nativeChildNode = nativeChildNodeMap.get(childNode.id);
    if (!nativeChildNode) continue; // 跳过无匹配原生节点的子节点
    // 递归调用 processNodePair 处理子节点,绑定当前节点为父节点,继承累积旋转角度
    const processedChildNode = await processNodePair(childNode, nativeChildNode, pluginSettings, jsonNode, cumulativeRotation);
    // 收集有效子节点(兼容数组/单个节点返回格式)
    processedChildNode && processedChildNodes.push(...(Array.isArray(processedChildNode) ? processedChildNode : [processedChildNode]));
  }
  jsonNode.children = processedChildNodes; // 更新子节点为处理后的列表
  // 标记是否相对定位:无布局模式 或 有绝对定位子节点,视为相对定位
  jsonNode.isRelative = jsonNode.layoutMode === "NONE" || jsonNode.children.some(child => child.layoutPositioning === "ABSOLUTE");
  adjustChildrenOrder(jsonNode); // 优化 z-index 顺序,确保节点渲染层级与 Figma 原生一致
}
第五步:特性优化

核心作用:适配主题化与 SVG 导出需求,提升中间表示层扩展性,主要包含 SVG 扁平化标记与颜色变量标准化处理。

// 5.1 SVG 扁平化处理:标记可扁平化为 SVG 的图标节点,适配 SVG 优化导出
if (pluginSettings.embedVectors && !parentNode?.canBeFlattened) {
  const isIconNode = isLikelyIcon(jsonNode as any); // 判断是否为图标节点
  (jsonNode as any).canBeFlattened = isIconNode; // 标记是否可扁平化
  // 开启颜色变量时,标记需要收集颜色映射(用于主题切换)
  if (isIconNode && pluginSettings.useColorVariables) {
    (jsonNode as any)._collectColorMappings = true;
  }
}

// 5.2 颜色变量处理:标准化颜色配置,收集颜色映射,支撑主题化切换
await processColorVariables(jsonNode, pluginSettings);
// 收集颜色映射后,删除临时标记(精简节点属性)
if ((jsonNode as any)._collectColorMappings) {
  (jsonNode as any).colorVariableMappings = await collectNodeColorVariables(jsonNode);
  delete (jsonNode as any)._collectColorMappings;
}
return jsonNode as AltNode; // 返回标准化后的中间表示层 AltNode

2.2.3 JSON_REST_V1 格式说明

JSON_REST_V1 是 Figma 官方节点交互标准格式,也是 nodesToJSON 方法(2.2.2 节)批量导出原生节点的核心格式,用于承载节点树完整层级和属性,是原生节点转换的基础(Figma 支持图像、SVG、PDF、JSON 四种导出类型)。

// JSON_REST_V1 导出示例:导出单个节点的完整节点树数据
// targetNode:用户选中的单个 Figma 节点
const targetNode = figma.currentPage.selection[0];
// jsonNode:导出的 JSON_REST_V1 格式数据(包含节点完整层级和属性)
const jsonNode = await targetNode.exportAsync({ format: "JSON_REST_V1" });

导出内容为嵌套节点树,完整格式可参考Figma 官方 API 文档

JSON_REST_V1 格式的核心是对节点属性的标准化描述,其中包含所有节点通用的全局属性,以及不同类型节点专属的类型属性,具体如下:

全局属性

所有节点通用的基础属性如下表:

属性名 类型 描述
id string 节点唯一标识
name string 节点名称
visible boolean 节点可见性(默认 true)
type string 节点类型(FRAME、TEXT 等)
rotation number 旋转角度(默认 0)
pluginData any 插件私有数据
sharedPluginData any 所有插件可见数据
componentPropertyReferences map<string, string> 组件属性引用映射
boundVariables(绑定变量) map<string, variableAlias> 变量映射
explicitVariableModes map<string, string> 显式变量模式映射
节点类型属性

不同类型节点的专属属性,按类型分组如下:

节点类型 属性名 类型 描述 备注
DOCUMENT children Node[] 文档下的画布数组 -
CANVAS children Node[] 画布顶层图层数组 -
backgroundColor Color 画布背景色 -
flowStartingPoints FlowStartingPoint[] 原型 flow 起点数组 -
prototypeDevice PrototypeDevice 查看原型属性的设备 -
exportSettings ExportSetting[] 画布导出设置 -
FRAME children Node[] 直接子节点数组 -
locked Boolean 图层是否锁定 -
fills Paint[] 节点填充样式 定义内部颜色/纹理
strokes Paint[] 节点描边样式 勾勒图形轮廓
strokeWeight number 描边权重 -
strokeAlign string 描边相对轮廓位置 INSIDE/OUTSIDE/CENTER
SECTION children Node[] 子节点数组 -
sectionContentsHidden Boolean 内容是否可见 -
devStatus DevStatus 开发状态标记 -
fills Paint[] 填充样式 -
strokes Paint[] 描边样式
VECTOR locked Boolean 图层是否锁定 -
exportSettings ExportSetting[] 节点导出设置 -
layoutAlign String 父级反向轴拉伸设置 仅自动布局直接子级可用
BOOLEAN_OPERATION children Node[] 子节点数组 含 VECTOR 属性
booleanOperation String 布尔运算类型(UNION 等) -
STAR/LINE/REGULAR_POLYGON - - - 属性与 VECTOR 相同
RECTANGLE cornerRadius Number 统一圆角半径 含 VECTOR 所有属性
rectangleCornerRadii Number[] 四个角独立半径 -
cornerSmoothing Number 圆角平滑度(0-1) -
TEXT characters String 文本内容 含 VECTOR 部分属性
style TypeStyle 文本样式(字体、粗细等) -
GROUP/TRANSFORM_GROUP - - - 属性与 FRAME 相同

2.2.4 节点矩形化

节点矩形化是 nodesToJSON 方法的核心辅助逻辑,贯穿 「初步预处理」「节点类型转换」 两大环节,核心目的是统一节点结构、消除 Figma 原生节点兼容性问题,为后续流程提供规范支撑。其核心价值是:统一容器类型、前置规范布局以支撑 2.4 节布局优化、衔接全转换流程,保障 AltNodes 及后续代码生成顺畅。

核心转换规则
  1. 背景矩形转换:将背景用途矩形节点转为 Frame 容器并嵌套关联子元素,与 GROUP 转 FRAME 并列,统一容器类型。
  2. 对齐元素转换:识别垂直/水平对齐多元素,转为 AutoLayout 规范布局,为 2.4 节布局优化的 AutoLayout 检测奠定基础。
完整转换流程

开始

转换为增强节点 AltNodes

矩形承载节点判断

group 转换为 frame

自动布局检测

结束

流程步骤解读
  1. 转换为 AltNodes:轻量封装原生节点,解决不可测试、修改污染问题,提升扩展性。
  2. 矩形承载节点判断:筛选背景用途矩形,转为 Frame 容器并嵌套子元素,统一容器结构。
  3. GROUP 转 FRAME:核心操作,分别在 nodesToJSON 初步预处理、processNodePair 类型转换中落地,将不兼容节点转为 Frame,保障后续处理顺畅。
  4. 自动布局检测:识别对齐多元素,启用 AutoLayout 规范布局,为后续 Flexbox 转换铺垫。

2.3 中间表示层 IR(AltNodes)解析

中间表示层 IR(AltNodes)是 Figma 原生节点与目标代码的核心桥梁,核心作用是对原生节点进行属性标准化、结构优化,生成统一可扩展的节点表示,为多端代码生成提供一致数据源,解决原生节点属性繁杂、适配性差的问题。

2.3.1 AltNode 核心类型定义

AltNode 是中间表示层的基础单元,明确节点核心属性,兼顾层级、布局与扩展需求,核心定义如下:

interface AltNode {
  id: string; // 节点唯一标识(继承 Figma 原生 ID)
  name: string; // 节点名称(与 Figma 原生一致)
  type: string; // 标准化节点类型(FRAME/TEXT/VECTOR 等)
  cumulativeRotation: number; // 累积旋转角度(修正定位偏差)
  uniqueName: string; // 唯一名称(避免代码命名冲突)
  canBeFlattened: boolean; // 是否可扁平化为 SVG(图标优化)
  isRelative: boolean; // 是否启用相对定位(适配布局)
  width: number; // 标准化宽度
  height: number; // 标准化高度
  x: number; // 相对父节点 X 坐标
  y: number; // 相对父节点 Y 坐标
  parent?: AltNode; // 父节点引用(明确层级)
  svg?: string; // 可选,图标节点 SVG 内容
  base64?: string; // 可选,图片 Base64 编码
  colorVariableMappings?: Map<string, string>; // 可选,颜色变量映射(主题化)
}

2.3.2 AltNodes 核心作用

AltNodes 核心解决原生节点与目标代码的适配问题,通过标准化、层级梳理、功能扩展为代码生成提供支撑,具体作用如下:

核心作用 详细说明
明确层级关系 通过 parent 属性绑定父节点,支撑布局计算与属性继承,避免层级混乱。
标准化尺寸位置 基于原生节点绝对边界框,计算标准化相对尺寸与位置,消除父节点旋转偏差。
统一文本样式 解析富文本样式并规范,确保多端渲染样式精准一致。
预处理颜色变量 标准化节点颜色、收集颜色变量映射,支撑多端主题化配置,提升可维护性。
优化 SVG 导出 标记可扁平化为 SVG 的节点(主要为图标),提升渲染效率,适配代码生成需求。

2.3.3 AltNodes 核心价值与优势

核心价值:解决 Figma 原生节点适配性、可扩展性弱的问题,核心优势如下:

核心优势 详细说明
灵活性强 脱离 Figma 环境独立处理,支持自定义扩展,适配 React/Flutter 等不同框架代码生成需求。
便于测试调试 无需依赖 Figma 客户端,可直接基于 AltNodes 测试,降低调试成本、提升效率。
支持个性化配置 添加 uniqueName 等自定义属性,解决原生节点命名冲突、属性缺失问题。

2.3.4 AltNodes 实操示例

实操示例 1:图标组件 AltNode(适配多端图标渲染)

{
  "id": "456:789",
  "name": "Icon",
  "uniqueName": "icon",
  "type": "VECTOR",
  "canBeFlattened": true,
  "svg": "<svg width=\"24\" height=\"24\">...</svg>",
  "width": 24, "height": 24,
  "x": 0, "y": 0,
  "cumulativeRotation": 0
}

关键解读:统一 24×24 尺寸适配多端规范,canBeFlattened 标记便于 SVG 导出,svg 属性直接提供渲染内容,可快速生成图标组件。

实操示例 2:复杂布局容器 AltNode(支撑多端复杂布局代码生成)

{
  "id": "789:101", "name": "CardContainer", "uniqueName": "card_container",
  "type": "FRAME", "width": 320, "height": 200, "x": 0, "y": 0,
  "cumulativeRotation": 0, "layoutMode": "NONE", "isRelative": true,
  "paddingLeft": 20, "paddingRight": 20, "paddingTop": 16, "paddingBottom": 16,
  "children": [
    {
      "id": "567:890", "name": "Title", "uniqueName": "card_title", "type": "TEXT",
      "width": 280, "height": 24, "x": 0, "y": 0, "characters": "Card Title", "fontSize": 18
    },
    {
      "id": "567:891", "name": "Content", "uniqueName": "card_content", "type": "TEXT",
      "width": 280, "height": 60, "x": 0, "y": 32, "characters": "This is the card content...", "fontSize": 14
    }
  ]
}

2.4 布局优化机制

2.4.1 布局计算核心流程

布局优化的核心是 AutoLayout 检测与 Flexbox 转换,核心依赖 optimizeLayout 方法(对应 2.1 节核心流程),该方法接收标准化后的 AltNodes 与插件配置,识别 Figma 原生布局模式(含 2.2.4 节节点矩形化初步规范的 AutoLayout 布局),转换为多框架兼容的标准布局,核心检测逻辑如下:

// 检测 AutoLayout 模式,转换为 Flexbox 布局
if (node.layoutMode === "HORIZONTAL" || node.layoutMode === "VERTICAL") {
  setFlexboxProperties(node); // 同步处理对齐、间距等属性
}

2.4.2 布局模式识别与转换策略

框架自动识别 3 种 Figma 节点布局模式,对应不同转换策略,保障多框架布局兼容:

模式 说明
HORIZONTAL/VERTICAL 自动识别为 AutoLayout,转换为对应方向 Flexbox 布局
NONE 无布局模式,按绝对定位逻辑处理
混合模式 含绝对定位子元素,用 Stack/Box 容器包裹,保障布局正常

2.4.3 响应式约束转换规则

针对 Figma 节点 3 种约束类型,按规则转换为多框架兼容样式,实现响应式适配:

约束类型 转换规则
FILL 转换为 flex: 1(Flexbox)或 width: 100%(固定布局),实现父容器填充
HUG 转换为 fit-content(Web 端)或 wrap_content(移动端),自适应内容尺寸
FIXED 保留固定尺寸,直接转换为对应框架固定宽高样式

2.4.4 布局优化详细流程图

HORIZONTAL

VERTICAL

NONE

无绝对定位

有绝对定位

存在

不存在

开始布局分析

检查 layoutMode 模式

设置 Flexbox:row

设置 Flexbox:column

检查子节点定位

处理对齐+间距

检查 inferredAutoLayout

相对定位容器(isRelative=true,用 Stack/Box)

推断布局方向,应用 AutoLayout

默认处理为普通容器

布局属性标准化(尺寸+约束转换)

最终布局输出

2.5 多框架代码生成机制

2.5.1 多框架适配器模式(核心逻辑)

框架采用适配器模式实现多框架代码生成,可灵活扩展,核心逻辑如下(通过配置切换框架,输出对应代码):

async function convertToCode(
  nodes: AltNode[],
  settings: PluginSettings
): Promise<string> {
  // 适配器模式:按框架配置调用对应生成函数
  switch (settings.framework) {
    case "Tailwind": return await tailwindMain(nodes, settings);
    case "Flutter": return await flutterMain(nodes, settings);
    case "SwiftUI": return await swiftuiMain(nodes, settings);
    case "HTML": return (await htmlMain(nodes, settings)).html;
  }
}

2.5.2 HTML 代码生成示例(实操参考)

以 HTML 代码生成(统一用 div,不使用组件)为例,核心流程为:初始化→节点遍历→类型判断→样式收集→代码生成,具体如下:

核心组件与流程说明

FRAME/COMPONENT

RECTANGLE/ELLIPSE

TEXT

其他类型

初始化设置

遍历节点

convertNode 节点类型判断

htmlFrame()

htmlContainer()

htmlText()

特殊处理

HtmlDefaultBuilder

HtmlTextBuilder

样式收集(cssCollection 全局变量)

代码生成(按模式输出)

组件 说明
HtmlDefaultBuilder 通用样式处理核心,解析节点位置、尺寸、颜色等样式,按配置生成对应输出格式
样式收集机制 通过cssCollection全局变量统一收集样式,支持 3 种模式:
- html:内联样式(嵌入 div)
- styled-component:收集至独立组件
- jsx:React 内联样式格式
节点类型对应处理规则
节点类型 处理函数 构建器
TEXT(文本节点) htmlText() HtmlTextBuilder
FRAME/COMPONENT/INSTANCE htmlFrame() HtmlDefaultBuilder
RECTANGLE/ELLIPSE htmlContainer() HtmlDefaultBuilder

三、框架总结与核心梳理

框架核心优势:FigmaToCode 具备五大核心优势,支撑设计到代码的高效转换:

  • 四阶段转换:采用节点转换→IR生成→布局优化→代码生成的完整流程,确保转换逻辑规范、高效;
  • 中间表示层:通过 AltNodes 自定义虚拟节点格式,为节点操作提供灵活的扩展空间,解决原生节点的使用局限;
  • 多框架支持:兼容 HTML、React、Flutter、SwiftUI 等多种主流技术框架,适配不同开发需求;
  • 布局优化:具备 AutoLayout 自动检测、响应式约束处理能力,保障生成布局的兼容性和规范性;
  • 智能处理:支持节点矩形化、SVG 扁平化、颜色变量处理等智能操作,提升代码生成质量。

3.1 框架分层技术架构

框架采用分层架构设计,解耦各环节逻辑,提升可扩展性与可维护性,各层内容:

层次 内容
节点转换层 Figma原生节点 → JSON_REST_V1格式 → AltNodes(中间表示层)
中间表示层 自定义虚拟节点格式(AltNodes),提供灵活操作与扩展能力
布局优化层 AutoLayout检测、响应式约束处理、节点矩形化等优化操作
代码生成层 多框架适配器,支持HTML、React、Flutter、SwiftUI、Svelte等代码生成

3.2 核心设计模式解析

框架核心设计模式,提升可扩展性与可维护性,具体如下:

模式 说明
适配器模式 应用于多框架代码生成,新增框架仅需添加适配器,无需修改核心逻辑
构建器模式 用于代码生成,通过不同构建器规范生成逻辑,适配不同输出格式
中间表示模式 通过AltNodes解耦Figma原生节点与代码生成逻辑,提升灵活性与可测试性

四、附录(相关资源)

  • FigmaToCode 开源项目:FigmaToCode GitHub(含项目构建、开发流程等完整文档)
  • Figma REST API 文档:Figma REST API(详细说明API调用、节点获取等核心能力)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐