Building a Browser Engine in Rust: Where It Stands
Nemo · · 3 min read
Monok is a browser written in Rust, but version 1 does not render pages with a Rust engine. The shell (tabs, panes, Magic Bar, terminal, favorites, blocking, internal pages) is Rust, and it talks to web content through an engine trait; the engine behind that trait in v1 is the system’s WebKit, through WKWebView. A Rust engine of our own was the original plan and is paused. This post maps both: what ships, and what the engine would be made of.
What does v1 look like inside?
| Crate | What it does in v1 |
|---|---|
| engine-api | The engine boundary: traits, events, content rules and a conformance suite |
| engine-system | WKWebView behind those traits; the only WebKit code in the app |
| shell | The chrome: tabs, top bar, favorites, Magic Bar, find bar, the ⋮ menu, browser:// pages, and the AppKit window |
| panes | The per-tab pane tree: splits, focus, resize, zoom |
| terminal | PTY, emulation and drawing for terminal panes |
| adblock-rules | EasyList and EasyPrivacy converted to WebKit content rules, plus the weekly updater |
| storage | Bookmarks, history, settings and the session in one file |
| update | The signed update feed |
| paint, text | Draw the chrome with vello_cpu and lay out its text with parley |
The browser’s own interface is not a web page: it is drawn by vello_cpu into native macOS layers, with the main menu, full screen and dialogs left to AppKit. The engine-system crate passes the engine trait’s conformance suite, 12 of 12 checks.
Why an engine trait?
So the engine can change without rewriting the browser. The shell knows nothing about WebKit: it sends navigations and receives events. A second engine, our own or Chromium, would be one more implementation of the same trait. The reasoning behind starting with WebKit is in why v1 runs on WebKit.
What was the own engine going to be?
| Step | Crate | Status |
|---|---|---|
| Parse HTML | html5ever | Early crate in the repository, unused by v1 |
| Style | Our own, on cssparser and selectors | Early crate, unused by v1 |
| Layout | taffy for block, flex and grid; parley for inline text | Early crate, unused by v1 |
| Paint | vello_cpu | In use, for the chrome only |
| Script | rquickjs (QuickJS) | Never started |
The hard part was always going to be the middle: the style system, and the Web APIs that JavaScript expects. The Web APIs post lists what React and Angular apps call, which is the bar any engine has to clear.
Why Rust for a browser on WebKit?
Memory safety for the parts we write, a small binary, and good crates for text, drawing, terminals and filter lists. The release build of 0.1.0 is 6.83 MB (arm64, stripped) and draws its first frame in 139 to 162 ms on an M5 Pro.
FAQ
Does Monok have its own engine?
Not in v1. Pages are rendered by WebKit through WKWebView. The own engine is paused.
Does Monok use Servo?
No. The paused engine used html5ever, which came out of the Servo project, but never Servo’s engine.
Can I use it today?
Yes. Version 0.1.0 is a download for macOS 14 or later.