Zig を用いた型安全な HTML テンプレート処理

2026/10/12 14:02

Zig を用いた型安全な HTML テンプレート処理

RSS: https://news.ycombinator.com/rss

要約▶

Japanese Translation:

著者は、Go の

Templ
を模倣した Zig 向けの新しいテンプレートライブラリ
zt
を紹介します。
zig build
実行時にテンプレートは解析され、Zig コードへと変換(transpile)されます。これにより、アプリケーションの型をインポートし、完全な型の安全性を実現できます。すべての入力はコンパイル時にチェックされ、出力は割り当てや中間状態なしに
std.Io.Writer
へ直接書かれます。これにより、実行時のテンプレートエラーやメモリ問題を回避します。組み込みの XSS 保護機能により、テキストと属性がデフォルトでエスケープされ、
href
/
src
における危険なスキーマは明示的にチェックされ、生の HTML を使用するには
{!value}
シンタックスが必要です。パーサーは要素の適切に閉じることを強制し、テンプレートエラーを Zig コンパイラーエラーとして提示し、行ごとのコメントにより元ソースへの位置を示します。
if
、
for
、
switch
などの制御構造は Zig で動作し、ペイロードキャプチャも引き続きサポートされています。既知の制限として、
if
、
for
、
switch
から始まる行がコードと誤って解釈されるブロックレベルの解析曖昧さが存在します。同プロジェクトは一部利用が進んでいるものの未成熟であり、より広範な産業での採用を可能にするために、GitHub issue や Zig Discord へのフィードバックを歓迎しています。

本文

Zig テンプレートエンジン「z」の紹介と活用方法

長年にわたり Web 開発に従事してきました。HTML生成のためのアプローチを多岐にわたって試行錯誤しました。

  • 初期〜2000 年代: PHP、Python の文字列連結、Smarty、Template Toolkit、Jinja/Django など
  • その後: SPA(シングルページアプリケーション)の潮流を受け、フロントエンド開発から離れることを選択

しかし、Zig という言語との出会いにより、Web 開発の展望が全く変わることを知らされました。

なぜ Zig で Web 開発が可能なのか?

当初は「低レベルな言語」で Web を扱うのは非現実的だと思っていましたが、実際には驚くほど管理可能です。

  • メモリ管理: アリーナアローケーター(arena allocator)を活用することで、文字列の解放を手動で行う必要がありません。
  • 高水準インターフェース:
    comptime
    を活用し、パフォーマンスを損なわずに高レベルな API を構築できます。
  • SPA 構築:
    htmx
    や
    Datastar
    を組み合わせることで、JavaScript/TypeScript を触らずに SPA を実装可能です。

テンプレートエンジンへの要件と発見

動的言語時代を経て、型安全性と安全性を最優先したテンプレートエンジンを求めました。

理想の要件

  1. 型安全性: コンパイル時に入力をチェックしたい(実行時エラーは嫌)。
  2. 高速性: メモリ割り当てなし、中間状態なし。
    std.Io.Writer
    に直接出力する方式が望ましい。
  3. 安全なデフォルト: XSS 対策として、すべての入力をデフォルトでエスケープする機能が必要。
  4. HTML の直感性: DSL と戦うことなく、HTML そのままを書く感覚を重視。

これらの要件を満たす既存ライブラリは見つからず、

Ziex
や
Templ
(Go)のアイデアを得た結果、Zig 向けの
z
(旧称:Templ の適応版)
というプロジェクトが発見されました。

「z」の特徴と仕組み

z
は Templ を Zig で実装したものであり、以下の点が特徴です。

  • トランパイル: テンプレートはビルド時に解析され、Zig コードへと変換(トランパイル)されます。
  • 双方向インポート: アプリコードからテンプレートをインポートできるだけでなく、テンプレート側からアプリコードを直接インポートできます。これにより、すべてのパラメータを完全に型付け可能になります。
  • コンパイラによる検証: 無効なデータや参照不能な変数は、レンダリング前に Zig コンパイラがエラーとして検知します。
  • 出力制御: ソケット直出またはバッファ集積など、柔軟に
    std.Io.Writer
    に出力できます。

テンプレート記法の実例

const User = @import("../models.zig").User;

pub templ Layout(title: []const u8) {
    <!DOCTYPE html>
    <html>
        <head>
            <title>{title}</title>
        </head>
        <body>
            @children
        </body>
    </html>
}

pub templ HomePage(user: ?User) {
    @Layout("Home") {
        if (user) |u| {
            <h1>Welcome back, {u.name}!</h1>
            <a href="/users/{u.id}">Your profile</a>
        } else {
            <h1>Welcome, guest!</h1>
            <a href="/login">Log in</a>
        }
    }
}

