見出し画像

Figma REST APIを使ってアイコンの書き出しを自動化する

こんにちは。私は普段はUIデザイナーとしてデザイン業務を行っています。

社内には複数のプロダクトが存在し、それぞれプロジェクトチームがあり、
デザイナーもエンジニアもメンバーが異なります。

ただし、社内のプロダクトの為一定のデザイン基調は合わせる必要がありますが、スケジュールがタイトなこともあり、細かな違いが出ることは多いです。

具体的に言うと、プロダクト横断して共通のボタンが、プロダクトやプラットフォーム(iOS、Android、Web)などでデザインが(色、スペース…など)違ってしまっていたりします。

また、同じアイコンにもかかわらずプロダクト毎に書き出している為、書き出し形式が異なっていたり、後からアイコンを差し替える場合、「プロダクト×プラットフォーム」分の対応が必要となり、なかなか大変です。

そこでこのようなデザイントークンと呼ばれるようなものを、共通化できなかと思い、まずはアイコンライブラリを作成してみようと仕組みだけ調べてみました。

まだ調べ途中なところもあり、文末の参考リンクのほうがわかりやすいと思います。

ゴールのイメージ

イメージとしてはこちらです。

  1. GitHub ActionsなどのCIから、Figmaのcomponentを取得

  2. 取得したcomponentをSVGファイルとして生成

  3. 差分があればPull Requestを出す

といった流れです。

Figma REST APIを使ってみる

それでは、FigmaのREST APIを使って画像を取り出してみたいと思います。

アクセストークンを取得

まずはアクセストークンを取得します。
「メニュー > Help and account > Account setting」 からPersonal access tokensから作成することができます。
作成したアクセストークンは1度しか表示されないのでコピーしておく必要があります。

メニュー
アクセストークン

APIを使ってみる

こちらを参考にAPIをリクエストしてみます。

まずはファイル情報をすべて取得してみます。

curl -H 'X-FIGMA-TOKEN: <personal access token>' 'https://api.figma.com/v1/files/:file_key'

リクエスト用のフォームが用意されているので、動きを確かめるにはこちらが手軽かもしれません。

先ほど作成した、アクセストークンとfile_keyを入力するとリクエスト用のcurlコマンドが作成されます。

file_keyはFigmaのファイルのリンク用のURLから取得します。

https://www.figma.com/design/{file_key}/{file名}?node-id=0-1

レスポンスの内容も画面内で見ることができます。


component一覧を取得してみる

以下で取得できます。
ただし、ライブラリをパブリッシュする必要があるので注意!
※ライブラリのパブリッシュは有料版のみ利用できます

https://api.figma.com/v1/files/{file_key}/components

レスポンスはこんな感じです。

{
    "error": false,
    "status": 200,
    "meta": {
        "components": [
            {
                "key": "315a....",
                "file_key": "F2l...",
                "node_id": "2:53",
                "thumbnail_url": "https://s3-alpha.figma.com/checkpoints/...",
                "name": "componentName",
                "description": "",
                "description_rt": "",
                "created_at": "2024-06-28T06:58:03.228Z",
                "updated_at": "2024-06-28T06:58:03.228Z",
                "containing_frame": {
                    "pageId": "0:1",
                    "pageName": "Page 1"
                },
                "user": {
                    "id": "125...",
                    "handle": "userName",
                    "img_url": "https://s3-alpha.figma.com/profile/..."
                }
            },
            ...省略
      ]
    },
    "i18n": null
}   

SVGファイルを取得する

以下で特定のnodeを画像として取得できます。

https://api.figma.com/v1/images/{file_key}?ids=${ids}

idsは、以下のようにnode_idを「, 」で区切った文字列として設定します。

https://api.figma.com/v1/images/{file_key}?ids=1:2,1:3,1:4

公式のドキュメントを見るとパラメータがわかりやすいです。

他にも色々あります。

パラメータ一覧

取得したSVGをファイルとしてダウンロードする

取得したSVG画像をファイルとしてダウンロードできるようにします。
現状のファイル構成としてはこんな感じ。

.
├── figma.js
├── node_modules
├── package-lock.json
└── package.json

準備

最終的にはCIで実行できるようにしたいので、コマンドを準備します。
package.jsonに実行用のscriptを追加。

  "scripts": {
    "build:assets": "node ./figma.js"
  },

npm modulesを読み込む際にimportを利用したいので、package.jsonに"type": "module",を追加。

