【実務・中級編】PenpotとGraphQL APIの活用:デザインデータからカスタムレポートを自動生成する開発者向けレシピ – UI/UX・デザインツール活用バイブル

Penpot × GraphQL API:デザインデータ駆動型開発(DDD)でメトリクスを自動化する極意

テックリードの皆さん、日々のスプリントで「今、デザインシステムはどれくらい浸透しているか」「未着手のコンポーネントはいくつあるか」といったデザインの定量データを、手動でスプレッドシートにまとめていないだろうか?

Figmaの閉じたエコシステムにフラストレーションを抱えていたチームにとって、オープンソースのベクター・プロトタイピングツール「Penpot」の登場は福音だった。そして、開発者・デザイナーの境界線を完全に融解させる最強の武器が、PenpotのGraphQL APIだ。

今回は、PenpotのバックエンドAPIを直接叩き、デザインデータからメトリクスを自動抽出し、社内ダッシュボードへリアルタイム出力するパイプラインの構築ハンズオンを公開する。

—

1. Penpot GraphQL APIのエンドポイント構造の解析

商用ツールとは異なり、PenpotはSelf-hosted(Docker等)での運用が基本となるため、APIの挙動を完全にコントロールできる。まずはその中核であるGraphQLエンドポイントの構造を暴く。

エンドポイントと認証の基本

Penpotのバックエンド(通常は `http://localhost:9001` もしくはリバースプロキシ経由)には、以下のエンドポイントが用意されている。

  • GraphQL Playground / Endpoint: `/api/rpc` (Penpotはクエリ/ミューテーションを単一のRPC風エンドポイントで処理する特殊なルーティングを採用している場合があるが、標準的なGraphQLクライアントが接続可能)

認証は通常、Cookie(JWT)ベースだが、自動化スクリプトやCI/CDパイプラインから叩く場合は、あらかじめ発行したアクセストークン、またはセッションCookieをヘッダーに付与する。

必須クエリの構造(チーム、プロジェクト、ファイル、ページ)

デザインデータ構造は以下の階層ツリーを描いている。これをトラバース(走査)することで、必要なメトリクスを抽出できる。

Team -> Project -> File -> Page -> Frame / Component

以下は、特定のファイル内のコンポーネントツリー構造を取得するためのGraphQLクエリの例だ。

query GetFileContent($fileId: UUID!) {
file(id: $fileId) {
id
name
data {
pages {
id
name
frames {
id
name
shapes {
id
name
boardId
… on ComponentInstance {
componentId
}
}
}
}
}
}
}

—

2. デザイン進捗・コンポーネント使用数を自動集計するスクリプトの実装

ここからが実務の本番だ。TypeScript(Node.js)を使用し、Penpotからデータを取得して「デザインシステム内のコンポーネントが何回インスタンス化されているか」を集計するスクリプトを実装する。

実用的な設定ファイル(`config.json`)

まずは接続情報やターゲットのファイルIDを定義する設定ファイルを用意する。

{
“$schema”: “./schema.json”,
“penpot”: {
“endpoint”: “https://penpot.your-company.internal/api/rpc”,
“teamId”: “a1b2c3d4-e5f6-7890-abcd-ef0123456789”,
“targetFileIds”: [
“f1e2d3c4-b5a6-7890-fedc-ba9876543210”
]
},
“metrics”: {
“outputFormat”: “json”,
“alertThresholds”: {
“unresolvedComponents”: 5
}
}
}

集計スクリプト(`metrics-collector.ts`)

import axios from ‘axios’;
import as fs from ‘fs’;
import as path from ‘path’;

// 設定ファイルの読み込み
const configPath = path.join(__dirname, ‘config.json’);
const config = JSON.parse(fs.readFileSync(configPath, ‘utf-8’));

interface ComponentUsage {
componentId: string;
count: number;
}

async function fetchPenpotData(fileId: string, authToken: string) {
const query = `
query GetFileShapes($fileId: UUID!) {
file(id: $fileId) {
name
data {
pages {
name
shapes {
id
type
name
… on ComponentInstance {
componentId
}
}
}
}
}
}
`;

try {
const response = await axios.post(
config.penpot.endpoint,
{
query,
variables: { fileId },
},
{
headers: {
‘Content-Type’: ‘application/json’,
‘Cookie’: `auth-token=${authToken}`, // セッション認証トークン
},
}
);
return response.data.data.file;
} catch (error) {
console.error(`Failed to fetch file ID: ${fileId}`, error);
process.exit(1);
}
}

