Figmaファイルのページ構造を一括生成するプラグインをつくる
この記事はFigma Advent Calendar 2024の23日目の記事です。
今年はFigmaのプラグイン開発をやるぞ!と個人的に目標を立てており、無事にプラグインの制作実績を解除することができました。今回はその中でも、デザインシステムの一部としてFigmaファイルのページ構造を一括生成するプラグインをつくったので、その紹介をしたいと思います。
プラグインの紹介
プラグインの名前は「Figma Page Generator」です。Figmaファイルのページ構造を一括生成するプラグインです。
- ページ名を入力すると、その名前のページを生成します。改行を入れることで複数のページを一括生成することもできます。
- Figmaのライブラリで公開しているコンポーネントのKeyを指定すると、カバーページにそのコンポーネントを配置し、サムネイルとして自動的に設定できます。
プラグインの詳細は以下のリポジトリで公開していますので、興味があればぜひ試してみてください。
制作の背景
元々ページの構造を一括生成するために「Automator for Figma」というプラグインを使っていました。しかし、このプラグインは数年前に開発が終了してしまい、新しいFigmaプラグインの仕様に対応していませんでした。Automator for Figma自体はまだ使えるものの、いつサービスが終了してもおかしくはない…ということで、良い機会なので自分でプラグインを作ってみようと思ったのがきっかけです。
とはいえ、一人だとついつい先延ばしになってしまうため、社内のDesignOpsに力を入れている@fkchaaangさんが開催してくれた「Figmaのプラグインとウィジェット開発のハンズオン」に参加して、情報をキャッチアップしつつモチベーションを高める作戦を取りました。
使用したツール・フレームワーク
最初はFigma公式のプラグイン開発ドキュメントを元に進めていましたが、ハンズオンで教わったCreate Figma Pluginというツールを使うことで、プラグインの開発環境やUIの構築が簡単にできました。
ちなみにTypeScriptは、以前に「なんもわからん…」とつぶやいていたら知人のエンジニアである@rhirayamaaanさんがそれを拾って記事を書いてくれたので、それを参考に去年からコツコツと勉強していました。そのおかげで、業務でもフロントエンドエンジニアが一時的に不在だったときに残ったメンバーと協力してプロダクト開発を進められたうえに、今回のプラグイン開発でも無事にTypeScriptを使うことができました。本当にありがとうございます🙏
プラグインの設計
プラグインの設計は、以下のような流れで進めました。
- ページ名を入力すると、その名前のページを生成する
- ページ名に改行を入れることで、複数のページを一括生成する
- ページ名にコンポーネントのKeyを指定すると、カバーページにそのコンポーネントを配置し、サムネイルとして自動的に設定する
- プラグインの設定を保存しておき、次回以降も同じ設定でページを生成できるようにする
元々ページ生成に使っていたAutomator for Figma自体がAPIの挙動をGUIで設定できるようなプラグインだったので、動作のイメージがしやすかったのが地味に助かりました。わからないことがあれば、FigmaのAPIリファレンスを見ながら進めていきました。
苦労したこと
プラグインの開発自体はCreate Figma Pluginを使うことで比較的簡単に進められたのですが、途中いくつかの問題にぶつかりました。
---
の扱い
区切り線 FigmaのAPIでページを生成する際、ページ名に ---
や ***
と入力すると、自動的に区切り線に変換される機能があるのですが、これがAPIからの操作では当初うまくいかず、あれこれ試行錯誤しました。
結果、APIが対応していなかったことが原因だとわかって半ば諦めてかけていたところで、なんとちょうど良いタイミングでAPIの仕様が変更され、区切り線の扱いができるようになりました。これにより、ページ名に ---
や ***
を入力することで、区切り線を生成することができるようになりました。
カバー用コンポーネントのサムネイルを公開中のライブラリから取得する
公開中のFigmaライブラリからコンポーネントのKeyを指定し、そのコンポーネントをページに取得・配置するのはAutomator for Figmaでもできていたので、比較的すんなりと実装できました。
ただ、Automator for FigmaではVariantなしのコンポーネントを指定していたのに対し、今回はVariantありのコンポーネントを指定しようとしたところ、なぜかコンポーネントが取得できないという問題が発生しました。
これはコンポーネントのVariantの有無で使用するAPIが異なるのが原因でした。Variantがあるコンポーネントを取得する場合はComponentSetを取得した後、その中からVariantを取得することで、Variantありのコンポーネントを取得することができました。今回のプラグインではVarinatのあり・なしどちらにも対応したかったので、チェックボックスを用意してVariantの有無を選択できるようにしました。
let instance;
if (componentType === "variant") { // Variantありのコンポーネントを取得する場合
const componentSet = await figma.importComponentSetByKeyAsync(
componentKey
);
const component = componentSet.defaultVariant;
instance = component.createInstance();
} else { // Variantなしのコンポーネントを取得する場合
const component = await figma.importComponentByKeyAsync(
componentKey
);
instance = component.createInstance();
}
frame.appendChild(instance);
await figma.setFileThumbnailNodeAsync(frame);
プラグインの設定を保存する
FigmaではFigma独自のLocal Storageのような機能(figma.clientStorage)があり、これを使うことでプラグインの設定を保存することができます。
さらに、Create Figma Pluginが提供している saveSettingsAsync / loadSettingsAsync という関数を使うことで、よりかんたんにプラグインの設定を保存・読み込むことができる…はずなのですが、これが何度試してもうまくいかず困りました。
結局は、Figmaが元々提供しているfigma.clientStorageを使ってプラグインの設定を保存することで解決しましたが、Create Figma Pluginの関数が使えなかったことが残念でした。解決できないのも悔しいので、ここはハンズオンの集まりで後日相談してみようかなと思います。
function saveSettings(
pages: string,
componentKey: string,
coverPageName: string,
isVariant: boolean
) {
figma.clientStorage.setAsync("pages", pages);
figma.clientStorage.setAsync("componentKey", componentKey);
figma.clientStorage.setAsync("coverPageName", coverPageName);
figma.clientStorage.setAsync("isVariant", isVariant);
}
async function loadSettings() {
const pages = await figma.clientStorage.getAsync("pages");
const componentKey = await figma.clientStorage.getAsync("componentKey");
const coverPageName = await figma.clientStorage.getAsync("coverPageName");
const isVariant = await figma.clientStorage.getAsync("isVariant");
return { pages, componentKey, coverPageName, isVariant };
}
まとめ
Create Figma Pluginを使うことで比較的簡単に開発環境を構築する方法もわかり、いつ動かなくなるか内心ヒヤヒヤしていたAutomator for Figmaに代わるプラグインを作ることができたので、個人的にはとても満足しています。
時間があれば、複数のページ設定を保存したり、設定をインポート・エクスポートできるようにできたらいいなと思っています(が、時間はあまりないのでどうなることやら…)。
今回のプラグインはいったん社内で使ってみて、問題がなければせっかくなので公開もチャレンジしてみようと野望を抱いています。公開できたら、また改めてどこかで紹介できれば!
Discussion