Figma の SVG アイコンと GitHub リポジトリを自動同期する
この記事は ZOZO Advent Calendar 2021 の 20 日目の記事です。
はじめに
こんにちは、田嶋です。この記事は ZOZO のアドカレの記事2本目です。最近はポケモンと自作PCのセットアップに勤しんでいます。フロントエンドエンジニア全然できてません。
前提
今回は Figma と GitHub リポジトリ の SVG アイコンを自動で同期させ、アイコン管理を楽にしちゃおうという記事です。
タイトルでは自動同期と言ってますが、Figma が変更されたかどうかの検知ではなく cron での定期実行でリポジトリを Figma の最新に合わせるすることで、自動同期を実現しています。
こちらの記事が大変参考になりました。GitHub か GitLab かの違いなのでもうほぼ二番煎じです。
この記事で述べられている Github Action の figma-action ですが、現在はメンテされておらずアーカイブされていました。一応自分でも使ってみましたが上手く動かないようでした。
方法
実現方法について簡単に説明します。
1. Figma API を叩けるようにする
Figma Developers で API を確認することができます。
Figma のファイルは node
と呼ばれる木構造で構成されています。 node は node.type
で RECTANGLE
や COMPONENT
など判別することができます。今回使用する Figma ファイルは下図のレイアウトです。今回は Page1
の node に 背景に使っている Rectangle 1
と Icon のコンポーネントが複数あるという構成で、フレームにしていないため Icon は Rectangle の子ではなく兄弟です。
2. Node.js で SVG をダウンロードしてくる CLI を作成する
Figma の API では子要素以下のファイルを直接ダウンロードする方法がないため、以下の階構成にしました。
- Icon を構成している node の
id
name
を取得 id
を使用し画像取得用 API を叩き画像URL を取得fs
を使用しローカルに画像をダウンロード
以下がコードです。
require("dotenv").config(); const fetch = require("node-fetch"); const fs = require("fs"); const baseUrl = "https://api.figma.com/v1/"; const figmaToken = process.env.FIGMA_TOKEN; const fileId = "YhHWg9mZ6GdKkseHAAS1gw"; // Figma ファイルの API から component の ID を取得 const getComponentIds = async () => { try { const res = await fetch(`${baseUrl}files/${fileId}`, { headers: { "X-Figma-Token": figmaToken, }, }); const data = await res.json(); const { components } = data; return components; } catch (error) { throw error; } }; // Id から画像の URL を取得 const getImageLinks = async (component) => { try { const componentKeys = Object.keys(component).join(); const res = await fetch( `${baseUrl}images/${fileId}?ids=${componentKeys}&format=svg`, { headers: { "X-Figma-Token": figmaToken, }, } ); const data = await res.json(); const images = Object.keys(component).map((key) => { const { name } = component[key]; const link = data.images[key]; return { name, link }; }); return images; } catch (error) { throw error; } }; // ローカルに画像を保存 const downloadImages = async ({ link, name }) => { const res = await fetch(link); const data = await res.buffer(); fs.writeFileSync(`../src/${name}.svg`, data); }; const main = async () => { const component = await getComponentIds(); const images = await getImageLinks(component); images.forEach(async (image) => { await downloadImages(image); }); }; main();
3. Github Actions で定期実行する
あとは Github Action で定期的に上記のコードを実行するだけです。猿でもできますね。(私は二時間くらいここで躓きました。)
説明できることが少ないためコードを載せておきます。
name: Export SVG from Figma on: schedule: cron: "0 0 * * *" jobs: actions: runs-on: ubuntu-latest env: FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }} steps: - name: checkout uses: actions/checkout@v2 - name: node setup uses: actions/setup-node@v2 with: node-version: "12" - run: cd script; npm install - run: cd script; npm run start - name: Commit run: | git config --local user.email "github_actions@example.com" git config --local user.name "GitHub Actions" git add . git commit -m "downloaded from Figma" - name: Push changes uses: ad-m/github-push-action@master with: github_token: ${{ secrets.TOKEN }}` branch: master
GitHub Action の schedule は UTC なためこちらじゃ JST の 9:00 に実行されます。あえて 0:00 (UTC) にしたのは起きている時間のほうがバグった時に対応できるからと思たという言い訳です。
まとめ
作成したコードはこちらになります。
今回は簡単な Figma ファイルで試したためもっと複雑な要求に対応するためにはもう少し改良を加える必要があります。例えば Solid
Outline
のアイコンはそれぞれ別に管理したいなど。しかし適切な API とドキュメントが提供されているため改良は容易にできそうです。
また curl 芸人ではないため、今回は Node で画像をダウンロードするスクリプトを書きましたが、 Github Actions で完結する方法もあります。
最後に
アドカレ2本目を書くことにあたって実は他に以下の二つのネタを用意していました。
しかし 1 はあまりに複雑で簡単にできなさそうだなと諦めたのと、 2 は Beta 版なため Figma の Organization プランでしかつ買うことができず、個人では契約することができなかったので諦めて前から気になっていたこちらをやってみることにしました。
私の所属している部署ではデザインツールは XD が使用されていますがこうしてアドカレで Figma の利便性を訴え布教をしていきたいです。
参考にした資料
no such file or directory, open の理由を知る - Qiita
https://www.figma.com/developers/api