アプリケーション側での利用

Zig コードからテンプレートを呼び出す際、型安全な方法で実行できます。

const std = @import("std");
const User = @import("models.zig").User;
const pages = @import("templates/pages.zig");

pub fn main(init: std.process.Init) !void {
    var buf: [4096]u8 = undefined;
    var stdout = std.Io.File.stdout().writer(init.io, &buf);
    const w = &stdout.interface;

    const user: User = .{ .id = 1, .name = "Lukas" };
    try pages.HomePage.render(.{user}, w);
    try w.flush();
}

Dusty フレームワーク内での簡易レンダリング例:

try res.render(.html, pages.HomePage, .{user});

注意: 上記のコードスニペットには、

std.Io
のキャンセル処理に関する未解決の問題(バグ)が含まれる可能性があります。詳細については後述します。

セキュリティとエラーハンドリング

このツールの最大の利点は、セキュリティとデバッグ体験にあります。

セキュリティ対策

  • 自動エスケープ: 動的値はテキストおよび属性ともにデフォルトで HTML エスケープされます。
  • URL 検証:
    href
    や
    src
    などの URL 属性には、危険なスキーマのチェックが組み込まれます。
  • 生の HTML 出力:
    {!value}
    という明示的な構文を使用する以外はすべてエスケープされるため、XSS の一般的な原因を防ぎます。
  • 構文エラー防止: パーサーは要素の閉じ方を厳密にチェックするため、壊れたマークアップを生成することを防ぎます。

コンパイル時の型チェック

テンプレート内の記述ミスがコンパイルエラーとして即座に検出されます。

誤記入力の例:

u.name
を
u.nmae
と間違えた場合

src/templates/pages.zig:45:43: error: no field named 'nmae' in struct 'models.User'
            try zt.writeEscaped(writer, u.nmae); // pages.zt:18:31
                                          ^~~~
