📦 開発環境の準備
1. Node.js と npm(または pnpm / Yarn)をインストール
| 手順 | 内容 |
|---|---|
| ① | https://nodejs.org/ から LTS バージョンをダウンロードし、インストーラを実行します。 |
| ② | インストール後、ターミナルで node -v と npm -v(または pnpm -v)を確認。バージョンが表示されれば完了です。 |
Tip
プロジェクト規模が大きくなる場合はpnpmやYarn Berryの導入も検討してください。依存関係のインストールが高速になるうえ、ワークスペース機能で複数プラグインを一元管理できます。
2. 型定義と TypeScript 環境の構築
Figma が公式に提供している型定義 @figma/plugin-typings を使うと、エディタ上で figma.* 系 API の補完が得られます。
|
1 2 3 |
npm init -y # package.json の雛形作成 npm i -D typescript @figma/plugin-typings eslint prettier |
tsconfig.json(推奨設定)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "compilerOptions": { "target": "ES2022", "module": "ESNext", "lib": ["DOM", "ES2022"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, /* 正しい typeRoots の指定 */ "typeRoots": [ "./node_modules/@types", "./node_modules/@figma/plugin-typings" ], "outDir": "dist", "sourceMap": true }, "include": ["src/**/*.ts", "src/**/*.tsx"] } |
ポイント
-typeRootsは./node_modules/@figma/plugin-typingsを指す必要があります。以前の記述 (./node_modules/@figma) では型が解決されません。
- VS Code の標準機能だけで TypeScript の補完は十分に動作します。過去に紹介した「TypeScript Hero」はメンテナンスが停止しており、現在は不要です。
3. ビルドツール:Vite(React/Preact)または esbuild
2024 年以降の Figma プラグインでは Vite がデファクトスタンダードとなっています。軽量かつ高速な HMR が特徴です。
|
1 2 3 4 |
npm i -D vite @vitejs/plugin-react # React UI を作る場合 # もしくは npm i -D vite preact @preact/preset-vite # バンドルサイズを極限まで削減したいとき |
vite.config.ts(React 用サンプル)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { lib: { entry: 'src/code.ts', formats: ['cjs'], }, outDir: 'dist', rollupOptions: { // Figma のランタイムは figma オブジェクトをグローバルに提供します external: ['figma'], output: { globals: { figma: 'figma' } }, }, }, }); |
package.json にビルドコマンドを追加
|
1 2 3 4 5 6 7 |
{ "scripts": { "dev": "vite build --watch", "build": "vite build" } } |
npm run dev を実行すると、src/ 配下の変更が自動で dist/ に出力されます。Figma デスクトップアプリはこのフォルダーを参照してプラグインをロードします。
4. コーディング支援ツール(任意)
- ESLint + Prettier:コード品質と整形を自動化
bash
npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier
npx eslint --init # 設定ウィザードに従って TypeScript 用の設定を作成 - Jest + figma-mock:プラグインロジックだけを単体テスト
bash
npm i -D jest ts-jest @types/jest figma-mock
🗂️ プラグインプロジェクトの構造
1. Figma アプリ内で雛形を作成
| 手順 | 操作 |
|---|---|
| ① | デスクトップ版 Figma を起動 |
| ② | プラグイン > 開発 > プラグインの新規作成 を選択 |
| ③ | 「カスタム UI」テンプレートを選び、プロジェクト名と保存先フォルダーを指定 |
| ④ | manifest.json と空の code.ts が自動生成されます |
2. manifest.json の必須項目
|
1 2 3 4 5 6 7 8 9 10 |
{ "name": "テキスト置換プラグイン", "id": "com.example.text-replacer", "api": "1.0.0", "main": "dist/code.js", "ui": "dist/ui.html", "editorType": ["figma"], "permissions": ["currentpage", "clipboardRead"] } |
editorTypeは必須(Figma、FigJam のいずれか)。apiはプラグイン API バージョンであり、REST API とは別です。
3. ディレクトリ例
|
1 2 3 4 5 6 7 8 9 10 11 |
my-plugin/ ├─ src/ │ ├─ code.ts # 背景スクリプト(Node 環境) │ └─ ui.tsx # カスタム UI(React/Preact) ├─ public/ │ └─ index.html # Vite が参照するテンプレート ├─ dist/ # ビルド成果物(Figma が読む側) ├─ tsconfig.json ├─ vite.config.ts └─ manifest.json |
🧩 コアロジックと UI 実装
1. 背景スクリプト src/code.ts
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// プラグイン起動時に UI を表示 figma.showUI(__html__, { width: 320, height: 240 }); figma.ui.onmessage = async (msg) => { try { if (msg.type === 'replace-text') { const selection = figma.currentPage.selection; let replacedCount = 0; for (const node of selection) { // TextNode のみ対象 if ('characters' in node) { node.characters = node.characters.replace( new RegExp(msg.search, 'g'), msg.replace ); replacedCount++; } } figma.notify(`置換完了:${replacedCount} 件`); } } catch (e: any) { // エラーハンドリングは必ず行う figma.notify(`エラー: ${e.message}`); console.error(e); } }; |
2. UI (src/ui.tsx) – React の例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import * as React from 'react'; import { createRoot } from 'react-dom/client'; function App() { const [search, setSearch] = React.useState(''); const [replace, setReplace] = React.useState(''); const onRun = () => { parent.postMessage( { pluginMessage: { type: 'replace-text', search, replace, }, }, '*' ); }; return ( <div style={{ padding: 12, fontFamily: 'sans-serif' }}> <h3>テキスト置換</h3> <input placeholder="検索文字列(正規表現)" value={search} onChange={(e) => setSearch(e.target.value)} style={{ width: '100%', marginBottom: 8 }} /> <input placeholder="置換後文字列" value={replace} onChange={(e) => setReplace(e.target.value)} style={{ width: '100%', marginBottom: 12 }} /> <button onClick={onRun} style={{ width: '100%' }}> 実行 </button> </div> ); } // Vite が自動で生成する #root 要素へマウント createRoot(document.getElementById('root')!).render(<App />); |
3. UI 用 HTML (public/index.html)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>テキスト置換プラグイン</title> <!-- CSP 推奨設定 --> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://unpkg.com; style-src 'self' 'unsafe-inline'; img-src data:;"> </head> <body> <div id="root"></div> <!-- Vite がビルド時に差し替えるエントリーポイント --> <script type="module" src="/src/ui.tsx"></script> </body> </html> |
セキュリティ注記
UI 側で外部スクリプトやevalを使用すると CSP に違反し、Figma がプラグインをブロックします。上記のように最低限のポリシーだけ許可する形が安全です。
4. メッセージングまとめ
| 方向 | コード例 |
|---|---|
| UI → 背景 | parent.postMessage({ pluginMessage: {...} }, '*'); |
| 背景 → UI | figma.ui.postMessage({ type: 'log', text: '完了' }); |
| 受信側(UI) | window.onmessage = (e) => { if (e.data.pluginMessage) … } |
| 受信側(背景) | figma.ui.onmessage = (msg) => { … } |
🛠️ ビルド・デバッグ・テスト
1. Vite のウォッチモード
|
1 2 |
npm run dev # ソース変更 → 自動で dist/ にビルド → Figma が即反映 |
- ターミナルに ✓ built in xxx ms と表示され、エラーは赤字で出力されます。
- ビルドが失敗した場合は
dist/が更新されないので、Figma 側のプラグインは古いコードを実行し続けます。
2. Figma デスクトップアプリでデバッグ
- プラグイン読み込み
- メニュー > プラグイン > 開発 > 既存のプラグインを読み込む →
manifest.jsonがあるフォルダーを指定。 - 実行
- 作成したプラグイン名をクリック。
- コンソール確認
Ctrl+Shift+I(macOS は⌥+⌘+I)でデベロッパーツールを開き、Consoleタブにfigma.notify,console.log,console.errorが出力されます。
3. ログとエラーハンドリングのベストプラクティス
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 背景側 figma.ui.onmessage = async (msg) => { try { // …ロジック… } catch (err: any) { figma.notify(`⚠️ ${err.message}`); console.error('[Plugin Error]', err); } }; // UI 側(未捕捉例外を親へ転送) window.onerror = (message, source, lineno, colno, error) => { parent.postMessage( { pluginMessage: { type: 'log', text: `${message} @${lineno}:${colno}` } }, '*' ); }; |
4. 単体テスト例(Jest + figma-mock)
src/__tests__/replace-text.test.ts
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { replaceTextInSelection } from '../code'; import { createMockFigma } from 'figma-mock'; const mock = createMockFigma(); test('選択中の TextNode の文字列が置換される', () => { const node = mock.createTextNode({ characters: 'Hello World' }); mock.currentPage.selection = [node]; replaceTextInSelection('World', 'Figma'); expect(node.characters).toBe('Hello Figma'); }); |
CI の設定例(GitHub Actions)
yaml
name: CI
on: [push, pull_request]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm ci
- run: npm run build
- run: npm test
🚀 公開と運用のベストプラクティス
1. Community へテスト公開する手順
| 手順 | 操作 |
|---|---|
| ① | Figma.com にログインし、右上メニュー → Community を選択 |
| ② | 「新しいプラグインを公開」 ボタンをクリック |
| ③ | manifest.json の情報(名前・説明・サムネイル)を入力 |
| ④ | ビルド成果物 (dist/code.js, dist/ui.html) を ZIP にまとめてアップロード |
| ⑤ | バージョン番号は manifest.json に "version": "1.0.0" のように明示的に記載し、更新時は必ずインクリメント |
注意:
apiフィールドはプラグイン API バージョンであり、バージョン番号とは別です。審査の際に混同しないようにしてください。
2. 権限・レートリミット・セキュリティ
最小権限の設定
manifest.jsonのpermissionsは 必要最低限 に絞ります。例としてテキスト置換だけなら"currentpage"があれば十分です。
正しいレートリミット情報(公式ドキュメント参照)
| 種類 | 上限 |
|---|---|
| Figma REST API(アクセストークン単位) | 60 リクエスト / 分(バーストで最大 600) |
プラグイン内部の fetch 呼び出し |
明確な上限は無いが、過剰に短時間で大量リクエストすると “429 Too Many Requests” が返ることがあります。 |
実装例:スロットリング
ts
let lastCall = 0;
const MIN_INTERVAL = 1000; // ms
async function throttledFetch(...args) {
const now = Date.now();
if (now - lastCall < MIN_INTERVAL) await new Promise(r => setTimeout(r, MIN_INTERVAL));
lastCall = Date.now();
return fetch(...args);
}
外部通信の安全策
fetchの URL は必ず https:// で始める。- CORS ヘッダーが正しく設定されているか確認(
Access-Control-Allow-Origin: *が必要なケースもある)。 - 入力データを直接 HTML に埋め込むと XSS のリスクがあります。React/Preact で JSX を使う場合は自動エスケープが働きますが、
innerHTMLは極力避けましょう。
3. 運用・保守のヒント
| 項目 | 方法 |
|---|---|
| バージョン管理 | GitHub リポジトリで main → release/vX.Y.Z タグを付与し、Community の「更新」ボタンと同期させる |
| 自動デプロイ | GitHub Actions でビルド後に ZIP を作成し、GitHub Release に添付。手動で Community にアップロードすれば OK |
| ユーザーフィードバック | UI 内に簡易アンケート(例:figma.ui.postMessage({type:'feedback'}))を実装し、取得した情報は Google Form など外部サービスへ送信 |
| ローカライズ | manifest.json の locales フィールドで多言語対応可能。翻訳ファイルは JSON 配列で管理すると更新が楽です |
📌 まとめ
- 環境構築 – Node + TypeScript + Vite がベストプラクティス。型定義は
@figma/plugin-typingsを正しいパスで設定。 - プロジェクト構造 –
manifest.json、src/,dist/の三層構成を守るとビルド・デバッグが楽になる。 - 実装のコツ – 背景スクリプトと UI の双方向メッセージングは必ず
try / catchで囲み、エラーメッセージはfigma.notifyとコンソールに同時出力。 - デバッグ・テスト – Vite のウォッチモード+ Figma デスクトップの DevTools が最速。Jest + figma‑mock でロジック単体テストを自動化。
- 公開と運用 – 最小権限、正しいレートリミット認識、CSP と XSS 対策は必須。GitHub Actions を活用すれば継続的デプロイが実現できる。
これらの手順に沿って作業すれば、非エンジニアでも 数時間で動くプラグイン が完成し、Community への公開・運用までスムーズに進められます。ぜひ本ガイドをベースに、自分だけの Figma プラグイン開発に挑戦してみてください! 🚀