async function analyzeDesignMetrics() {
const authToken = process.env.PENPOT_AUTH_TOKEN;
if (!authToken) {
console.error(‘Error: PENPOT_AUTH_TOKEN environment variable is missing.’);
process.exit(1);
}

const componentCounts: Record = {};

for (const fileId of config.penpot.targetFileIds) {
console.log(`Analyzing file: ${fileId}…`);
const fileData = await fetchPenpotData(fileId, authToken);

fileData.data.pages.forEach((page: any) => {
page.shapes.forEach((shape: any) => {
// コンポーネントインスタンスであるかを判定
if (shape.type === ‘component-instance’ || shape.componentId) {
const compId = shape.componentId;
componentCounts[compId] = (componentCounts[compId] || 0) + 1;
}
});
});
}

// 結果の整形
const metricsResult = {
timestamp: new Date().toISOString(),
totalUniqueComponentsUsed: Object.keys(componentCounts).length,
componentUsageBreakdown: componentCounts,
};

// 出力
const outputPath = path.join(__dirname, ‘output-metrics.json’);
fs.writeFileSync(outputPath, JSON.stringify(metricsResult, null, 2));
console.log(`Metrics successfully generated at ${outputPath}`);
}

analyzeDesignMetrics();

—

3. 社内ダッシュボードへデザインメトリクスをリアルタイム出力する方法

収集したJSONデータを、Datadog、Grafana、あるいは社内のSlackチャンネルへリアルタイムに流し込むことで、デザインと開発の乖離を防ぐ「オブザーバビリティ(可観測性)」をデザイン領域にも拡張する。

Prometheus / Grafana連携のベストプラクティス

上記のスクリプトをGitHub Actionsや社内KubernetesのCronJobとして定期実行(例: 1日1回、あるいはPRマージ時)し、PrometheusのPushgatewayやInfluxDBにメトリクスをプッシュする。

Grafanaで監視すべきKPI

1. Design System Adoption Rate(デザインシステム採用率):
カスタムで作られた自由形状(Frame/Path)の数に対する、公式コンポーネント(Component Instance)の比率。
2. Component Debt(負債コンポーネント数):
非推奨(Deprecated)になったコンポーネントが、いまだに画面上にいくつ配置されているか。

—

💡 開発効率を最大化するプロのTips

ここからは、Penpotを実務で使い倒すための「隠れた知見」を共有する。

1. 開発スピードを劇的に高めるショートカット

  • `Shift + 2`: 選択したオブジェクトへのズーム(Figmaと同じ感覚で高速フォーカス)。
  • `Alt + Drag`: プロパティパネルの数値フィールド上でドラッグすると、値が細かくインクリメント・デクリメントされる(CSSの数値微調整に神がかった効果を発揮)。
  • `Ctrl/Cmd + Shift + L`: コンポーネントへの変換を一撃で行う。

2. 絶対入れるべき神プラグイン&拡張

Penpotはプラグインエコシステムもオープンだ。特に開発者とのブリッジとして以下の拡張を推奨する。

  • Penpot Exporter for Storybook: 抽出したコンポーネントのトークンを、自動的にStorybookのArgTypesへとマッピングするカスタムプラグイン(自社製スクリプトと組み合わせるのがベスト)。

3. チーム開発で役立つ設定の共有化ルール

  • カラートークンのCSS変数同期:

Penpotのデザイン変数をJSON形式でエクスポートし、Style Dictionaryなどのビルドツールを経由して、フロントエンドの`variables.css`やTailwindの`tailwind.config.js`へ自動同期するCIパイプラインを必ず組むこと。手動でのカラーコードコピペは「技術的負債の温床」となる。

—

結びに代えて

デザインツールを「お絵描きソフト」として扱っているうちは、モダンなアジャイル開発のスピードには追いつけない。PenpotのGraphQL APIをハックし、デザインデータをコードの世界へとシームレスに接続することで、デザインの品質と進捗は「感覚」から「定量データ」へと昇華される。

さあ、今すぐコンソールを開き、デザインのメトリクスをコードで奪い取ろう。

タイトルとURLをコピーしました