🔌

Figma プラグインの作り方

2020/10/21に公開

リアルタイムコラボレーションデザインツール Figma のプラグインの作り方について解説します。なお、公式ドキュメント (英語) は https://www.figma.com/plugin-docs/ にあります。とても体系的に整備されていてわかりやすいが、やはり英語ということもあり、二の足を踏んでいる方も多いかも知れません。本記事はなるべく 簡潔に、汎用的に、手順どおりに 解説していきます。少しでも日本人開発者が増えればと思います。

Figma とは

デザインツールとして XD や Sketch とよく比較されますが、両者と違い Figma はウェブベース (ブラウザ上で使えること) 、リアルタイムコラボレーションに重点を置いて開発されています。ウェブベースですが、デスクトップアプリもあります。プラグインの開発にはデスクトップアプリが必須です。ウェブベースなので、プラグインは基本的に JavaScript、HTML、CSS で開発することになります。ウェブ開発者が存分に力を発揮できます。

まず宣伝

Japanese Dummy Text Cover Art

Japanese Dummy Text というプラグインを作りましたので、日本語を使ったデザインでぜひご活用ください。文字数指定、テキストボックスのサイズに合わせて自動生成ができます。

事前準備

Figma デスクトップアプリ

プラグインの開発にはデスクトップアプリを使う必要があります。https://www.figma.com/downloads/ からダウンロードできます。

すでにインストール済みの場合は、必ず最新バージョンにアップデートしておいてください。

エディタ

使い慣れたものでかまいませんが、TypeScript を使うなら Visual Studio CodeIntelliJ IDEA あたりがおすすめです。

Node.js と npm

HTML と JavaScript のみで開発できなくもないが、公式推奨の TypeScript を使う場合は Node.js と npm が必要です。https://nodejs.org/en/download/ からダウンロードできます。もちろん npm の代わりに yarn を使っても大丈夫です。

テンプレートからプラグインを生成

Create your own plugin の手順

Figma デスクトップアプリを開き、[アカウント名] > [Plugins] > [Create your own plugin +] をクリックすると、「Create a plugin」というモーダルが出てきます。

Create a plugin モーダル

名前をつけて [Continue ->] をクリックして、次の画面でテンプレートを選択します。名前はプラグインの表示名、生成されるフォルダ名、package.jsonname に自動的に利用されますが、あとで変更することはできます。

テンプレートの選択

プラグインテンプレート選択画面

テンプレートは3種類選べますが、初めて開発する場合は「With UI & browser APIs」がおすすめです。「Empty」は manifest.json (プラグインの必須ファイル) とメインのスクリプトファイルのみが生成されます。「Run once」は UI (プラグインを起動したときに立ち上がる小さいウィンドウ) を必要としない、即実行するプラグインのテンプレートです。「With UI & browser APIs」と「Run once」は TypeScript を前提としていて、「Empty」は完全に自由です。

プラグインの保存・アンインストール

プラグイン読み込み済み

[Save as…] をクリックして任意の場所に保存すると、プラグインが読み込まれた状態になります。ローカルのプラグインファイルを移動・削除するとエラーになりますのでご注意ください。プラグイン右の [・・・] > [Remove…] をクリックするとプラグインをアンインストールすることができます (ローカルのファイルは削除されません) 。

ローカルプラグインの再インストール

ローカルプラグインの再インストール方法

Create a plugin」モーダルの「Link existing plugin」部分をクリックしてプラグインの manifest.json ファイルを選択すれば、再度プラグインを読み込むことができます。

プラグインのファイル構成

manifest.json

プラグインのメタ情報を記述する必須ファイル。プラグイン生成すると自動的に簡単な manifest.json が作成されます。

例:

manifest.json
{
  "name": "Example",
  "id": "737805260747778092",
  "api": "1.0.0",
  "main": "code.js",
  "ui": "ui.html"
}

name: string (必須)

メニューなどに表示されるプラグインの名前。

id: string (任意)

プログラム上必須ではないが、プラグイン生成すると自動的に付与されますし、設定せずにプラグイン公開する際も自動付与されますので、ほぼ必須と思ってもいいでしょう。

また、setPluginData などの API を利用する場合は必須になります。

api: string (必須)

Figma API のバージョン。最新版の利用が推奨されています。おそらくプラグイン生成で最新のバージョン番号が自動的に入ると思います。

main: string (必須)

メインの JavaScript コードへの相対パス。

ui: string | {[key: string]: string} (任意)

UI の HTML ファイルを指定します。figma.showUI で利用できます。

  • 単一画面の場合はファイルへの相対パスの文字列を記述します。定数 __html__ として利用できます。
    code.ts
    figma.showUI(__html__)
    
  • 画面が複数ある場合は下記のように map オブジェクトを指定します。
    manifest.json
    "ui": {
      "main": "main.html",
      "sub": "sub.html"
    }
    
    定数 __uiFiles__ として下記のように利用できます。
    code.ts
    figma.showUI(__uiFiles__.main)
    

