---
title: "DevTools — zenit Zig UI ドキュメント"
description: "1 行の overlay、独立パネル、容量上限付きの構造化 Console で、レイアウト・ヒットテスト・描画・パフォーマンスの問題を素早く特定します。"
url: https://zenit.z.express/ja/docs/advanced/devtools
language: ja
alternate_en: https://zenit.z.express/docs/advanced/devtools.md
alternate_zh: https://zenit.z.express/zh/docs/advanced/devtools.md
alternate_es: https://zenit.z.express/es/docs/advanced/devtools.md
alternate_ko: https://zenit.z.express/ko/docs/advanced/devtools.md
alternate_fr: https://zenit.z.express/fr/docs/advanced/devtools.md
alternate_de: https://zenit.z.express/de/docs/advanced/devtools.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# DevTools

1 行の overlay、独立パネル、容量上限付きの構造化 Console で、レイアウト・ヒットテスト・描画・パフォーマンスの問題を素早く特定します。

## ウィンドウ内インスペクター

開発中は overlay をルートにアタッチします。ホバーするとノードの rect を破線の枠で示し、サイズとコンポーネント名を表示します。overlay 自体は pass-through で、クリックやスクロールを横取りせず、ホバー時も描画レベルの更新だけを行い、再レイアウトは発生しません。

`main.zig`

```zig
fn mountUi(cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node {
    const root = try mountProductUi(cx, scope);

    // Development only: hover highlight with size + component name.
    _ = try ui.devtools.overlay.attach(cx, scope, root, .{});
    return root;
}
```

overlay の状態は渡した `scope` に保持され、その Scope が破棄されると overlay も一緒に取り除かれます。製品ウィンドウで「この領域を占めているのは誰か」をすぐ確認するのに向いており、完全な診断には独立パネルを使います。どちらも実際の Node / Cx の状態を読み取るため、デバッグ用のミラーモデルを別途維持する必要はありません。

## 症状別の診断

| 症状 | まず確認 |
| --- | --- |
| 配置がずれる | 親ノードの rect、padding、gap、direction（Elements → Layout） |
| 広い空白部分もクリックできてしまう | ヒットしたノードのサイズと `hit_behavior` |
| テキストのデータは変わったが画面が変わらない | TextProps のフィールドを直接書き換えて `setText` / `setTextContent` を呼んでいないのでは？ この 2 つの API は自分で比較し、sizing / render dirty をマークします |
| 幅を変えてもレイアウトが動かない | `node.style` に直接代入しても dirty はマークされません。`node.setStyle(alloc, .width, v)` を使えば、フィールドごとに適切な dirty レベルが選ばれます |
| だんだん遅くなる | 重複した mount、Scope とともに解放されない Effect、毎フレームのアロケーション（Performance → Summary / Rebuild） |

## DevTools パネル

