Figmaが重い、動かない。その時、真のアーキテクトはどうコードとメモリを支配するか
Figmaが「ただのデザインツール」だと思っていたなら、今すぐその認識を改めろ。
Webブラウザ(またはC++ベースのElectronラッパー)上で動作するFigmaは、巨大なデザインシステムや数千のインスタンスを抱えた瞬間、単なるフロントエンドアプリケーションの枠を超え、「極限まで肥大化したDOM/Scene Graph構造体」へと変貌する。
メモリリーク、GPUのオーバードロー、そして不毛な再レンダリング。
これらはデザイナーの「レイヤー整理の甘さ」ではない。システムアーキテクチャの敗北だ。
本稿では、UI/UXエンジニアおよびデザインシステムのガバナンスを担うDevOps/リードエンジニアに向け、Figmaの内部挙動(Scene Graphとメモリモデル)を解剖し、パフォーマンスを物理的限界まで引き上げる10の極限チェックポイントと、それを自動化するAPI/CLIハックを叩き込む。
—
Ⅰ. Figmaの内部アーキテクチャとメモリ枯渇のメカニズム
なぜFigmaは重くなるのか? 根本原因を理解せずして最適化は語れない。
1. Scene Graphの肥大化: Figmaのファイルは、実質的に巨大なJSONツリー構造(Scene Graph)だ。ノード数が10万を超えたあたりから、差分検知(Diffing)アルゴリズムの計算量が爆発する。
2. GPUテクスチャメモリの圧迫: 未最適化の巨大なPNG/JPEG画像が配置されると、VRAMを直接食いつぶす。ブラウザのWebGLコンテキストがロストし、あの悪名高い「Out of Memory」クラッシュを引き起こす。
3. 過剰なネスト(DOM/Component Depth): 深すぎるオートレイアウトのネストは、レイアウト計算のパイプライン(Cassowaryソルバーの系譜)に致命的な負荷をかける。
これを手動の「お片付け」で解決しようなどと考えるのは、手動でガベージコレクションをやろうとするようなものだ。システムで殴れ。
—
Ⅱ. パフォーマンスを劇的に改善する10のチェックポイント
1. ノード数(Scene Graph Nodes)のハードリミット設定
- 症状: 1ファイルあたりのノード数が50,000を超えると、操作のたびにメインスレッドがブロックされる。
- 対策: 1ファイル、1ページの限界値を明確に規定せよ。巨大なワイヤーフレームや全画面フローは、絶対に単一ファイルに収めるな。
2. コンポーネントライブラリの「ポータビリティ」分離
- 症状: アプリケーションの実装コードと同様、デザインシステムも単一モノリス(Monolith)にすると崩壊する。
- 対策: Foundations(トークン)、Primitives(原子パーツ)、Patterns(分子)を厳密に別ファイル(別チーム)に切り出し、ライブラリとしてパブリッシュ(Publish)せよ。ローカルでのオーバライドの嵐を防げ。
3. 未使用スタイル・コンポーネントの完全消去
- 症状: 「いつか使うかも知れない」というエンジニアの悪癖が、Figma内でもメモリを蝕む。
- 対策: プラグインやAPIを使い、インベントリから参照されていない(`remote` ではない、かつローカルで参照ゼロの)スタイルを容赦なく purge(削除)しろ。
4. オートレイアウトのネスト深度制限(最大3階層まで)
- 症状: 「とりあえずAuto Layoutに入れとけ」精神が生む、10階層以上の深いネスト。
- 対策: 再帰的なレイアウト計算コストは $O(N)$ 以上で跳ね上がる。コンポーネントをフラットに再設計し、ネストは最大3階層以内に強制せよ。
5. 画像テクスチャの強制ダウンサンプリング
- 症状: デザイナーが無加工の4Kディスプレイ用スクリーンショット(数MB)をそのまま貼り付ける。
- 対策: Figmaに持ち込む前に、CLIで適切な解像度(Retinaであれば2xまで)に圧縮・リサイズするパイプラインを強制しろ。
6. ベクターネットワークの極限までのパス単純化
- 症状: イラストレーターからインポートした複雑なSVG。何千ものアンカーポイントを持つパスデータがGPUを殺す。
- 対策: パスファインダーで結合し、不要な隠しレイヤーやオーバーラップパスをFlatten(統合)しろ。
7. バリアント(Variants)の過剰生成の禁止
- 症状: すべての状態(State)やサイズを1つのコンポーネントのバリアントに詰め込み、バリアント数が数百に達する。
- 対策: 組み合わせ爆発を起こすバリアントは分割せよ。本当に必要なプロパティだけに絞る。
8. 「ページ分割」のモジュール化設計
- 症状: 1つのファイルに「表紙」「ワイヤー」「詳細デザイン」「プロトタイプ」「アーカイブ」が同居している。
- 対策: ページ(Page)単位でドメインを完全に分離せよ。Figmaはアクティブなページ以外の重いシーンを一部遅延ロードするが、ファイル全体のインデックス負荷は軽減されない。
9. 非表示レイヤー(Hidden Layers)のパージ
- 症状: 「ボツ案」や「将来のアイデア」と称して、非表示にしたまま放置された数千のレイヤー。
- 対策: 非表示であってもScene Graphのメモリには常駐する。ボツ案は別ファイルに退避(Export)し、即座に削除しろ。
10. クラウドキャッシュとローカルハードウェアの最適化
- 症状: ブラウザタブのメモリ肥大化。
- 対策: 重いデザイン作業を行う際は、ブラウザ版ではなくFigmaデスクトップアプリの専用インスタンスを使用し、定期的にキャッシュディレクトリ(`~/Library/Application Support/Figma/`等)をクリーニングせよ。
—
Ⅲ. 【独自ハック】Figma REST API & CLIによる「パフォーマンス自動監査」スクリプト
手動のチェックポイントなど、人間の意志に頼るプロセスは3日ていどで崩壊する。
真のエンジニアは、CI/CDパイプライン(または定期実行スクリプト)でFigmaファイルを監視し、重すぎるファイルを自動検知・警告する仕組みを構築する。
以下に、Figma REST APIを叩いてファイルの「ノード数」「画像過多」「深すぎるネスト」を静的解析し、Slackへアラートを飛ばす Node.js スクリプトを提示する。これを叩き込め。
/
- Figma Performance Auditor (Figma Performance CI Script)
- 指定されたFigmaファイルのJSONツリーを解析し、
- ノード数、ネスト深度、重い画像を検知してメトリクスを出力する。
- 実行要件: Node.js, node-fetch
/
const fetch = require(‘node-fetch’);
// 環境変数からの設定
const FIGMA_TOKEN = process.env.FIGMA_ACCESS_TOKEN;
const FILE_KEY = process.env.FIGMA_FILE_KEY; // FigmaのURLから取得
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
// 閾値設定(アーキテクチャの安全基準)
const THRESHOLDS = {
maxNodes: 25000, // 最大ノード数
maxDepth: 6, // 最大ネスト深度
maxImages: 50 // 許容画像数
};
async function auditFigmaFile() {
if (!FIGMA_TOKEN || !FILE_KEY) {
console.error(‘Error: FIGMA_ACCESS_TOKEN and FIGMA_FILE_KEY must be set.’);
process.exit(1);
}
console.log(`[Audit] Fetching Figma file metadata for: ${FILE_KEY}…`);
try {
const response = await fetch(`https://api.figma.com/v1/files/${FILE_KEY}?depth=4`, {
headers: { ‘X-Figma-Token’: FIGMA_TOKEN }
});
if (!response.ok) {
throw new Error(`Figma API Error: ${response.statusText}`);
}
const data = await response.json();
// 解析メトリクスの初期化
let metrics = {
totalNodes: 0,
maxObservedDepth: 0,
imageCount: 0,
warnings: []
};
// 再帰的にノードを走査する関数
function traverse(node, currentDepth = 1) {
metrics.totalNodes++;
if (currentDepth > metrics.maxObservedDepth) {
metrics.maxObservedDepth = currentDepth;
}
// 画像の検知 (FILLにIMAGEタイプが含まれるか)
if (node.fills && node.fills.some(fill => fill.type === ‘IMAGE’)) {
metrics.imageCount++;
}
// 子ノードの再帰処理
if (node.children) {
for (const child of node.children) {
traverse(child, currentDepth + 1);
}
}
}
// ドキュメントルートから走査開始
traverse(data.document, 1);
console.log(‘— Figma Architecture Audit Report —‘);
console.log(`Total Nodes: ${metrics.totalNodes} (Limit: ${THRESHOLDS.maxNodes})`);
console.log(`Max Nest Depth: ${metrics.maxObservedDepth} (Limit: ${THRESHOLDS.maxDepth})`);
console.log(`Image Count: ${metrics.imageCount} (Limit: ${THRESHOLDS.maxImages})`);
// 閾値チェックと警告の生成
if (metrics.totalNodes > THRESHOLDS.maxNodes) {
metrics.warnings.warn(`[CRITICAL] Node count exceeds threshold: ${metrics.totalNodes}`);
}
if (metrics.maxObservedDepth > THRESHOLDS.maxDepth) {
metrics.warnings.push(`[WARNING] Max nest depth is too deep: ${metrics.maxObservedDepth}`);
}
if (metrics.imageCount > THRESHOLDS.maxImages) {
metrics.warnings.push(`[WARNING] High image count detected: ${metrics.imageCount}`);
}
// 警告が存在する場合はSlack等へ通知
if (metrics.warnings.length > 0) {
console.log(‘Performance bottlenecks detected. Sending alerts…’);
await sendSlackAlert(metrics.warnings);
} else {
console.log(‘All metrics within acceptable performance limits.’);
}
} catch (error) {
console.error(‘Audit failed:’, error);
process.exit(1);
}
}
async function sendSlackAlert(warnings) {
if (!SLACK_WEBHOOK_URL) return;
const payload = {
text: `🚨 Figma Performance Alert 🚨\nFile: \`${FILE_KEY}\`\n\`\`\`\n${warnings.join(‘\n’)}\n\`\`\“
};
await fetch(SLACK_WEBHOOK_URL, {
method: ‘POST’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify(payload)
});
}
auditFigmaFile();
—
Ⅳ. 結び:ツールに支配されるな、システムを支配せよ
Figmaが重いと感じた瞬間、それはデザインの複雑性がツールの処理限界を超えたというシステムからのアラートだ。
デザイナーに「レイヤーを綺麗にして」と頼むのは、プログラマーに「コードを綺麗にして」と抽象的な精神論を説くのと同じくらい無意味である。
アーキテクトよ、構造を定義しろ。ルールをコード化し、APIで監視せよ。
ツールを限界までチューニングし、一瞬たりとも思考を止めない最高速のプロトタイピング・パイプラインを死守するのだ。