figma pluginをサクッと作って理解する

## この記事について
[figma公式](https://www.figma.com/plugin-docs/setup/)が提供しているサンプルプラグインを作成する記事です。
前半はプラグイン作成、後半はどのように動作しているのかをまとめています。

「プラグイン作るのってなんか難しそ〜」と思いなんとなく試せずにいたのですが、やってみると意外にもすんなり作成できたので忘れないようにまとめました。

## 対象
- figmaプラグインを作ったことない方
- figmaプラグインってどんな感じで動いてんのーが気になる方

## 事前準備
- figma-pluginを動作させるコードを管理するリポジトリ(管理したい方のみでOK)
- figmaデスクトップアプリ
- VScodeなどのお気に入りエディタ

## figma でテンプレートを作成する
1. figmaデスクトップアプリ版にて、「Plugins > Development > New plugin...」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/fdda528d-80d2-1d39-53ad-f7aad377fc04.png)

2. フォームに適当なプラグイン名を入力し、「Figma design + Fig jam」のカードを選択
	- プラグイン名は`package.json`から変更できるのでとりあえずなんでもOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/5a18644e-8f33-caf6-2d24-4f30e252ffc0.png)

3. 「With UI & browser APIs」のカードを選択し、「Save as」をクリック。フォルダをどこに保存するか確認されるため、お好みの場所に配置(リポジトリ作成した方はその配下になど)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/e1027a72-b98b-d795-6e7e-11b856d0493b.png)

4. 「New plugin created!」のモーダルが出てきたらテンプレート作成は完了！「Done」を押しモーダルを消す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/47971b05-440a-4f6a-211b-f61742b96d60.png)
※作成したプラグインで「RUN」を押すと以下のようなエラーが出てくるが、手順通りに進めるとエラーは消えるので気にしなくてOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/e7192595-9f5a-b008-adcc-6dd71cbf7b0f.png)

## 実行環境を整備
1. 作成したフォルダ配下で`npm install` を実行しnpmを取得
2. `npm install -D @figma/plugin-typings` を実行しfigma-pluginに対応するTSの型を取得

## figmaでプラグインを実行
1. figmaデスクトップアプリ版に戻り、「Plugins > Development > 作成したプラグイン名」を選択すると、プラグインが立ち上がり以下のような画面になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/2c8e789e-9de7-aee3-648c-6f53654cc800.png)

2. 「Create」をクリックし、オレンジの四角が5つ出てきたら成功🚀プラグイン作成は完了！！！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/2b508a3a-3146-6fa2-5242-0b7f78576dc3.png)


## 完成したので、少し深掘りしていく
まず、各ファイルが何に使われるかを確認します。
色々ありますが主要なファイルは4つ。それぞれ以下の用途で使用されています。

### manifest.json
- `package.json`のようなメタ情報を書くファイル。必ず必要。
- プラグインで使用するパラメータ名、アクセス権限、プラグイン対象のエディタなど細かく指定が可能。
- 詳細は[plugin Manifest](https://www.figma.com/plugin-docs/manifest/)にて記載されています。

### code.ts
- figmaの操作を行うための処理コードを書くファイル。
- [figma API](https://www.figma.com/plugin-docs/)を利用することでfigma上の操作が可能。

### code.js
- `code.ts`をコンパイルした後のファイル。
- `manifest.json`に読み込まれ、figma上で実行されるのはこのファイル。

### ui.html
- プラグインのUIを整えるファイル。いたって普通のHTML。





## プラグイン動作の流れについて
figma pluginはHTML・CSS・JSで動作しますが、WEB制作でコードを書いていく流れでは制作できず「？」となったポイントがありました。

それが、**figmaとfigma pluginの通信部分**になります。

figma pluginの実行環境は、パフォーマンスや安全性を考慮した結果サンドボックスのメインスレッドで実行されています。（[参考: How Plugins Run](https://www.figma.com/plugin-docs/how-plugins-run)）
そしてサンドボックスは最低限のJS実行環境となっているため、ブラウザAPIが使用できません。（`XMLHttpRequest`や`DOM API`などなどが利用不可。ただし、JS環境ではあるのでJSが提供するAPIは利用可能）

figma pluginの実態はiframeとなっています。`ui.html`に書いた内容はiframeとして反映され、そのiframeがfigmaに埋め込まれる形で実装されています。

「figma plugin（iframe）」と「figma（window）」間での通信方法として、JSが提供するAPIの[Window.postMessage()](https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage)が使用されています。postMessageを使用すると、iframeと親window間で、安全に情報を伝達することができるようになるみたいです。全体的な流れは以下。

![figma-plugin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603107/6809be8f-9f39-b606-e5bb-fb40e892eacb.png)
参照元: https://www.figma.com/plugin-docs/how-plugins-run

サンドボックス側（code.ts）では、figmaAPIを使用してfigmaで実行させたい処理を記載することができますが、ブラウザAPIを使用することができません。

逆にiframe側（ui.html）では、HTMLやJSのコードが書けてブラウザAPIが実行できますが、figmaにアクセスできません。

そこでpostMessageを使用して双方向の通信を行うことにより、figma pluginが実装ができるようになる。そういった仕組みのようです。



## 感想
figma pluginの実装自体は思ったより簡単にできるので色々活用できそうだな〜と感じた。

ただし、実行環境に関しては普段のweb制作をしている中で出会ったことのない方法だったため、一連の流れの理解に苦しみました...。

プラグインコードをサンドボックスのメインスレッドで実行するとどの辺がパフォーマンス的に嬉しいのか全然わからなかったので詳しい方いたら教えてください！



## その他
### [Window.postMessage()](https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage)　とは？

オブジェクト間で安全にオリジン間通信を可能にするためのメソッド。

通常は同じプロトコル、ポート番号、ホストである場合のみアクセスが可能であり、そうでない場合はエラーとなる事がありアクセスできない場合があります。（[同一オリジンポリシー](https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy)）

Window.postMessage()を使うのはハック的な手段ではなく、このアクセス制限を安全に回避できる方法のようです。


### [サンドボックス](https://www.ntt.com/bizon/glossary/j-s/sandbox.html)とは？

ユーザーが利用する領域から隔離した、保護された空間のこと。

例えば外部から送られてきたプログラムやファイルを実行する際に、通常の領域から隔離されているため、万が一何かあっても害を防ぐことができるという仕組みのこと。


## 参考
https://www.figma.com/plugin-docs/setup/

https://zenn.dev/ixkaito/articles/how-to-make-a-figma-plugin

https://www.ntt.com/bizon/glossary/j-s/sandbox.html

https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#preflighted_requests