その他

その他の詳細は公式 https://www.figma.com/plugin-docs/manifest/ をご覧ください。

code.ts

メインスクリプトのソースファイル。名前や配置は変更しても大丈夫ですが、変更後の manifest.json やコンパイルの設定にはご注意ください。

code.js

上記ソースファイルをコンパイルしてできた、Figma が実際に読み込むファイル。こちらも名前や配置は変更しても大丈夫ですが上記同様です。

ui.html

UI の HTML ファイル。名前や配置は変更しても大丈夫ですが同上です。基本的に UI で必要となる CSS と JavaScript はすべてこのファイルに記述する必要があるため、CSS は style タグかインライン CSS、JavaScript はインライン script を使うことになります。

<img src="..."><link href="..." rel="stylesheet"><script src="..."></script> のように、外部リソースを使えなくもないが、http://https:// で始まる URL でないといけないので、リソースをどこかのサーバにアップする必要があります。また、オフラインで利用できなくなります。

ですので、複雑な UI の場合は、Webpack や React などを利用して、最終的に1つの HTML ファイルにまとめるのをおすすめします。

package.json

プラグイン公開に利用されることはありませんが、開発を便利にするため後ほど npm-scripts を追記します。

tsconfig.json

TypeScript の設定ファイル。テンプレートから生成すると予め下記が記述されています。利用するには後述 Figma の型定義ファイルをインストールする必要があります。

tsconfig.json
"typeRoots": [
  "./node_modules/@types",
  "./node_modules/@figma"
]

README.md

開発を始める手順が記述されています。公式ドキュメント同様、Visual Studio Code のビルドタスク機能を利用する前提ですが、本記事ではエディタに依存しない方法を紹介します。

プラグイン公開には利用されません。公開時は別途プラグインの説明を記述することになります。

npm パッケージインストール・npm-scripts 追加

TypeScript と Figma の型定義ファイルをインストール

ターミナルを開いてプラグインフォルダ内で下記コマンドを実行します。

npm install -D typescript @figma/plugin-typings

公式ドキュメントではグローバルに TypeScript をインストールしますが、プロジェクト内にインストールしておくことをおすすめします。

npm-scripts に dev コマンドを追加

Visual Studio Code のビルドタスク機能ではなく、npm コマンドで TypeScript をコンパイルできるよう、scriptsdev コマンドを追加しておきます。ちなみに build コマンドは最初から入っていると思います。

package.json
"scripts": {
  "dev": "tsc -w",
  "build": "tsc -p tsconfig.json"
},

これで npm run dev を実行すると code.tscode.js にコンパイルします。さらに code.ts の変更を監視し、保存されるたびに code.js を再生成するようになります。

別環境・共同での開発

これで環境が変わっても、

npm i
npm run dev

だけですぐに開発を続けることができます。

プラグインの実行

下記コマンドを実行して code.ts をコンパイルし変更を監視しておきます。

npm run dev

Figma デスクトップアプリで適当なファイルを開き、[Menu] > [Plugins] > [Development] > [プラグイン名] でプラグインを起動します。[Create] をクリックすると、「Count」に入力された数のオレンジの正方形が作成されます。

サンプルプラグイン実行画面

変更を加えてみる

最初は [Create] をクリックするとプラグインの UI が閉じると思います。code.ts の32行目あたりの figma.closePlugin(); をコメントアウトして閉じないようにしてみます。

code.ts
// figma.closePlugin();

保存すると自動的にコンパイルされますので、⌥ option+⌘ command+P (Mac) / Ctrl+Alt+P (Windows) で最後に実行したプラグインを再度起動して [Create] をクリックしても、UI が閉じないようになっているはずです。

これでプラグイン開発の準備が整いました。あとは code.tsui.html などを編集していけばいいです。コードの変更を反映させるには上記のようにプラグインを起動しなおす必要があります。

デバッグ

[Plugins] > [Development] > [Open Console] をクリックするかショートカット ⌥ option+⌘ command+I で開発者ツールを開けば、ブラウザと同じようにデバッグできます。

プラグインがどのように動作しているのか

Figma プラグインがどのように動作しているかの図解

パフォーマンス向上のため、プラグインのメインコードは Figma のメインスレッドのサンドボックス内で実行されます。しかし、サンドボックス内は最小限の JavaScript 環境であり、XMLHttpRequest や DOM などのブラウザ API を直接利用できません。