src/models.zig:1:18: note: struct declared here
pub const User = struct {
                 ^~~~~~
  • エラーメッセージには、生成されたコードの位置と、元のテンプレート内の行番号(コメント)が含まれています。
  • 型不整合(例:文字列を
    ?User
    を期待する場所へ渡す)もコンパイルで阻止されます。

高度な機能

基本的な記法に加え、以下のような強力な機能が備わっています。

  • コンポーネント: 再利用可能なコンポーネントを構築し、値として渡すことができます。
  • レイアウト継承:
    @children
    を用いて他のテンプレートをラップでき、他言語におけるテンプレート継承に相当します。
  • 制御フロー:
    if
    ,
    for
    ,
    switch
    など、純粋な Zig の制御構造がそのまま利用可能です。
  • パフォーマンス: すべては割り当てなしの一連の書き出し命令としてコンパイルされます。

現在の課題と今後の展望

Dusty との連携

より複雑な Web アプリを構築する際は、

Dusty
と組み合わせることで動的 SPA も構築できます(詳細は Dusty の TODO 例 を参照)。

構文に関する議論

ブロックレベルの制御フローについて、以下の選択肢が検討されています。

  • 現状: Templ に倣って純粋な Zig で記述(
    if
    ,
    for
    ,
    switch
    はコードとして解析される)。
    • 欠点: 「パスワードをお忘れの場合は…」といった単独のテキスト行はパーサーエラーになるため、要素で囲むか文字列式とする必要があります。
  • 将来の提案: Razor や Twirl stile に倣い
    @if
    ,
    @for
    ,
    @switch
    を導入する検討中。
    • メリット: 曖昧性が解消される。
    • デメリット: テンプレートにノイズが発生するコストがある。

フィードバック募集: 構文に関するご意見は、GitHub の Issues でコメントを残していただけますと幸いです。

プロジェクトの成熟度

複数の利用者がいるものの、プロジェクトはまだ未成熟な段階です。

  • 問題が見つかった場合は、GitHub Issue を作成するか、Zig Discord 上でご連絡ください。
  • フィードバックを大歓迎します。

同じ日のほかのニュース

一覧に戻る →

2026/10/13 6:40

AI は道具です。それを巧みに使うには技術が必要です。

## 日本語翻訳: 本稿の核心的な論点は、大規模言語モデルは自律的な「自動化」ではなく、人間の技量が必要なツールであるというものである。これは、AI が独立した意思あるいは悪意を持って行動するという考え方を否定するものであり、ソフトウェアが「反逆する(rogue)」ように振る舞うなど、業界特有の成り行きや陰謀論的なナラティブに煽られておりやすい。物理的な器具が悪用され得るように、LLM もエンジニアリング上の制限によって予期せぬ出力を生み出すに過ぎず、エージェント性の喪失によるものではない。人間による判断が依然として中核をなすのは、ユーザーが盲目的に制御権を委ねるのではなく、フィードバックループ内で結果を検証し、プロンプトを見直し、変更を検証するからです。本稿は AI を記述するために使用される擬人化された言語を批判しており、「陰謀」などの用語は技術的な問題が存在する場所に人間の動意を不当に暗示することを示唆しているとしています。 今後の議論では、AI を別個の存在として描く枠組みから転じ、解釈への問いかけや誤りへの認識においてユーザーの専門性を育むことに焦点を移すべきです。開発者および企業に対しては、恐怖を煽る比喩ではなく正確な工学用語を採用することで、より良いリスク管理と説明責任を実現できます。真の熟達とは、どのような質問が重要かを理解し、熟練した運用と盲目的な委任を見極めることであり、不完全なパフォーマンスがツールの有用性や作業者の責任を否定するものではありません。

2026/10/13 1:13

C で構築されたモダンな Web アプリ

## Japanese Translation: 本テキストは、2026 年に C と CGI を OpenBSD 上で構築された独自の商用 Web アプリケーション「marketyour.games」について説明しています。このプロジェクトは現代のフレームワークよりも極度な簡潔性とセキュリティを優先しており、「BCHS」スタック(OpenBSD、C、httpd、SQLite)を採用し、外部のフレームワークや独立したデータベースサーバーは一切使用しません。核心的な革新点は、アプリケーション全体が静的にリンクされた単一のバイナリとして動作し、ランタイム依存関係がゼロであるというアーキテクチャにあります。デプロイはファイルを 1 つだけフォルダに配置するだけであり、古いバージョンを置き換えるだけで済みます。再起動やダウンタイムも不要です。 セキュリティは OpenBSD のデフォルト設定を通じて強制されており、httpd に対して `chroot` を適用し、C プログラムに対して `pledge` および `unveil` などのツールを使用して制約を課します。アーキテクチャは、すべての HTTP リクエストごとに新しいプロセスをフォークし、コードから直接アセットを提供することでメモリ内に完全に収まり、すべてのトラフィックを httpd を介して CGI バイナリにルーティングするという方式に基づいています。このアプローチでは JavaScript テンプレート言語を使用しない(プログレッシブ改善に従う)とともに、安定した CGI 1.1 規格に準拠しますが、使いやすさを犠牲にして制御性を追求します。 主な利点としては、サプライチェーンリスクが著しく低減すること—依存するのは C コンパイラーと 3 つのライブラリ(`libcurl`、`libsodium`、組み込み済みの `libcjson`)のみ—、そして GDB のような標準ツールによるデバッグが容易であることです。アプリケーションは通常の実行ファイルだからです。しかしながら、この手法では開発者がデータを解析するためのロジック(クッキー、クエリ、フォーム)やカスタムヘッダーの管理を自ら実装する必要があり、複雑な依存関係グラフではなく、基本的な HTTP 概念と Vim のような古典的なツール(プラグインなし)を活用する姿勢を選択します。

2026/10/13 4:40

ZX Spectrum 向けのデモシーンイントロを作成する

## Japanese Translation: 著者は、標準的な 128KB の ZX Spectrum にて手書きのレトロなイントロを成功裏に作成し、高度に最適化されたアセンブリ言語プログラミングにより複雑なビジュアルとオーディオを実現した。2 ヵ月間(2025 年 12 月から開始)にわたり、約 19KB のコード(具体的には 10287 バイトのメインルーチン)を書き下し、内蔵 ROM を書き換えることでカスタムフォント「Cartoon」を用いたスムーズなスクロールテキストを作成し、また Amiga モジュール「Milkman」を変換して 3 チャネル AY サウンドトラックを生成した。限られたメモリ制限を管理するため、アセットは BASIC ロードに分割され、ルーチンはオーバーヘッドを避けるために特定のアドレスでハードコーディングされた。技術的な最適化としては、Z80 RL 命令を用いてスクロールテキストの回転を実現し、スキャンライン衝突を避けるために Ruby で生成した座標テーブルを事前計算してスターフィールド効果を再現し、さらにサウンドチップから直接振幅レジスタを読み取ってバウンス VU メーターを実装している。プロジェクトは 1980 年代後半の Amiga クrack イントロに触発され、本物の Spectrum +3上でローカル TNFS サポートのある Makefile 駆動のビルドシステムを用いて開発された。最終的な.tap ファイルは Web ブラウザまたは pouet.net を経由して入手でき、レトロなハードウェア上で高忠実度な体験を提供し、極限を効率的に達成したコーディングの実証として立っている。

Zig を用いた型安全な HTML テンプレート処理 | そっか~ニュース