{
  "name": "figma",
  "version": "1.0.0",
  "description": "",
  "main": "figma.js",
  "type": "module",  // 追加

メインコード

実行するコードはこんな感じです。

◎figma.js

import fetch from "node-fetch";
import path from "path";
import { fileURLToPath } from "url";
import fs from "fs";
import * as dotenv from "dotenv";
dotenv.config();

const FIGMA_FILE_KEY = process.env.FIGMA_FILE_KEY;
const FIGMA_TOKEN = process.env.FIGMA_TOKEN;
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const download = async (url, path) => {
  const res = await fetch(url);
  const data = await res.text();
  fs.writeFileSync(path, data);
};

const getComponents = async () => {
  try {
    const res = await fetch(
      `https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/components`,
      {
        headers: {
          "X-FIGMA-TOKEN": FIGMA_TOKEN,
        },
        responseType: "json",
      }
    );
    const body = await res.json();
    return body.meta.components;
  } catch (error) {
    throw error;
  }
};

const getSvgImages = async (ids) => {
  const res = await fetch(
    `https://api.figma.com/v1/images/${FIGMA_FILE_KEY}?ids=${ids}&format=svg`,
    {
      headers: {
        "X-FIGMA-TOKEN": FIGMA_TOKEN,
      },
      responseType: "json",
    }
  );
  const images = await res.json();
  return images;
};

async function main() {
  // ディレクトリを削除して初期化
  await fs.promises.rm(`${__dirname}/assets`, { recursive: true, force: true });
  // ディレクトリを作成
  await fs.promises.mkdir(`${__dirname}/assets`, { recursive: true });
  // コンポーネントを取得
  const components = await getComponents();
  // 画像を取得
  const ids = components.map((r) => r.node_id).join(",");
  const { images } = await getSvgImages(ids);

  // 画像をダウンロード
  const nodeIds = Object.keys(images);
  nodeIds.forEach(async (nodeId) => {
    const url = images[nodeId];
    const component = components.find((r) => r.node_id === nodeId);
    const name = component.name;
    const filePath = `${__dirname}/assets/${name}.svg`;
    await download(url, filePath);
  });
}

main();

◎Figma

以下のようにアイコンをcomponent化の上、ライブラリをパブリッシュします。

実行する

figma.js直下で、npm run build:assets実行すると、実行環境直下にassetsディレクトリが作成されて、Figma内のcomponentがSVGファイルとしてダウンロードされます。

.
├── assets // ← 作成される
│   ├── Ellipse.svg
│   ├── Rectangle.svg
│   └── Star.svg
├── figma.js
├── node_modules
├── package-lock.json
└── package.json

GitHub actionsでPRを作成する

FigmaのREST API経由で生成したSVGファイルを、CIで自動化したいと思います。
※参考にしたサイトは文末に記載していますが、そちらを見たほうがわかりやすいかもしれません。

GitHub actionsからworkflowを作成する

GitHub actionsは.github/workflows/ 配下にyamlファイルを作成します。
GitHub上で作成するには「Actions」タブから行います。

実行するコードはこちら。

name: Update Icon

on: [workflow_dispatch]

jobs:
  update-icon:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: "20.x"
      - name: Install
        run: npm ci
      - name: Update Icon
        run: FIGMA_TOKEN=${{ secrets.FIGMA_TOKEN }} FIGMA_FILE_KEY=${{ secrets.FIGMA_FILE_KEY }} npm run build:asset
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v6
        with:
          token: ${{ secrets.REPO_ACCESS_TOKEN }}
          commit-message: "feat: update icons"
          committer: GitHub <noreply@github.com>
          author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
          branch: feat/update-icons
          branch-suffix: timestamp
          delete-branch: true
          title: "feat: update icons"
          body: Icons has been updated

何をしているか簡単に説明すると、

  1. ヘッドブランチをチェックアウト

  2. Figma APIでSVGファイルを生成

  3. Pull Requestを作成する

GitHubシークレットを利用してトークンを管理

表に出せないトークン情報などは、Actions secrets and variablesを利用します。
Settings > Secreats and variables >Actions から登録できます。

登録した変数は以下のように利用します。

${{ secrets.FIGMA_TOKEN }} 

workflowを実行

登録したworkflowを実行します。 実行のトリガーをon: [workflow_dispatch] としているので、取り合えすgithub上から実行します。
Actionsの「Run workflow」を押します。

処理が実行されて、問題なければ緑のチェックマークがつき、Pull Requestが作成されます。

まとめ

とりあえずSVGファイルをCI上で生成してプルリクエスト出すところまで来ました。
残りの課題は以下になります。こちらも追々検討したいと思います。

  • SVGのままだと使えないので各プラットフォームで利用できるように変換すること

  • プロダクトからどのように取得するか


参考

大変参考になりました。


この記事が気に入ったらサポートをしてみませんか?