一方、UI 側のコードは Figma の画面では iframe として出力され、ここでは任意の HTML、JavaScript を書いて、ブラウザ API にアクセスすることができます。

つまり、メインコードから Figma の「scene」(Figma ドキュメントを構成するレイヤーの階層) にはアクセスできますが、ブラウザ API にはアクセスできません。逆に、UI コードからブラウザ API にはアクセスできますが、Figma の「scene」にはアクセスできません。メインコードと UI 間では、postMessage でメッセージを送信し onmessage で受け取ることで通信することができます。

UI からメインコードへのメッセージ送信

UI からメインコードにメッセージを送るには、HTML に以下のように書きます:

ui.html
<script>
...
parent.postMessage({ pluginMessage: 'anything here' }, '*')
...
</script>

メインコードでメッセージを受け取るには、以下のように書きます:

code.ts
figma.ui.onmessage = (message) => {
  console.log("got this from the UI", message)
}

メインコードから UI へのメッセージ送信

メインコードから UI にメッセージを送るには、以下のように書きます:

code.ts
figma.ui.postMessage(42)

UI でメッセージを受け取るには、HTML に以下のように書きます:

ui.html
<script>
...
onmessage = (event) => {
  console.log("got this from the plugin code", event.data.pluginMessage)
}
...
</script>

上記の文字列や数値以外に、配列やオブジェクトなども送受信できます。

API ドキュメントとサンプルプラグイン

あとはこちらの API ドキュメントを参照しながら開発していくことになります。

また、公式が用意している サンプルプラグイン も参考になると思います。React、Vue、Webpack を利用したテンプレートも入っています。ただ、どれも少し古くなっているため、Figma の型定義の npm パッケージを利用するのではなく、型定義ファイル figma.d.ts を含めた構成になっています。

プラグイン公開

プラグイン公開手順

開発中プラグイン右の [・・・] > [Publish New Release…] をクリックすると、プラグインを Community に公開できます。「Publish Plugin」というモーダルが開きます。

プラグイン情報入力画面

必要情報を入力し、アイコンやカバーアートをアップロードして [Publish] をクリックすると、レビューに回されます。「Published」に「In Review」状態で表示されると思います。最長で1週間ほどかかるとのことですが、僕の場合は1週間かかりました。ただ、レビュー中でも自分だけはプラグインページにアクセスでき、インストールすることもできますので、インストールしてブラウザのほうでチェックしてみてもいいかも。

Tips

テキストレイヤー (TextNode) の変更は予めフォントを読み込む必要がある

テキストレイヤーの内容を変更する場合は、予め figma.loadFontAsync(fontname) のように、設定済みのフォントを読み込む、もしくは新たに設定する必要があります。

1つのテキストレイヤーにフォントが1つだけ設定されている場合は、下記のように読み込むことができます:

code.ts
figma.loadFontAsync(node.fontName)

1つのテキストレイヤーに複数のフォントが設定されている場合は、下記のように1文字ずつ読み込むことができます:

code.ts
let len = node.characters.length
for (let i = 0; i < len; i++) {
  await figma.loadFontAsync(node.getRangeFontName(i, i+1))
}

プラグインにデータや前回の設定などを保存

下記のように setPluginData を使って example キーに Hello, world! を保存できます。ただし、保存できるのは文字列のみです。複雑なデータの場合は複数キーに分けるか、保存時に文字列に変換し受け取ったら戻すなどの対策が必要です。

code.ts
figma.root.setPluginData('example', 'Hello, world!')

保存されたデータを取得するには getPluginData を使います。

code.ts
figma.root.getPluginData('example')

React を使う場合

複雑な UI の場合は React や Vue を使いたくなるでしょう。サンプルプラグインの React/Vue テンプレートが参考になると思います。ただ、React については少し注意する必要があります。

Figma の場合、UI のスクリプトやスタイルなどもすべて1つの HTML ファイルにまとめる必要があるため、何かしらの方法で React のコードもすべて HTML にインラインで埋め込む必要があります。

サンプルでは Webpack のプラグイン html-webpack-pluginhtml-webpack-inline-source-plugin を利用しています。

package.json
"html-webpack-inline-source-plugin": "0.0.10",
"html-webpack-plugin": "^3.2.0",

上記の組み合わせなら問題ありませんが、最新版 "html-webpack-plugin": "^4.5.0""html-webpack-inline-source-plugin": "0.0.10" だとエラーになります

なんとか html-webpack-plugin 4.x を使う方法もありますが、少しややこしいので、上記エラーが解決されるまで、もしくは、もっといい代案が出るまではサンプルとおりのバージョンを使ったほうが無難です。

最後に

https://github.com/ixkaito/figma-plugin-japanese-dummy-text に宣伝したプラグインのソースコードを公開していますので、よければご参考ください。

Discussion