5.5 KiB
Browser Project Structure & Modularization Guide
Purpose of this Document
This document provides tactical, technical guidance for structuring the browser codebase as a Rust monorepo. It complements the higher-level architecture document by focusing on:
- Concrete crate layout
- Dependency and layering rules
- Patterns that keep modules extractable
- Constraints that make AI-assisted development safe and scalable
This document is intentionally opinionated.
Design Goals
- Monorepo convenience, library-quality modularity
- Clear ownership and boundaries between subsystems
- Low cognitive load for humans and AI agents
- Future extraction of complex subsystems without rewrites
- Minimal use of
unsafe, isolated by design
High-Level Workspace Structure
The project is a single Cargo workspace with many small, focused crates.
/Cargo.toml # workspace root
/crates
/app_browser # binary: macOS/Linux desktop shell
/browser_runtime # tabs, navigation, session/history, permissions
/web_api # JS<->DOM boundary and host bindings
/js # JS engine public facade
/js_vm # interpreter, runtime, GC integration
/js_parser # JS tokenizer/parser
/dom # DOM tree, mutation, events
/html # HTML tokenizer/parser
/css # CSS tokenizer/parser + OM
/selectors # CSS selector matching
/style # cascade and computed styles
/layout # layout tree and algorithms
/display_list # normalized drawing commands
/render # display list execution (CPU-first)
/graphics # graphics backend abstractions
/net # fetch, cache, cookies, HTTP state machines
/storage # persistent storage plumbing
/image # image decode pipeline
/fonts # font loading and shaping (later)
/platform # macOS/Linux OS integration
/shared # common utilities, types, errors
/tests
/wpt_harness # Web Platform Tests runner
/goldens # golden pages + expected dumps
/tools
/repro_minimizer # shrinking failing test cases
/triage # crash and flake analysis tools
Many crates may start out nearly empty; their value is in defining boundaries early.
Layering and Dependency Rules
Dependency Direction
Crates must only depend downward:
app_browser
↓
browser_runtime
↓
engine crates (web_api, dom, style, layout, render, net, js)
↓
shared
Rules:
app_browserowns the desktop UI and event loop glue.- Engine crates must never depend on
app_browseror UI concepts. - Platform-specific code lives in
platformand is accessed via narrow adapters.
Crate Responsibilities (Selected Highlights)
app_browser
- Window creation
- Input event capture
- Platform event loop integration
- Wiring everything together
No browser logic lives here.
browser_runtime
- Tabs and browsing contexts
- Navigation lifecycle
- Session and history management
- Permissions and security policy decisions
js / js_vm / js_parser
js: stable public API used by the browserjs_vm: interpreter, execution state, GC hooksjs_parser: tokenizer and parser only
Design rule: the interpreter is the semantic oracle for future JITs.
DOM / Style / Layout / Rendering
dom: tree structure, mutation, eventsstyle: selector matching + cascadelayout: box tree and layout algorithmsdisplay_list: backend-agnostic paint representationrender: executes display list
These crates must remain platform-agnostic and testable in isolation.
Patterns That Enable Future Extraction
Prefer IDs over Borrows
Across crate boundaries:
- Use
NodeId,StyleId,LayoutId, etc. - Store data in arenas inside each crate
- Expose explicit query/mutation APIs
This avoids lifetime coupling and simplifies APIs.
Phase-Based Mutation
Structure work in explicit phases:
parse → build DOM → style → layout → paint
Each phase produces a stable representation consumed by the next.
Platform Abstraction via Traits
Core crates depend on traits like:
ClockNetworkProviderFontProviderImageDecoder
Implemented by platform or app_browser.
unsafe Usage Policy
Default: no unsafe.
Allowed only in:
- OS bindings (
platform) - Graphics backends (
graphics) - Future performance islands (e.g., JIT, SIMD)
Every unsafe block must:
- document invariants
- have targeted tests
- be covered by fuzzing where applicable
AI-Agent-Friendly Constraints
To maximize safe agent contribution:
- Keep core execution single-threaded early
- Prefer simple data structures over clever ones
- Enforce tests for every change
- Use compiler errors and tests as the primary feedback loop
Rust’s type system and this structure together act as guardrails.
What This Document Is Not
- A final architecture
- A performance roadmap
- A commitment to specific libraries or backends
Those decisions will follow from experimentation and testing.
Expected Evolution
As the project grows:
- Some crates may merge or split
- Certain crates may be extracted into external libraries
- Additional layers (JIT, compositor threads, sandboxing) will be added
The constraints in this document are intended to make those changes incremental, not disruptive.