忙しい人のためのFigma Plugin開発手引

この記事は [さくらインターネット Advent Calendar 2019](https://qiita.com/advent-calendar/2019/sakura) 21日目の記事です。

---- 

UXデザイングループ所属のkgsiです。最近Figmaを副業でよく使ってます。さくらインターネット社内でも初学者向けに[ハンズオン](https://speakerdeck.com/kgsi/getting-started-with-figma)を開催したり、導入推進をしたりしています。そんな中でプラグイン開発に言及していなかったなぁと思い、まとめてみた次第です。

## この記事について
細かくプラグイン開発について説明している記事はすでにいくつもあるので、忙しい人向けに要点を短くまとめた記事です。~~自分が単に時間がないからでは決して有りません。~~

## Figma について
![スクリーンショット 2019-12-23 12.05.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22445/8cec3879-be1e-039b-fa72-1753b1fcc498.png)
https://www.figma.com/

* Webベースのプロトタイプ・デザインツール
* チームのためのデザインツールがコンセプト

## Figma Pluginについて

* [Figma](https://www.figma.com/)が今年から開始したPluginプラットフォーム
* Figmaのアカウントがあれば、無料有料プランを問わず誰でも開発可能
* 開発言語はTypeScript推奨（JavaScriptでも一応かける）
* 開発ツールはVisual Studio Code推奨
* プラグインの有料化は可能、広告表示によるマネタイズはNG

## できること・（まだ）できないこと

### できること
基本的にできることはシンプルで、Figma Pluginは開いているドキュメントに対して操作が行えます。

* ドキュメント内のレイヤー、レイヤープロパティの読み取り
* 対象レイヤーの編集・書き換え
* モーダルUI（iframe）を通してブラウザAPIにアクセス

### （まだ）できないこと
主だったできないことは以下の通りです。

* ローカルファイル、ユーザー、チーム情報、コメントへのアクセス
* チームライブラリへのアクセス
* プラグイン側でキーボードショートカットを操作する
* イベントトリガーのカスタマイズ

これらはアップデートされることで改善するものも含まれます。一方で外部フォントの読み込み、デスクトップAPIへのアクセスは、互換性やライセンスの問題で実装は行われないと明言されています。詳しくは以下を参照してください。

公式： https://www.figma.com/plugin-docs/whats-supported/
 
## 開発方法

### 環境整備
ステップとしては以下のとおりです。公式にも書かれていますが、特に難しいこともなく、簡単にプラグインの実行が可能です。

1. Figmaの`Plugin > Development > 「+」アイコン`をクリック
2. nameを設定して、Templateを選んで雛形をローカルに保存
3. VS Codeのインストール
4. `sudo npm install -g typescript`でTypeScriptをローカルにインストール
5. VS Codeでディレクトリを開き、 `ターミナル > タスクを実行` を選択。`tsc: ウォッチ - tsconfig.json `を選んでタスク実行
6. デザイン画面で`Plugin > development > プラグイン名`で実行

公式： https://www.figma.com/plugin-docs/setup/


### デバック方法
デバック方法は通常のフロントエンド開発と同じ要領で行えます。

* デザイン画面の`Plugin > development > Open Console`を開くと、開発コンソールが開く。
* 標準だとビルドされるたびにプラグインを実行し直す必要がある
* 実行ステップを確認しつつ行う場合は`DeveloperVM`を使う
* ショートカットによる簡易実行(最後に開いたプラグインの実行)で、都度開かなくても実行可能 ` Windows: Alt-Ctrl-P Mac: Command-Option-P`

## 開発のポイント

### ブラウザAPIへのアクセスについて
DOMの操作やネットワークへのアクセスなどの、ブラウザAPIは、UIパネル上(`<iframe>`)でしか利用できません。ブラウザAPIを使いたい場合は、UIパネル越しにアクセスする必要があります。

### UIパネルでできること
UIパネル上(ui.html)は完全なhtmlで、JS・CSSも自由に利用可能です。サードパーティ製のプラグインも読み込むことができます。もちろんReactやVueなどのフレームワークも利用可能なので、高度なUI設計も可能です。

### レイヤー操作の基本
基本的に画面に配置されているレイヤーをfor文で探索し、keyやtypeで判定して編集・操作を行うシンプルな構造です。実装方法によっては処理コストが大きく、パフォーマンスに影響が出てしまうので、注意が必要です。

### プラグイン実行の仕組み

#### 一度だけ実行するタイプ
UIパネルを利用させず、Pluginを一度だけ実行する場合は、`code.tsに`処理を書くだけで実行できます。

```typescript
for (const node of figma.currentPage.selection) {
  if ("opacity" in node) {
    node.opacity *= 0.5;
  }
}
figma.closePlugin('Edited Layers'); //引数にトーストメッセージを入れられる
```

#### UIパネルを通して実行するタイプ
メインコード（code.ts）とUIパネル（ui.html）は完全に独立しており、お互いの値を受け渡して利用するには、`postMessage`メソッドを使い、オブジェクトデータの受け渡しをする必要があります。

```javascript:ui.html
document.getElementById('send').onclick = () => {
  parent.postMessage({ pluginMessage: { type: 'create-message', 10 } }, '*')
}
```

```typescript:code.ts
// ui.htmlを使う宣言
figma.showUI(__html__)

// ui.htmlからcallbackを受け取る
figma.ui.onmessage = msg => {
  if (msg.type === "create-message") {
     console.log(msg.count) //受け取ったデータ
  }
}
```

## 参考
### 公式ドキュメント
* [Figma Developer Platform](https://www.figma.com/developers/)

### Plugin参考
* [Better Font Picker](https://www.figma.com/c/plugin/739922281164562258/Better-Font-Picker)
    * フォントの一覧プレビュー機能
* [A11y - Color Contrast Checker](https://www.figma.com/c/plugin/733159460536249875/A11y---Color-Contrast-Checker)
    * コントラストをみてアクセシビリティチェックするツール 
* [Roller · Design Linter · Toybox](https://www.figma.com/c/plugin/751892393146479981/Roller-%C2%B7-Design-Linter-%C2%B7-Toybox)
    * スタイルの不一致を自動的に検出して修正するツール
* [Autoflow](https://www.figma.com/c/plugin/733902567457592893/Autoflow)
    * フロー図作成ツール 

### Pluginについて
* [Figma Pluginの作り方（初級編）とTips](https://kudakurage.hatenadiary.com/entry/2019/08/17/104015#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3)
* [デザインツール「Figma」のプラグイン開発：さっそく作ってみた所感](https://cocopon.me/blog/2019/08/figma-plugin/)
* [FigmaのPlugin(プラグイン)の開発方法／作り方](https://gorilla-blog.net/entries/46a3afc7-c46b-43b8-9e8b-e706c5e81f2f)