ブログ

  • 【テスト投稿】AI連携の動作確認用サンプル記事

    この記事は、WordPressとAIの連携(投稿の自動作成)が正しく動作するかを確認するためのテスト投稿です。実際の公開記事ではなく、動作チェックを目的としています。

    この投稿について

    AI経由で投稿の作成からプレビューまでが問題なく行えるかを確認しています。画像は含めず、テキストのみで構成しています。

    確認したい項目

    • 見出し(H2)が正しく表示されるか
    • 段落テキストが正しく表示されるか
    • 箇条書きリストが正しく表示されるか

    まとめ

    このテキストが意図したとおりに表示されていれば、基本的な投稿機能は正常に動作しています。確認が済んだら、この投稿は削除またはゴミ箱に移動して問題ありません。

  • テスト投稿:wp-ai-post-abilities 動作確認

    テスト投稿:wp-ai-post-abilities 動作確認

    これは wp-ai-post-abilities-dev MCPサーバーを使ったテスト投稿です。

    確認内容

    • ✅ コンテンツタイプの取得
    • ✅ 画像のアップロード(URLから)
    • ✅ 投稿の作成
    • ✅ アイキャッチ画像の設定
    • ⬜ 投稿の公開

    投稿日時:2026年5月28日

  • 2010年のFlexbox記事は、CSSレイアウトがfloatから解放される予告だった

    2010年のFlexbox記事は、CSSレイアウトがfloatから解放される予告だった

    Mozilla Hacksの「The CSS 3 Flexible Box Model」は、まだFlexboxが現在のdisplay: flex構文になる前、display: boxbox-flexで説明されていた時代の記事です。2010年の記事なので、そのまま今の実装ガイドとして読むものではありません。ただし、CSSレイアウトがfloatやtable的な発想から抜け出していく過程を読む資料としてはかなり面白い内容です。

    記事では、Flexible Box Modelを「子要素を親ボックスの中でどう並べ、余った空間をどう分配するか」を決める新しいボックスモデルとして紹介しています。XUL、XAML、GladeXMLのようなUI記述で使われる考え方に近く、ブラウザウィンドウやフォントサイズに合わせて変化する流動的なレイアウトに向いている、という位置づけでした。

    記事の要点

    • 当時の構文はdisplay: boxから始まる。 現在のdisplay: flexではなく、親要素にdisplay: boxまたはinline-boxを指定して、子要素をFlexible Box Modelで扱う説明になっています。
    • box-orientで縦横の軸を決める。 子要素を縦に並べるか横に並べるかを指定し、現在のflex-directionにつながるような役割を持っていました。
    • box-directionbox-ordinal-groupで視覚的な順序を変えられる。 HTML上の順番と表示順を分けられることが、当時から大きな利点として扱われています。
    • box-flexで余白を比率配分する。 子要素に柔軟性を持たせ、固定幅の要素と可変幅の要素を混ぜながら残りスペースを分ける発想が説明されています。
    • box-packbox-alignで余った空間の寄せ方を制御する。 中央寄せ、端寄せ、均等配置、stretchなど、今のFlexboxでよく使う配置の原型が見えます。

    リンク先も読むと見える変化

    記事内のW3C仕様リンクは、現在はCSS Flexible Box Layout Module Level 1へリダイレクトされます。現行仕様では、display: flex/inline-flexflex-directionflex-wrapjustify-contentalign-itemsなど、今のWeb開発で見慣れた名前に整理されています。2025年10月14日のCandidate Recommendation Draftとして公開されているページも確認しました。

    記事のデモリンク(http://hacks.mozilla.org/wp-content/uploads/2010/04/exemple-blog.html)は、確認時点では404でした。Shawn J. Goff氏の記事リンク(http://shawnjgoff.com/blog/css3-flexible-box-layout-module)も現在は名前解決できませんでした。一方で、CSS3.infoの紹介記事は参照でき、当時からGecko/WebKit実装の差やデモの見え方の違いが話題になっていたことがわかります。

    この古い記事と現行仕様を並べると、概念はかなり残りつつ、プロパティ名とモデルが整理されてきたことが見えます。たとえばbox-flexで比率を指定する考え方は、現在のflexflex-growを理解する入口になります。box-pack/box-alignは、現在のjustify-content/align-itemsのような役割へつながっています。

    気づき

    この記事の価値は、古い構文を学べることではなく、CSSが「文書を上から下へ流す」だけのモデルから、「利用可能な空間を部品同士で交渉して分ける」モデルへ移っていく瞬間が見えることだと思います。今ではFlexboxは当たり前の道具ですが、2010年の記事では、中央寄せ、順序変更、sticky footer、流動レイアウトがまだ長年の悩みとして語られています。

    つまりFlexboxは、単に便利なプロパティ群ではなく、CSSにUIレイアウトの語彙を足した転換点でした。古いdisplay: boxの説明を読むと、現在のFlexboxがなぜmain axiscross axisflexalignmentという構成になっているのかも少し見えやすくなります。

    参照した記事

  • Protocol Buffersは、Rust共有コンポーネントのFFI境界を「スキーマ」で守る選択だった

    Protocol Buffersは、Rust共有コンポーネントのFFI境界を「スキーマ」で守る選択だった

    Mozilla Hacksの「Crossing the Rust FFI frontier with Protocol Buffers」は、Firefox SyncなどのMozilla Application Servicesを、複数プロダクトで再利用できるRust共有コンポーネントへ寄せていく過程を紹介した記事です。

    当時の課題は、Firefox Desktop、Android、iOSで同じような機能を別々の実装として持っていたことでした。SyncであればJavaScript、Java、Swiftの実装が並び、機能差やバグ修正の反映漏れが起きやすくなります。そこで中核ロジックをRustで共通化し、各プラットフォームにはKotlinやSwiftなどの薄いラッパーを置く方針が採られました。

    記事の要点

    • 狙いは、Firefox機能の中核ロジックを1つのRustコードベースへ集約すること。 修正や改善を各プロダクトへ個別移植するのではなく、共通コンポーネントのバージョン更新として届けられるようにします。
    • 難所はFFI境界のデータ受け渡しだった。 Rustの所有権・メモリ安全性を守りながら、KotlinやSwift側にリッチな構造化データを渡す必要があります。
    • 初期案ではJSON文字列やC風structを使っていた。 JSONは扱いやすい一方でシリアライズ/デシリアライズの負荷があり、型変更を各言語側で手作業追従する必要があります。C風structのポインタ受け渡しは、定義のズレがメモリ破壊につながり得ます。
    • Protocol Buffers v2により、.protoスキーマを単一の情報源にした。 Rust側と利用側のデータクラスを同じスキーマから生成できるため、境界の形を手作業で合わせる危険が減ります。
    • Rust側ではprostを使っていた。 Rustのderive macroを活かし、生成されるstructがRustらしく扱える点が選択理由として説明されています。

    リンク先も読むと見える流れ

    Application Servicesのリポジトリを見ると、この方針がFirefox Accounts、Sync、Push、ExperimentationなどをまたぐRustコンポーネント群として続いていることがわかります。現在のREADMEでは、共有Rustコードを各プラットフォーム向けのネイティブバインディングで包む構成が説明され、コンポーネントのFFI生成にはUniFFIも使われています。

    記事中で紹介されるffi-supportは、RustでFFIを扱うときの補助crateです。そもそもFFIは、異なる言語やランタイム間で関数やデータをやり取りする境界であり、そこでは型・メモリ所有・文字列表現の違いがそのままバグの入口になります。

    データ形式については、データシリアライズ形式の比較にあるように、多くの選択肢があります。この記事では、速度だけでなく、スキーマから複数言語の型を生成できることを重視してProtocol Buffersを選んでいます。prostはRust向けProtocol Buffers実装として、そのRust側の生成コードを担います。

    また、Firefox AccountsやWebPushのような機能は、単体アプリの内部実装ではなく、複数デバイス・複数製品へ広がるサービスの接点です。だからこそ、各プラットフォームで似たものを作るのではなく、共通ロジックと薄いネイティブ層に分ける設計の意味が大きくなります。

    気づき

    この記事で面白いのは、Rust化の価値を「速くなる」「安全になる」だけで語っていないところです。本当の焦点は、複数プラットフォームへ同じ機能を届けるための保守境界をどこに置くかです。Rustを中核に置くことでロジックは共有できますが、FFI境界の設計が弱いと、結局Kotlin側やSwift側で型のズレを手作業で吸収することになります。

    その意味でProtocol Buffersは、単なる高速なバイナリ形式というより、チーム間・言語間の契約をファイルとして固定する道具として効いています。後年のUniFFIの流れを見ると、この2019年の記事は「Rustで共有する」だけでなく、「共有したRustをどう安全に各言語へ見せるか」というMozillaの試行錯誤の途中段階として読めます。

    参照した記事

  • Rust 2018は、新バージョンではなく「生産性の節目」として設計された

    Rust 2018は、新バージョンではなく「生産性の節目」として設計された

    Mozilla Hacksの「Rust 2018 is here… but what is it?」は、Rust 2018 editionを「新しい言語バージョン」としてではなく、Rustをより実用的に使えるようにする節目として説明した記事です。著者はLin Clark氏とRust Teamで、同日に公開されたRust公式ブログのRust 1.31/Rust 2018発表とも対応しています。

    この記事の軸は、Rust 2018が破壊的変更をまとめて導入するための仕組みでありながら、既存コードを壊さないように設計されている点です。editionはcrate単位で指定でき、依存関係全体を一斉に移行する必要はありません。既存コードはRust 2015のまま動き続け、必要になったcrateだけがRust 2018へ進めます。

    記事の要点

    • Rust 2018は、通常の「新バージョン」とは違う。 互換性のある改善はRust 2015にも入り、互換性に影響する構文やキーワードだけをeditionで分ける考え方です。
    • 移行はcrate単位で、cargo fixが支援する。 Cargo.tomlにedition = "2018"を指定する前に、ツールが移行に必要な修正をかなり自動化できます。
    • async/awaitなど、将来の構文のための準備も含まれていた。 記事公開時点では機能本体がまだ揃っていないものもありましたが、予約語として先に場所を確保しています。
    • module systemの整理も大きい。 crate::などの導入により、外部crateとcrate rootの区別を読みやすくする方向へ進みました。
    • 言語仕様だけでなく、用途別の生産性も主役だった。 WebAssembly、embedded、networking、command line toolsの4領域にworking groupを置き、Rustを具体的な用途で使いやすくする取り組みが進められました。

    リンク先も読むと見える広がり

    公式ブログのRust 1.31/Rust 2018発表では、non-lexical lifetimes、module systemの変更、Clippy、rustfmt、IDE支援、domain working groupsなどが、同じ「Rust 2018」というまとまりで扱われています。Mozilla Hacksの記事は、この公式発表をより視覚的に、背景込みで読める入口になっています。

    WebAssembly領域では、web-sys/js-syswasm-packRust and WebAssembly Bookが参照されています。RustをWebアプリ全体へ置き換えるのではなく、重い処理や型安全にしたい部分へ小さく差し込む発想が見えます。

    embedded領域では、The Embedded Rust Bookが案内されます。記事では、nightly依存だった体験をstableへ近づけ、ARM Cortex-M向けの開発を現実的にする流れが説明されています。これは「言語の安全性」だけではなく、対象デバイス・CI・ドキュメントまでそろわないと生産性にならない、という話です。

    CLI領域では、ripgrepのような複雑なツール、panic時の出力を人間向けにするhuman-panic、設定ファイルまわりを簡略化するconfyが例として挙げられています。Rustの強みを「速くて安全な低レベル言語」に閉じず、配布しやすい単一バイナリや使いやすいCLI体験につなげている点が印象的です。

    気づき

    この記事を読むと、Rust 2018の本質は「新機能の一覧」ではなく、互換性を壊さずにエコシステムを前へ進める運用設計だったとわかります。editionで破壊的変更を小さく閉じ込め、cargo fixで移行作業を支援し、同時にドメイン別のworking groupやツール整備を進める。言語の進化を、仕様だけでなく移行経路と利用場面まで含めて設計しているところが重要です。

    特に興味深いのは、Rust 2018が「Rustを書く人の体験」を中心に据えている点です。borrow checkerの改善、module pathの整理、rustfmtやClippyの安定化、WebAssemblyやembeddedの教材整備は、どれも学習や日常開発の摩擦を減らすものです。パフォーマンスや安全性だけでは言語は広がらず、使い続けられる環境まで整って初めて生産性になる、という判断が見えます。

    参照した記事

  • メモリ管理入門は、ArrayBufferを読む前に「確保・参照・解放」を整理してくれる

    メモリ管理入門は、ArrayBufferを読む前に「確保・参照・解放」を整理してくれる

    Mozilla Hacksの「A crash course in memory management」は、ArrayBufferとSharedArrayBufferの解説シリーズの第1回です。主題は低レベルAPIそのものではなく、その前提になる「メモリとは何か」「プログラムはいつメモリを確保し、いつ手放すのか」という基礎の整理です。

    記事は、メモリを同じ大きさの箱が並んだものとして説明します。値を保存するには、その値をビット列に変換し、空いている場所を探して置く必要があります。数字だけでなく文字も、UTF-8のようなエンコーディングを通して数値化され、取り出すときには逆向きにデコードされます。

    記事の要点

    • JavaScriptでは、JSエンジンがメモリ操作を仲介する。 変数やオブジェクトを作ると、エンジンが値を内部表現へ変換し、置き場所を確保します。
    • 自動メモリ管理では、到達不能になった値をガベージコレクションが回収する。 開発者は直接メモリを解放しませんが、その分、実行時のオーバーヘッドや性能の読みにくさが生まれます。
    • Cのような手動メモリ管理では、malloc/freeで確保と解放を明示する。 細かく制御できる反面、解放忘れはメモリ不足につながり、早すぎる解放はバグやセキュリティ問題になります。
    • WebAssemblyの文脈では、この違いが重要になる。 CなどをWebAssemblyへコンパイルすると、JavaScriptとは異なるメモリ管理モデルがブラウザ内に入ってくるためです。

    リンク先も読むと見える流れ

    同じシリーズの第2回「A cartoon intro to ArrayBuffers and SharedArrayBuffers」では、ArrayBufferがJavaScriptの中で「バイト列として扱うメモリ」を提供する仕組みとして説明されています。通常の配列とは違い、ArrayBufferそのものは値の型や区切りを知らず、TypedArrayなどのviewを通して解釈します。

    さらに第3回「Avoiding race conditions in SharedArrayBuffers with Atomics」へ進むと、SharedArrayBufferで複数のworkerが同じメモリを読んだり書いたりできる代わりに、race conditionの問題が出てくることがわかります。Atomicsは、単一操作の競合、ロック、命令の並べ替えといった問題を抑えるための土台として扱われています。

    補助リンクとして、2進数の説明やUTF-8の説明、そしてWebAssembly入門も参照されています。これらを合わせると、この記事は単なるメモリ管理の入門ではなく、WebAssembly、ArrayBuffer、SharedArrayBufferへ進むための地ならしになっています。

    気づき

    この記事で大事なのは、「自動管理か手動管理か」という二択だけではなく、メモリの責任がどこに置かれているかを意識することだと感じました。JavaScriptでは多くの責任をエンジンが引き受けますが、ArrayBufferを使うと開発者側に少しだけ低レベルな責任が戻ってきます。SharedArrayBufferではその責任がさらに広がり、複数の実行主体が同じメモリを扱うため、Atomicsのような同期の考え方が必要になります。

    つまりこの第1回は、後続記事を読むための用語解説ではなく、「便利な抽象化の下で、誰がメモリの寿命を管理しているのか」を見直す記事です。普段のJavaScriptでは見えにくい部分を先に理解しておくと、ArrayBufferやWebAssemblyの設計意図もかなり読みやすくなります。

    参照した記事

  • SharedArrayBufferは、JavaScriptに“共有メモリ”を持ち込むための危険で強い道具だった

    SharedArrayBufferは、JavaScriptに“共有メモリ”を持ち込むための危険で強い道具だった

    Mozilla Hacksの「A cartoon intro to ArrayBuffers and SharedArrayBuffers」を読みました。SharedArrayBufferとAtomicsを扱う3本シリーズの第2回で、ArrayBufferがJavaScriptにどのような低レベルメモリ操作の入口を与え、SharedArrayBufferがそれをworker間の共有メモリへ広げるのかを説明しています。

    前回紹介したAtomicsの記事は、共有メモリを使ったときの壊れ方をどう防ぐかの話でした。今回の記事は、その一つ手前にある「そもそもArrayBufferとSharedArrayBufferは何を可能にするのか」を整理する内容です。

    記事の要点

    • JavaScriptは通常、自動メモリ管理を備えた言語ですが、ArrayBufferを使うと一部のデータをより低レベルに扱えます。
    • ArrayBuffer自体は、0と1が並んだ生のメモリ領域のようなものです。
    • ArrayBufferを直接読むのではなく、Int8ArrayやUint16Arrayなどのtyped array viewを通じて、同じbit列をどの単位で解釈するかを決めます。
    • 同じArrayBufferに複数のviewを重ねると、同じbit列でも異なる数値として扱えます。
    • Web Workerを使うとJavaScriptの処理をmain threadから分けられますが、通常はmemoryを共有せず、postMessageでデータをコピーします。
    • ArrayBufferはtransferにより、コピーではなく所有権を移すことができます。ただし移した後は元のworkerから使えません。
    • SharedArrayBufferは、複数のworkerが同じmemory blockを同時に読み書きできるようにします。
    • その代わり、同時アクセスによるrace conditionが起きるため、次の記事で扱われるAtomicsが必要になります。

    リンク先も見てわかったこと

    シリーズ第1回の「A crash course in memory management」では、JavaScriptの自動メモリ管理と、Cのような手動メモリ管理の違いが説明されています。ArrayBuffer記事は、その前提の上に「JavaScriptでも必要な場面ではより低レベルなメモリ表現を扱える」という位置づけです。

    MDNのArrayBufferSharedArrayBufferページも確認しました。特にSharedArrayBufferについては、2017年記事のステータス説明をそのまま現在情報として読むのではなく、現在はSpectre以降のセキュリティ要件としてsecure contextとcross-origin isolatedが必要になる点を押さえておく必要があります。

    Web WorkersWorker.postMessage()のMDNページも、この記事の背景を理解するのに役立ちます。postMessageはworker間通信の基本ですが、大きなデータをコピーするコストが課題になります。ArrayBufferのtransferとSharedArrayBufferの共有は、そのコストをどう避けるかという文脈で出てきます。

    気づき

    今回の気づきは、SharedArrayBufferは「速くするAPI」というより、「コピーしないで済む代わりに、責任を開発者側へ戻すAPI」だという点です。通常のJavaScriptでは、メモリの割り当てや解放、worker間のデータ隔離はエンジンやプラットフォームがかなり面倒を見てくれます。SharedArrayBufferは、その保護を一部ゆるめることで、より低レベルで高速な協調処理を可能にします。

    ただし、共有メモリは便利さと危険がセットです。コピーやtransferなら所有者が比較的はっきりしていますが、SharedArrayBufferでは複数のworkerが同じ場所を同時に見るため、読み書きの順序を考えなければなりません。だから次の記事でAtomicsが必要になる。ArrayBuffer、SharedArrayBuffer、Atomicsは、低レベル化の階段として読むと流れがかなりわかりやすくなります。

    また、2017年当時の記事と現在のMDNを見比べると、Webの低レベル機能は性能だけで決まらないことも見えます。Shared memoryはWebAssemblyのthreadsにもつながる重要な基盤ですが、Spectre以降はセキュリティ境界とセットで扱う必要があります。低レベル機能ほど、性能、使いやすさ、安全性の三つを同時に設計しないといけないのだと感じました。

    読むとよさそうな人

    • ArrayBufferとTypedArrayの関係をざっくり理解したい人
    • Web WorkerのpostMessage、transfer、shared memoryの違いを整理したい人
    • SharedArrayBufferとAtomicsがなぜセットで語られるのか知りたい人

    参照した記事

  • Atomicsは、SharedArrayBufferの速さより先に“壊れ方”を制御するための土台だった

    Atomicsは、SharedArrayBufferの速さより先に“壊れ方”を制御するための土台だった

    Mozilla Hacksの「Avoiding race conditions in SharedArrayBuffers with Atomics」を読みました。SharedArrayBufferとAtomicsを扱う3本シリーズの第3回で、共有メモリを使うときに起きるrace conditionと、それをAtomicsがどう抑えるのかを説明しています。

    この記事は、前回紹介したQuantum CSS / Styloの記事からdata raceの背景として参照されていました。StyloはRustでdata raceをコンパイル時に防ぐ話でしたが、今回の記事はJavaScriptの低レベル共有メモリAPIで、開発者が何に気をつけるべきかを説明しています。

    記事の要点

    • SharedArrayBufferは複数スレッドで同じメモリを共有できるため、race conditionを起こしやすくなります。
    • 記事は、アプリ開発者がSharedArrayBufferやAtomicsを直接使うことは想定しにくく、経験のあるライブラリ作者が抽象を作るためのAPIだと説明しています。
    • 単一操作に見えるインクリメントも、CPUレベルでは読み込み、計算、書き戻しに分かれるため、スレッド間で混ざると値が壊れます。
    • Atomics.add などは、そうした複数ステップの操作を不可分なatomic operationとして扱えるようにします。
    • Atomics.compareExchange は、値を読んで計算し、他スレッドに更新されていなければ書き戻す、という再試行型の操作に使えます。
    • 複数操作をまとめて守りたい場合はlockが必要になり、Atomics.waitAtomics.wakecompareExchangestore などでライブラリ作者がlockを作れます。
    • CPUやコンパイラは高速化のために命令を並べ替えることがあり、マルチスレッドではそれがrace conditionになることがあります。
    • Atomics.loadAtomics.store は、メモリ操作の順序を守るためのfenceのような役割を果たします。

    リンク先も見てわかったこと

    シリーズ前半の「A crash course in memory management」では、メモリを値としてではなく、確保、参照、解放、再利用される資源として見る前提が説明されています。Atomics記事は、この前提の上に「複数の実行単位が同じメモリを見ると何が起きるか」を積み上げています。

    第2回の「A cartoon intro to ArrayBuffers and SharedArrayBuffers」は、ArrayBufferとSharedArrayBufferの違いを理解する入口です。共有できることは高速化や並列化につながりますが、共有するからこそ順序や排他制御が必要になる、という流れが第3回へ続いています。

    記事内で参照されているjs-lock-and-conditionは、SharedArrayBufferとAtomicsを使ったlockとcondition variableのサンプル実装です。リポジトリは現在inactiveですが、Atomicsが直接アプリロジックを書くためというより、こうした同期プリミティブを作るための部品だと理解しやすいリンクです。

    気づき

    今回の気づきは、Atomicsの価値は「共有メモリを速く使う」ことよりも先に、「共有メモリを使ったときの壊れ方を制御する」ことにあるという点です。共有メモリはコピーを減らせますが、読み書きの順序が曖昧になった瞬間に、結果は再現しづらいバグになります。

    特に印象的だったのは、race conditionが単一操作、複数操作、命令の並べ替えという複数の層で起きることです。インクリメントのような簡単な処理でも壊れますし、オブジェクト全体の更新にはlockが必要になります。さらに、ソースコード上の順序とCPUが実行する順序が一致するとは限らない。Atomicsは、こうした層ごとの危険に対して最低限の同期手段を提供しているわけです。

    これはQuantum CSSのRust採用とも対照的です。Rustはdata raceをコードの構造と型システムで防ごうとし、Atomicsは低レベルAPIとして開発者に明示的な同期手段を渡す。どちらも並列処理を可能にする技術ですが、片方は安全側へ寄せた抽象、もう片方は安全な抽象を作るための部品として見えるのが面白いところです。

    読むとよさそうな人

    • SharedArrayBufferとAtomicsがなぜ難しいのかを知りたい人
    • race condition、lock、atomic operation、memory orderingをざっくり整理したい人
    • JavaScriptの並列処理APIと、Rustのdata race防止の違いを比較して理解したい人

    参照した記事

  • Quantum CSSは、CSS計算をRustで並列化してFirefoxの描画前半を速くした

    Quantum CSSは、CSS計算をRustで並列化してFirefoxの描画前半を速くした

    Mozilla Hacksの「Inside a super fast CSS engine: Quantum CSS (aka Stylo)」を読みました。Firefox Quantum期に、Servo由来の新しいCSS engineであるQuantum CSS、当時の名前でStyloがFirefoxへ入っていく背景を説明する記事です。

    前回紹介したWebRenderの記事がpainting/compositing寄りの話だったのに対し、今回の記事はその手前、HTMLとCSSから各要素の見た目を計算するstyle computationの話です。

    記事の要点

    • Quantum CSSは、ServoからFirefoxへ移植された最初の大きなコンポーネントとして紹介されています。
    • CSS engineは、DOM nodeごとにどのCSS ruleが適用されるかを決め、各CSS propertyのcomputed valueを作ります。
    • その中核には、selector matchingとcascadeがあります。
    • CSS propertyは膨大なので、computed styleをそのまま全nodeに持たせるのではなく、fontなど関連する値をstyle structとして共有します。
    • Styloはstyle computationを複数CPU coreへ分散し、DOM treeの枝ごとに並列処理します。
    • DOM treeは不均等になりやすいため、work stealingで空いたcoreが他のqueueから仕事を取れるようにします。
    • Rustを使うことで、並列処理で怖いdata raceをコンパイル時に防ぎやすくしています。
    • Firefox由来のrule treeでrestyle時のselector matchingを減らし、Safari/Chrome由来のstyle sharing cacheを発展させて初回計算も高速化します。

    リンク先も見てわかったこと

    記事内から参照されているdata raceの説明記事を読むと、並列処理の難しさがよりはっきりします。複数の処理が同じデータへ同時に触ると、再現しづらいバグにつながります。StyloがRustを使った意味は、単に新しい言語を採用したことではなく、Firefoxの中核で安全に並列化するための土台を得たことにあります。

    また、記事中で紹介されているRustのparallelismやwork stealingに関する動画リンクも、Styloが「CSS engineをちょっと速くした」程度の話ではなく、ブラウザ内部の計算を現代的なCPUの複数coreへどう分散するかという話だと示しています。

    WebRender記事と合わせて読むと、Firefox Quantum期の設計方針が見えてきます。Styloはstyle computationを並列化し、WebRenderは描画側をGPU向けに再構成する。どちらも、既存のWeb互換性を保ったまま、内部の仕事の分け方を大きく組み替える取り組みでした。

    気づき

    今回の気づきは、Quantum CSSの速さは「CSS selectorを速く探す」だけではなく、「同じ仕事を繰り返さない」「並列化しても壊れない」「過去の最適化を捨てずに組み合わせる」という複数の設計が重なっている点です。

    並列化は目立つ要素ですが、それだけでは足りません。restyle時にはrule treeで以前のmatching結果を再利用し、似たnodeにはstyle sharing cacheでcomputed styleを共有します。さらに、その並列処理をRustで安全に書けるようにする。記事を読むと、性能改善は単一の特効薬ではなく、計算量、メモリ、再利用、安全性を同時に詰める仕事だとわかります。

    もう一つ印象的なのは、Quantum CSSが「4つのブラウザの先行技術を組み合わせた」と説明されていることです。Servoの並列化、Firefoxのrule tree、Safari/Chrome系のstyle sharing cacheなど、ブラウザ間で積み上がってきた知見をFirefoxの中に再構成している。Webエンジンの進化は、競争だけでなく、長年の実装知識の再利用でもあるのだと感じました。

    読むとよさそうな人

    • Firefox Quantum期の高速化で、Styloが何を担当したのか知りたい人
    • CSS engineがselector matchingとcascadeで何を計算しているのか整理したい人
    • Rustがブラウザ内部の並列処理にどう効いたのかを知りたい人

    参照した記事

  • WebRenderは、Web描画をゲームエンジンのように考えてjankを減らした

    WebRenderは、Web描画をゲームエンジンのように考えてjankを減らした

    Mozilla Hacksの「The whole web at maximum FPS: How WebRender gets rid of jank」を読みました。Firefox Quantum期の記事で、Servo由来の描画技術であるWebRenderが、なぜ単に「速い」だけでなく「滑らかさ」を重視していたのかを説明しています。

    この記事は2017年時点の内容で、WebRenderは当時Firefoxへ統合されていく途中の技術として紹介されています。前に紹介したFirefox 100のProcess Isolation記事ではWebRenderが前提技術として出てきましたが、今回の記事はそのWebRender自体がどんな発想で作られたかを掘り下げています。

    記事の要点

    • WebRenderの目的は、単に描画を速くすることではなく、60FPS以上の滑らかさを安定させることです。
    • ブラウザは1フレームを約16.67ms以内に描画する必要があり、この時間枠を超えるとフレーム落ちやjankとして見えます。
    • 従来のブラウザは、変更部分だけを塗り直すinvalidationや、layerとcompositingで作業量を減らしてきました。
    • ただしlayerはメモリを使い、どこをlayer化するかの判断を誤ると逆に遅くなることがあります。
    • WebRenderは、paintingとcompositingを分ける発想を見直し、GPUを3Dゲームエンジンのように使う方向へ進みます。
    • Layoutからはframe treeではなく、高水準の描画命令であるdisplay listを受け取り、RenderBackendがGPU向けのdraw callへ変換します。
    • Early culling、render task tree、batching、opaque/alpha pass、Z-cullingなどで、GPUが無駄な仕事をしないようにします。
    • テキストglyphなど一部は当時まだCPU側で扱われ、PathfinderでGPU化の実験も進められていました。

    リンク先も見てわかったこと

    記事冒頭で参照されているQuantum CSS / Styloの記事では、Servo由来のCSS engineが並列処理を使ってstyle計算を速くする話が扱われています。WebRender記事でも、CPU側で残るglyph描画などを並列化する文脈で、Styloのwork stealingが参照されています。Firefox Quantum期の性能改善は、CSS計算と描画の両方で「並列化」と「仕事量の削減」を進めていたことが見えてきます。

    servo/webrenderのGitHubリポジトリでは、WebRenderがGPU-based rendererとして説明されています。Webページを単なる2Dの塗りつぶしではなく、GPUに向けた描画命令として組み立てる発想が、このリポジトリ説明からも確認できます。

    Pathfinderは、フォントやベクターグラフィックスをGPUで扱うための実験として記事内で参照されています。WebRenderがすべてを一気にGPUへ移したわけではなく、どの処理をCPUに残し、どの処理をGPUへ移すかを段階的に見極めていた点が重要です。

    気づき

    今回の気づきは、WebRenderの本質は「毎フレーム全部描く」という単純な力技ではなく、「全部描けるだけの形に仕事を組み替える」ことにあるという点です。GPUは大量のピクセルを並列に処理できますが、draw callが細かすぎたり、shader切り替えが多すぎたり、見えないものまで塗ったりすると、その強みを活かせません。

    だからWebRenderは、display listから不要なものを早く除外し、render task treeで中間textureを減らし、batchingでGPUの状態変更を減らし、Z-cullingで隠れるpixelの計算を避けます。単に「GPUを使えば速い」ではなく、GPUが得意な形へWeb描画を再構成しているところが面白いです。

    また、記事の中で何度も出てくるのは最高速度よりも一貫性です。平均FPSが高くても、数フレームだけ重くなればユーザーにはjankとして見えます。WebRenderは、速さのピークを上げるより、性能の崖を減らして滑らかさを保つための設計だったと読むと理解しやすくなります。

    読むとよさそうな人

    • ブラウザのpainting、compositing、GPU描画の違いをざっくり知りたい人
    • Firefox Quantum期の性能改善でWebRenderがどんな役割を持っていたか知りたい人
    • jankやframe budgetを、ブラウザ内部の描画パイプラインから理解したい人

    参照した記事