从零开发设计稿转代码插件(一)

从今天开始开个新的专栏,从零开始开发一个 figma design to code 插件。

阅读并且实操完本系列文章,你会

  • 对 figma 设计工具有深入的理解,甚至可能会比你们公司 ui 同学理解的还要深刻
  • 熟悉代码生成原理,自己也能够写出一个效果不错的插件
  • 对页面布局有了新的认知(比如不用 margin),大大提升你写 html 的速度和还原度

开发 figma 插件需要使用 figma 客户端。我们打开 figma 客户端,新建设计文件,然后点击顶部栏的 Plugins -> Development -> New Plugin

然后选择 Figma design,输入插件名字,点击确定

选择 Custom UI

将代码保存到本地,用你的编辑器打开,然后跟随readme 的指引运行项目

css 复制代码
npm install -g typescript
npm install --save-dev @figma/plugin-typings
npm run watch

这样项目就跑起来了

之后打开 figma 客户端运行你的插件

点击 create 之后会生成五个黄色的矩形

看下代码目录结构,我就说几个重要

manifest.json是插件描述文件,里面包含插件的 name,id,ui和 mian,ui 就是弹窗里面展示的 ui。main 是运行在沙盒环境的代码,里面应该是你主要的业务逻辑。他们通过 postMessage 通信

json 复制代码
{
  "name": "my-first-plugin",
  "id": "1482330158480649678",
  "api": "1.0.0",
  "main": "code.js",
  "capabilities": [],
  "enableProposedApi": false,
  "documentAccess": "dynamic-page",
  "editorType": [
    "figma"
  ],
  "ui": "ui.html",
  "networkAccess": {
    "allowedDomains": [
      "none"
    ]
  }
}

ui.html

html 复制代码
<h2>Rectangle Creator</h2>
<p>Count: <input id="count" type="number" value="5"></p>
<button id="create">Create</button>
<button id="cancel">Cancel</button>
<script>

document.getElementById('create').onclick = () => {
  const textbox = document.getElementById('count');
  const count = parseInt(textbox.value, 10);
  parent.postMessage({ pluginMessage: { type: 'create-shapes', count } }, '*')
}

document.getElementById('cancel').onclick = () => {
  parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*')
}

</script>

code.ts

ts 复制代码
figma.showUI(__html__);
figma.ui.onmessage =  (msg: {type: string, count: number}) => {
  if (msg.type === 'create-shapes') {
    const numberOfRectangles = msg.count;

    const nodes: SceneNode[] = [];
    for (let i = 0; i < numberOfRectangles; i++) {
      const rect = figma.createRectangle();
      rect.x = i * 150;
      rect.fills = [{ type: 'SOLID', color: { r: 1, g: 0.5, b: 0 } }];
      figma.currentPage.appendChild(rect);
      nodes.push(rect);
    }
    figma.currentPage.selection = nodes;
    figma.viewport.scrollAndZoomIntoView(nodes);
  }
  figma.closePlugin();
};

看完代码现在就产生了一个问题,就是他们提供的代码实在是太古老了,过于刀耕火种了🔪⛏️🔥🌱,所以我来基于 react、vite 、ts 改造一下。

大概分享一下我的改造过程

  1. 在根目录直接npm create vite@latest

  2. 再给文件移出来🐶

  3. 创建 vite.ui.config.ts,用于build react 代码,使用viteSingleFile插件把代码都打包到 html 中

  4. 创建 vite.plugin.config.ts 用于 build 核心代码

  5. 修改 watch 命令

    json 复制代码
    "watch": "run-p watch:*",
    "watch:ui": "npm run build:ui -- --watch",
    "watch:plugin": "npm run build:plugin -- --watch",
    "build:ui": "vite build --config vite.ui.config.ts",
    "build:plugin": "vite build --config vite.plugin.config.ts"Ï

然后这个模板就完成了🎉

我给放到了 github 上,懒得自己折腾的小伙伴可以直接 clone 到本地直接跑 github.com/alpacachen/...

(readme 全是 ai 写的)

bash 复制代码
figma-react-template/
├── dist/                   # 构建输出
├── src/
│   ├── plugin/             # 插件代码(在 Figma 中运行)
│   │   └── index.ts        # 主插件代码
│   └── ui/                 # UI 代码(在 WebView 中运行)
│       ├── app/
│       │   ├── app.tsx     # 主 React 组件
│       │   ├── app.css     # 样式
│       │   └── main.tsx    # React 入口点
│       ├── index.html      # HTML 模板
│       └── vite-env.d.ts   # Vite 环境类型
├── .gitignore
├── eslint.config.js        # ESLint 配置
├── manifest.json           # Figma 插件清单
├── package.json            # 项目依赖和脚本
├── tsconfig.json           # TypeScript 配置
├── tsconfig.app.json       # 应用的 TypeScript 配置
├── tsconfig.node.json      # Node 的 TypeScript 配置
├── vite.plugin.config.ts   # 插件的 Vite 配置
└── vite.ui.config.ts       # UI 的 Vite 配置

现在前期准备弄完了,接下来真正开始

首先监听选中事件,可以让 ui.html知道选中了哪个图层,这样后面才好获取信息

ts 复制代码
// plugin.ts
figma.showUI(__html__);

figma.on('selectionchange', () => {
  const selection = figma.currentPage.selection;
  if (selection.length == 1) {
    const selectedNode = selection[0];
    // 将选中图层的坐标大小和类型全部发送给 ui
    const { x, y, width, height, type } = selectedNode;
    figma.ui.postMessage({
      x,
      y,
      width,
      height,
      type
    });
  }
});
ts 复制代码
// 在 app.ts中监听 message,然后打印出来
useEffect(() => {
    window.addEventListener('message', (event) => {
        console.log(event.data.pluginMessage);
   });
}, []);

然后测试一下

这样代码生成第一大步就完成了,因为代码生成说白了就是规则转化,把 figma 的字段转成 css 的属性。

本文到此结束,后面的章节会重点在 ui 界面的制作上,欢迎关注

相关推荐
AlienZHOU7 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc10 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师11 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen12 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒12 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow12 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林81812 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang8007812 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明12 小时前
第 6 章 组件进阶
前端·vue.js
江华森12 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端