Elements、Components、Console、Performance の完全なビューが必要なときは `ui.devtools.mountPanel(cx, target, opts)` を使います。パネルは自前の Cx を持ち、別の target Cx を観察します。[MultiWindowApp](https://zenit.z.express/ja/docs/advanced/multi-window) で独立ウィンドウに置けば、製品 UI を隠しません。パネル使用中は target が生存している必要があります。

`main.zig`

```zig
const std = @import("std");
const ui = @import("ui");
const zenit_app = @import("zenit_app");

// mountProductUi: your app's ordinary mount function (see above).
var g_target_cx: ?*ui.Cx = null;

fn mountDevTools(cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node {
    _ = scope;
    const target = g_target_cx orelse return error.TargetNotReady;
    return ui.devtools.mountPanel(cx, target, .{ .title = "My App DevTools" });
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var application = zenit_app.MultiWindowApp.init(gpa.allocator(), .{});
    defer application.deinit();

    const product = try application.createWindowWith(.{
        .window = .{ .width = 900, .height = 640, .title = "My App" },
    }, mountProductUi);
    g_target_cx = product.cx;

    const tools = try application.createWindowWith(.{
        .window = .{ .width = 760, .height = 560, .title = "DevTools" },
    }, mountDevTools);
    _ = ui.devtools.setViewMode(tools.cx, "performance"); // optional start tab

    try application.run();
}
```

これがリポジトリの `zig build devtools-probe` の構成です。`ui.devtools` には `setViewMode`、`setTreeFilter`、`setConsoleFilter` などの関数もあり、プローブや E2E からパネルをプログラムで操作できます。

[![Zenit DevTools Elements panel with a box selected and its layout details](https://zenit.z.express/media/devtools-elements.png?v=1c99ec3edc)](https://zenit.z.express/media/devtools-elements.png?v=1c99ec3edc)

左はライブの UI ツリー。ノードを選択すると、右の Layout タブに computed rect、padding、sizing、flex プロパティが表示されます。スクリーンショットの手のカーソルは harness の仮想カーソルです。

### 4 つのビューと 6 つの詳細タブ

| ビュー | 答える問い |
| --- | --- |
| **Elements** | 実際のノード階層、tag / id / text、レイアウトとヒット範囲はどうなっているか？ |
| **Components** | どのノードがコンポーネント境界か、その状態と所有者 Scope はどこか？ |
| **Console** | target Cx はどの構造化ログを捕捉したか、追い出しや破棄はあったか？ |
| **Performance** | target は描画中かアイドルか？ layout / render / cache / interaction のコストは？ |

Elements / Components の行を選択すると、**Layout、Style、State、Events、Render、Trace** を切り替えられます。Style の一部の値はライブ編集でき、Render / Trace では dirty になった理由と最近のイベントを確認できます。ツリー検索は tag、`#id`、コンポーネント名に対応します。`ui.devtools.source_link` を設定すると、コンポーネント行からエディタの定義箇所へ直接ジャンプできます。

## Console ログ

各 `ui.Cx` はスレッドセーフで容量上限付きの Console を持ちます。1 回の呼び出しでターミナルに出力しつつ、DevTools や E2E harness 向けに構造化イベントとして保持でき、パネルを開く前に捕捉された履歴も表示されます。

`logging.zig`

```zig
const log = cx.console();

log.info("application ready", .{});
log.scoped("network").warn("retry {d}", .{attempt});

// Plain level methods don't record a call site; writeAt does.
log.writeAt(.err, @src(), "save failed: {s}", .{@errorName(err)});
```

レベルは `debug`、`log`、`info`、`warn`、`err` です。さらにブラウザの Console に対応する `group` / `groupEnd`、`count`、`time` / `timeEnd`、`assert`、`trace`、`inspect`、`table` もあります。

| パネル領域 | 用途 |
| --- | --- |
| **Clear** | 表示だけでなく、target の Console ストアそのものを消去します。 |
| **Filter** | message と scope を大文字小文字を区別せずに照合し、レベルフィルタと組み合わせて適用されます。 |
| **Levels** | Debug / Log / Info / Warn / Error を任意の組み合わせで切り替えます。 |
| **ログ一覧** | レベル、scope、メッセージ、group のインデント、任意のソース位置を表示します。最下部から離れると自動追従が一時停止します。 |
| **ステータスバー** | shown / captured / evicted / dropped で、フィルタ・追い出し・ログ喪失を区別します。 |

[![Zenit DevTools Console with debug, info, warn and error entries](https://zenit.z.express/media/devtools-console.png?v=1411f611cd)](https://zenit.z.express/media/devtools-console.png?v=1411f611cd)

ログはパネルを開く前に target Cx の有界ストアに入っています。scope、レベル、ソース位置はすべて保持されます。

[![Zenit DevTools Console filtered to the network scope](https://zenit.z.express/media/devtools-console-filter.png?v=acfa3d9446)](https://zenit.z.express/media/devtools-console-filter.png?v=acfa3d9446)

Filter と Levels は DevTools 内でローカルに組み合わされ、target のストアのイベントは削除されません。

[Video](https://zenit.z.express/media/devtools-console.mp4?v=05e8c163e3)

実際の 2 ウィンドウアプリ。仮想カーソルが Elements から Console に切り替え、Filter にフォーカスして network と入力します。映像は DevTools ウィンドウの Metal drawable から直接録画しています。

通常のレベルメソッドは呼び出し位置を記録しません。ログをクリックしてエディタへジャンプしたい場合は `writeAt(level, @src(), …)` を使い、`ui.devtools.source_link.configure` でソースルートとエディタコマンド（既定は `code --goto`）を設定します。

### キャプチャの設定

`main.zig`

```zig
const app = try zenit_app.App.init(allocator, .{
    .console = .{
        .terminal_level = .info, // null disables the terminal sink
        .capture_level = .debug, // null disables in-memory capture
        .max_entries = 10_000,
        .max_bytes = 8 * 1024 * 1024,
        .max_entry_bytes = 64 * 1024,
    },
});
```

`console` を渡さない場合、`zenit_app` はビルドモードに応じて既定値を選びます。

| ビルドモード | ターミナル | メモリ内キャプチャ |
| --- | --- | --- |
| `Debug` | `.debug` | `.debug` |
| `ReleaseSafe` | `.info` | `.info` |
| `ReleaseFast / ReleaseSmall` | `.warn` | `null`（オフ） |

> WARNING
> 
> **Release ビルドは既定でキャプチャしません。** ReleaseFast / ReleaseSmall では DevTools から履歴ログは見えません。本番ビルドで必要な場合は `capture_level` を明示的に設定し、トークン・パスワード・個人データをログに記録しないでください。

Console が対応するのはブラウザ Console のログ収集・閲覧機能であり、Zig / JavaScript の REPL ではありません。Group は現在インデントのみで、インタラクティブな折りたたみはできません。`table` は現在テキストとして出力されます。完全な API、スレッドとライフタイムの制約、harness の例はリポジトリの `docs/CONSOLE.md` を参照してください。

## Performance：アイドルとフリーズの区別

Performance ビューは「直近 N 個の描画フレーム」を切り取って固まるわけではありません。100 ms の実時間バケットで target を継続的に観測します。バケットは 64 個、約 6.4 秒のローリングウィンドウで、FPS は直近 10 バケット（約 1 秒）の平均です。target が 0.7 秒以上新しいフレームを出さないと、読み値は `FPS: 0 — idle (not rendering)` と明示されます。これはフレームワークが省電力のため意図的に描画を止めている状態で、0 FPS のフリーズではありません。

100MS BUCKETS

フレームが止まってもグラフは進み続け 0 を記録します。読み値は空のバケットとともに下がり、0.7 秒を超えると idle に切り替わります。古い値を現在値として見せることはありません。

[![Zenit DevTools Performance showing FPS 0 idle (not rendering) with timing metrics](https://zenit.z.express/media/devtools-performance.png?v=41f18a12a0)](https://zenit.z.express/media/devtools-performance.png?v=41f18a12a0)

静的な target は描画を停止しています。DevTools 自身は約 10 Hz の低頻度で更新してグラフを進め、layout、render、cache、focus、interaction の指標は引き続き読み取れます。

| 読み値 | 意味 |
| --- | --- |
| FPS + ローリンググラフ | 実時間バケット。フレームのないバケットは 0 を記録して中立のベースラインとして描かれ、古い値を現在値として扱いません |
| Timing | target の直前フレームにおける layout、render コマンド生成などの CPU 実時間 |
| Summary / Interaction | hit registry、mouse-hit、redraw streak、focus と interaction rebuild |
| Cache / Rebuild | retained cache のヒット / ミス、full / partial rebuild |

## テストの入口

```sh
zig build test-headless
zig build test-ui
zig build test-render
zig build hello-button
```

> WARNING
> 
> **内部ファイルに対して zig test を単独で実行しないでください。** zenit のモジュールはディレクトリをまたいでインポートし合うため、`build.zig` で定義されたテスト step を使ってください。そうしないと `import of file outside module path` に遭遇することがあります。完全な一覧は [コマンド一覧](https://zenit.z.express/ja/docs/reference/commands)、実ウィンドウのテストは [E2E 自動化](https://zenit.z.express/ja/docs/advanced/e2e) を参照してください。

## リリース前チェック

-   **デバッグ UI をオフにする。**inspector overlay を取り除くか、debug 用の設定で開発ビルドのときだけマウントします。
    
-   **実ウィンドウで入力を検証する。**キーボード、IME、クリップボード、VoiceOver。
    
-   **ビルドゲートを実行する。**headless、UI、render 関連のテスト step。
    
-   **Console の方針を確認する。**Release のターミナルレベルとキャプチャ設定が意図どおりで、ログに機密データが含まれていないこと。
    
-   **バージョンを固定する。**zenit の revision をロックし、対象の Zig バージョンを記録します。
