Amazonで商品を見るセール会場へ

Figmaプラグインのプログレスバー実装|中止処理とENOENTの対処

Figmaプラグインで時間のかかる処理をする場合は、メインコードから完了件数をUIへ送り、HTMLのprogress要素で表示できます。進捗の表示と処理の分割を組み合わせ、利用者が状態を確認できるようにします。

この記事の処理は、100件を50msずつ待つ説明用のダミーです。CSV出力やノード走査そのものではありません。開始の多重実行を防ぎ、中止の要求と完了を分ける最小構成を示します。

目次

メインコードとUIの通信

  1. UIがstart-taskを送ります。
  2. メイン側が1件を終えるたびにcompletedとtotalを送ります。
  3. UIがprogressのvalueとmaxを更新します。
  4. 中止要求はcancelを送り、メイン側のフラグで次の反復を止めます。
  5. 完了・中止・失敗の結果を表示し、開始を再び使える状態にします。

awaitで制御を返さず長い同期処理を続けると、中止やUI更新をすぐ処理できない場合があります。実処理へ置き換えるときは、処理自体も分割します。出典:プラグインの実行環境、showUIとui。

ファイルを作成する

FigmaのNew pluginで生成したmanifestを基に、次の設定を使います。掲載例ではidを省略しています。自分のmanifestに割り当てられたidがある場合はその値を保ち、サンプルの任意文字列に置き換えません。3ファイルを同じフォルダへ保存してください。

manifest.json

{
  "name": "進捗表示サンプル",
  "api": "1.0.0",
  "main": "code.js",
  "ui": "ui.html",
  "editorType": [
    "figma"
  ],
  "documentAccess": "dynamic-page",
  "networkAccess": {
    "allowedDomains": [
      "none"
    ]
  }
}

code.js

figma.showUI(__html__, { width: 400, height: 200 });
let running = false, cancelled = false;
figma.ui.onmessage = async msg => {
  if (!msg) return;
  if (msg.type === "cancel") { cancelled = true; return; }
  if (msg.type !== "start-task" || running) return;
  running = true; cancelled = false;
  try {
    const total = 100;
    for (let completed = 0; completed < total; completed++) {
      if (cancelled) break;
      await new Promise(resolve => setTimeout(resolve, 50)); // 説明用のダミー処理
      figma.ui.postMessage({ type: "progress", completed: completed+1, total });
    }
    figma.ui.postMessage({ type: "done", cancelled });
  } catch (_) { figma.ui.postMessage({ type: "error", message: "処理に失敗しました。" }); }
  finally { running = false; }
};

ui.html

<!doctype html><html lang="ja"><meta charset="utf-8">
<button id="start">開始</button><button id="cancel" disabled>中止</button>
<progress id="progress" max="100" value="0"></progress><p id="status">待機中</p>
<script>
const start = document.getElementById("start"), cancel = document.getElementById("cancel");
const progress = document.getElementById("progress"), status = document.getElementById("status");
function send(type) { parent.postMessage({ pluginMessage: { type } }, "*"); }
start.onclick = () => { start.disabled = true; cancel.disabled = false; progress.value = 0; status.textContent = "処理中…"; send("start-task"); };
cancel.onclick = () => { cancel.disabled = true; status.textContent = "中止を要求…"; send("cancel"); };
window.onmessage = event => {
  if (event.source !== parent) return;
  const msg = event.data && event.data.pluginMessage;
  if (!msg) return;
  if (msg.type === "progress") {
    progress.max = msg.total; progress.value = msg.completed;
    status.textContent = `処理中 ${msg.completed}/${msg.total}`;
  } else if (msg.type === "done" || msg.type === "error") {
    start.disabled = false; cancel.disabled = true;
    status.textContent = msg.type === "error" ? msg.message : msg.cancelled ? "中止しました" : "完了しました";
  }
};
</script></html>

ENOENT・画面が出ない場合の確認

確認項目対処
mainがcode.tsになっているTypeScriptをビルドし、生成したcode.jsを指定する
uiのファイルがないmanifestからの相対パスとファイル名を照合する
JSONの末尾にカンマがある正しいJSONに直す
進捗が表示されない送るtypeとUIが受けるtypeを照合し、長い同期処理を分割する
100%になったが保存できない作成処理とダウンロード操作を分け、UIを先に閉じない

この例のmainはJavaScriptなので、掲載コードをそのままcode.jsへ保存します。TypeScriptを使う場合も、mainは生成先のJavaScriptです。コードを小分けにする仕組みはコンポーネントCSV出力で説明しています。

元記事の操作例

以下は元記事で掲載していた開発時の画面です。今回のコード改稿後に撮影した検証画像ではありません。現行の表示や変更結果は、複製したファイルで確認してください。

Figmaプラグインにおけるプログレスバーの表示例。
2025年08月の元記事の掲載例。改稿後コードの検証画像ではありません。

検証範囲と関連ガイド

今回確認したのは掲載コードの構文と、該当する入力・例外処理のローカル模擬検証です。Figmaデスクトップアプリ上での動作確認とは区別しています。改稿後のコードと、元記事が参照していたGitHub上の版が一致するとは限りません。

開発環境と登録手順はFigmaプラグイン開発入門、公開はCommunityへの申請を参照してください。

サービス

Service

デザイン制作に関心がありましたら、ぜひ詳細をご覧ください。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

Figmaのおすすめ書籍

Figma用PCの選び方

周辺機器の優先度

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次