CLOUDFLARE WORKERS

Cloudflare の Kitesurf を、公開情報だけで作ってみた

Chromium を使わず、Rust で書いたブラウザエンジンを Wasm にして Workers の isolate で動かす。Cloudflare が 2026 年 8 月に発表した Kitesurf と同じ構成を、発表記事に名前が挙がっている部品だけで組んだものです。ソースコードは非公開なので、中身は見ていません。

以下の画像は全部、この Worker が Wasm の中で描きました。

3 つのブラウザで同じページを撮る

左が本物のブラウザ (Chromium)、中央が Cloudflare の 本物の Kitesurf、右がこの記事で組んだ疑似 Kitesurfです。3 枚は同じ時刻に撮っています — ja.wikipedia のトップページは日ごとに変わるので、別々に撮るとエンジンの違いとページの違いが混ざります。画像を押すと元の大きさで開きます。

撮影 2026-09-08 07:44 UTC。下の「自分で試す」だけはその場で描きます。

ja.wikipedia.org

日本語の見出しと本文、2 カラム、写真 24 枚。CSS は 3 枚で 231 KB
https://ja.wikipedia.org/wiki/メインページ · 1000×780

Chromium202 KB
ja.wikipedia.org を Chromium が描いた画像
本物のブラウザ。Browser Run の既定
課金 1266 ms
Kitesurf390 KB
ja.wikipedia.org を Kitesurf が描いた画像
Cloudflare 版。Chromium を使わない
課金 5542 ms
疑似 Kitesurf359 KB
ja.wikipedia.org を 疑似 Kitesurf が描いた画像
公開情報だけを見て組んだもの (browser-on-workers)
2 パス · CSS 3 枚 · 画像 24 枚

developer.mozilla.org

CSS 20 枚。本文中の map() が等幅で出ている。JS は 938 KB 実行してエラー 0 件
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map · 1000×780

Chromium54 KB
developer.mozilla.org を Chromium が描いた画像
本物のブラウザ。Browser Run の既定
課金 743 ms
Kitesurf66 KB
developer.mozilla.org を Kitesurf が描いた画像
Cloudflare 版。Chromium を使わない
課金 3985 ms
疑似 Kitesurf57 KB
developer.mozilla.org を 疑似 Kitesurf が描いた画像
公開情報だけを見て組んだもの (browser-on-workers)
2 パス · CSS 18 枚 · 画像 0 枚

react.dev

SSG。ページの JS を動かすと React のハイドレーションが本文を消すので、JS を切って描き直したもの
https://react.dev/ · 1000×780

Chromium153 KB
react.dev を Chromium が描いた画像
本物のブラウザ。Browser Run の既定
課金 733 ms
Kitesurf84 KB
react.dev を Kitesurf が描いた画像
Cloudflare 版。Chromium を使わない
課金 6715 ms
疑似 Kitesurf67 KB
react.dev を 疑似 Kitesurf が描いた画像
公開情報だけを見て組んだもの (browser-on-workers)
2 パス · CSS 1 枚 · 画像 24 枚

todomvc.com (React の SPA)

HTML の中は空。見えているものは全部、ページの JS が描いたもの
https://todomvc.com/examples/react/dist/ · 1000×780

Chromium22 KB
todomvc.com (React の SPA) を Chromium が描いた画像
本物のブラウザ。Browser Run の既定
課金 1329 ms
Kitesurf24 KB
todomvc.com (React の SPA) を Kitesurf が描いた画像
Cloudflare 版。Chromium を使わない
課金 2411 ms
疑似 Kitesurf20 KB
todomvc.com (React の SPA) を 疑似 Kitesurf が描いた画像
公開情報だけを見て組んだもの (browser-on-workers)
2 パス · CSS 1 枚 · 画像 0 枚

自分で試す

好きな URL を入れてください。この場に画像が出ます。

外部 CSS と画像は Worker が取ってきてエンジンに渡します。重いページは 10 秒ほどかかります。10 秒で 4 枚までにしています。

JavaScript も動く

ページの <script>Boa (Rust で書かれた JavaScript エンジン) で実行しています。Workers は evalnew Function を禁じていますが、Boa が自分でコンパイルするので、ページの中の eval は通ります

同じページを左右に並べます。左はあなたのブラウザが表示したもの、右はこの Worker が Wasm の中で描いた画像です。緑の枠はどちらもページの <script> が書き換えたものです。

あなたのブラウザiframe · 760×560
6 つとも緑になります — 最後の枠の 5000 万回のループも、数十ミリ秒で終わるので
疑似 Kitesurf が描いた画像PNG · 760×560
同じページを、この Worker が描いた画像。上の 5 つの枠は緑で、最後の枠だけ灰色のまま。
最後の枠だけ灰色のまま — Boa はループ 50 万回で JavaScript を止めます。止まる前に書いた 5 つは残ります

違いは最後の枠だけです。ページを単体で開くこともできます。

V8 と Boa が同じ isolate に同居する形になります。Worker のコードは V8 で動き、ページのコードは Wasm の中の Boa で動く。Cloudflare の Kitesurf も同じ構造です。

中身

役割使っているもの
HTML のパースhtml5ever
DOMblitz-dom
CSSStylo — Firefox の CSS エンジン
レイアウトTaffy
テキスト整形Parley
描画blitz-paint + vello_cpu
JavaScriptBoa (blitz-vibey-script 経由)
PNG 化自前。Workers に画像の API が無いので
フォントStatic Assets に置いて起動時に読む
外向きの取得Worker の fetch() 1 箇所だけ

Rust を wasm32-unknown-unknown にビルドして Worker から呼んでいます。Wasm は 15 MB ほど。

できないこと