
最近在技術社區里LadybirdBrowser 的熱度明顯漲了一波。很多人把它稱作“真正從零開始寫的瀏覽器”也有不少人誤以為它只是一個玩具項目。實際上Ladybird 已經發展成一個獨立于 SerenityOS 的瀏覽器工程在 HTML/CSS/JS 解析、渲染、布局、安全模型等方面都有非常完整的代碼實現。這篇文章會從底層視角切入講解 Ladybird 的定位、倉庫結構、核心技術架構、源碼編譯步驟、閱讀路線、常見問題和參與方式。目標是讓關注瀏覽器內核方向的同學能獨立把 Ladybird 拉下來跑起來并且能看懂它的主干流程。文章適合三類讀者對瀏覽器內核感興趣的 C 開發者、想參與開源項目的初學者、以及想了解“非 Chromium 系瀏覽器”如何工作的前端/后端工程師。1. Ladybird 是什么一個“真正獨立”的瀏覽器引擎1.1 從 SerenityOS 中走出來的瀏覽器Ladybird 原本是 SerenityOS 操作系統項目內置的瀏覽器。SerenityOS 是一個從零開始、類 Unix 風格的教學型操作系統由 Andreas Kling 發起。這個項目有一個很特別的原則盡量不依賴現有的大型第三方代碼很多組件都自己實現。瀏覽器作為系統里最復雜的一塊自然也被寫了出來。早期它只是 SerenityOS 的附屬應用但隨著代碼量增長、功能變多開發者們發現它完全可以作為獨立跨平臺瀏覽器發展。于是 Ladybird 從 SerenityOS 倉庫中剝離成為單獨的 GitHub 項目LadybirdBrowser/ladybird。這里有一個核心信息需要記住Ladybird 不是 Chromium 套殼不是 Firefox 換皮也不是 WebKit 分支。它的 HTML 解析器、CSS 解析器、JavaScript 引擎、WebAssembly 支持、布局與繪制邏輯都是基于開源標準一點點實現的。1.2 Ladybird 解決什么問題現在世界上的主流瀏覽器底層引擎集中在三個Chromium / Blink V8Firefox / Gecko SpiderMonkeyWebKit / WebCore JavaScriptCore當瀏覽器市場被少數引擎主導時Web 標準容易被“實際上怎么實現”反過來綁架。Ladybird 項目的意義在于做一個獨立于這些實現之外的瀏覽器引擎用代碼去驗證標準、推動標準而不是單純地“再做一個瀏覽器”。同時Ladybird 的設計理念里很強調隱私。它不打算內置遙測、不收集用戶行為、沒有廣告業務綁定。這也讓它在隱私敏感型用戶和研究者群體中獲得了不少關注。1.3 當前項目狀態Ladybird 目前仍然處于快速迭代階段。它已經能打開不少現代網站基本的 CSS 布局、JavaScript 交互、Canvas、WebAssembly 等都在持續完善。但也要理性看待它的兼容性、穩定性和性能暫時無法和 Chrome、Safari 這些商業級瀏覽器相比。對普通用戶來說它可能還不是日常主力瀏覽器對開發者來說它卻是一份極好的“瀏覽器內核學習資料”。2. 與主流瀏覽器相比Ladybird 的定位與優勢2.1 不復制 Chromium 代碼意味著什么很多開源瀏覽器項目本質上是在 Chromium 外面包了一層殼比如曾經的 Edge、現在的各種國產瀏覽器、一些極簡瀏覽器。這類項目主要工作集中在 UI、同步、賬號系統、安全策略和插件生態內核能力都來自 Chromium。Ladybird 不同。它的渲染引擎叫 LibWebJavaScript 引擎叫 LibJSWebAssembly 運行時叫 LibWasm。這些代碼不依賴 V8、不依賴 Blink、不依賴 SpiderMonkey是完全另一條技術路線。這意味著 Ladybird 的源碼里你可以看到HTML 解析器如何把字符流變成 DOM 樹。CSS 引擎如何做選擇器匹配和樣式計算。JavaScript 引擎如何實現字節碼解釋執行。布局模塊如何處理正常流、Flex、Grid、絕對定位。這些內容在 Chromium 源碼里被大量封裝和優化之后已經非常難讀。而 Ladybird 的代碼結構相對小命名也直白很多非常適合學習。2.2 隱私優先的設計理念Ladybird 沒有商業壓力所以它的瀏覽器架構里少了很多“商業化功能”。項目更關注默認不啟用遙測。沒有廣告注入點。盡量把網絡請求和用戶身份隔離。對于研究人員來說這種項目更容易分析“瀏覽器到底在請求什么、渲染什么”。對于普通用戶來說如果你能接受功能殘缺Ladybird 也可以作為隱私要求較高的輔助瀏覽器使用。2.3 主流瀏覽器引擎對比瀏覽器/項目渲染引擎JavaScript 引擎代碼基礎主要定位ChromiumBlinkV8Google 主導商業瀏覽器、WebView、Electron 基礎FirefoxGeckoSpiderMonkeyMozilla 主導開源瀏覽器、隱私保護SafariWebCoreJavaScriptCoreApple 主導蘋果生態內置瀏覽器LadybirdLibWebLibJSLadybird 社區獨立瀏覽器、標準驗證、學習研究從表格可以看出Ladybird 在技術棧上是完全獨樹一幟的。這也是它在開發者社區受到關注的根本原因。2.4 誰適合使用或研究 Ladybird我建議這幾類人重點看看 LadybirdC 開發者想找一個大型但可讀性較高的 C 項目。前端工程師想理解瀏覽器從 URL 到像素的完整鏈路。安全研究員想研究瀏覽器多進程隔離、網絡策略、解析器漏洞。開源新人想找一個有活躍社區、有清晰貢獻路徑的項目。3. 倉庫結構拆解一個大型 C 項目的組織方式3.1 頂層目錄說明拉取代碼后第一件事是看目錄結構。Ladybird 的倉庫組織延續了 SerenityOS 的風格頂層目錄大致如下目錄作用Ladybird/瀏覽器宿主層代碼包括窗口、菜單、地址欄、WebContent 進程入口Userland/用戶態程序與庫核心內容在Libraries子目錄Meta/構建腳本、輔助工具、代碼生成工具Tests/單元測試和集成測試Base/內置資源、默認首頁、字體等Documentation/項目文檔和貢獻指南其中最重要的就是Userland/Libraries。這里面的每一個Lib*目錄都可以理解成一個相對獨立的組件庫。3.2 核心庫組件在Userland/Libraries下你會看到大量以Lib開頭的目錄常見的有LibWeb負責 HTML 解析、DOM、CSS、布局、繪制指令生成。LibJSJavaScript 引擎包括解析器、字節碼、解釋器、內置對象。LibWasmWebAssembly 字節碼解析與執行。LibGfx圖形、字體、圖片編解碼基礎能力。LibUnicodeUnicode 數據和字符處理。LibTextCodec字符編碼轉換。LibCore基礎事件循環、文件、進程、網絡抽象。LibHTTPHTTP 客戶端實現。這種組織方式的優點非常明顯每個庫都有清晰邊界測試可以單獨編譯、單獨執行。對閱讀者來說你不用為了看一個 CSS 解析邏輯被迫翻遍整個瀏覽器。3.3 “庫”的思維與工程意義Ladybird 把瀏覽器引擎拆成庫而不是一個巨大的可執行程序這在工程上是一種很好的解耦策略。比如你只關心 JavaScript 引擎那你可以只研究 LibJS不需要陷入網頁渲染細節。又比如你想給 LibWeb 增加一個 CSS 屬性支持你通常只需要在 LibWeb 內部改代碼不會牽連到 UI 層。正是這種模塊化設計讓 Ladybird 對開源貢獻者非常友好。你可以像“做填空題”一樣在某個子庫里實現一個規范點然后跑對應測試驗證。4. 核心技術架構解析4.1 LibWeb從 HTML 到 DOM 再到布局LibWeb 是 Ladybird 的靈魂負責整個網頁內容管線。它包含一條完整的處理鏈路網絡層拿到 HTML 文本。HTML 解析器把字符流拆成 Token再組裝成 DOM 樹。CSS 解析器解析style標簽和內聯樣式生成樣式表。樣式引擎計算每個 DOM 節點的最終樣式。布局模塊根據視口尺寸、樣式信息和內容生成布局樹。繪制階段把布局結果轉換成繪制指令交給宿主窗口渲染。這個過程和 Chromium 的 Blink、Firefox 的 Gecko 在宏觀流程上是一致的但實現細節和代碼組織有很大差異。LibWeb 的注釋里經常能看到 WHATWG 規范鏈接和相關說明閱讀時配合規范看效率會高很多。4.2 LibJS 與 LibWasm自研腳本運行時LibJS 是 Ladybird 的 JavaScript 引擎。它實現了 ECMAScript 規范中的語法解析、作用域分析、字節碼生成、解釋執行和垃圾回收。與 V8 相比LibJS 的整體代碼量小很多優化的深度也淺一些。但它的結構相對清晰理解門檻低很多。如果你想搞明白“JavaScript 引擎到底怎么運行”LibJS 是一個比 V8 友好得多的入口。LibWasm 則負責 WebAssembly。它讀取.wasm二進制格式校驗模塊結構執行函數體。對前端開發者來說WebAssembly 可能只是一個接口在 Ladybird 里你可以看到它底層真正的字節碼結構。4.3 多進程與事件循環現代瀏覽器為了安全普遍使用多進程架構。協議、渲染、GPU 進程各自隔離防止一個網頁崩潰拖垮整個瀏覽器。Ladybird 也采用了類似思路瀏覽器 UI 進程與 WebContent 內容進程分離兩者之間通過進程間通信傳遞頁面內容、輸入事件和繪制結果。這種設計不是為了炫技而是安全模型的基石。一個惡意網頁即使攻破了渲染進程也很難直接訪問操作系統用戶數據。進程內部則靠事件循環驅動。JavaScript 的異步回調、網絡請求、定時器、用戶輸入最終都會變成事件循環里的任務。LibCore 提供了一個跨平臺的事件循環抽象LibWeb 和 LibJS 的事件處理都建立在它之上。為了便于理解下面給出一段簡化的事件循環示意代碼。它并不是 Ladybird 倉庫中的真實源碼而是用來說明“事件驅動”和“統一重繪”的核心思路。// 簡化示意展示瀏覽器事件循環如何驅動解析、輸入與重繪 #include deque #include functional #include iostream enum class EventType { Input, Timer, NetworkTask, Repaint }; struct Event { EventType type; std::functionvoid() handler; }; class EventLoop { public: void postEvent(Event ev) { queue_.push_back(std::move(ev)); } void run() { while (!stop_) { // 處理當前事件隊列中的所有任務 while (!queue_.empty()) { auto ev std::move(queue_.front()); queue_.pop_front(); ev.handler(); } // 所有任務處理完成后如果頁面標記為需要重繪則統一繪制 if (dirty_ onRepaint_) { std::cout [EventLoop] repaint page\n; onRepaint_(); dirty_ false; } // 等待下一輪事件Linux/Unix 下通常是 poll/epoll/select waitForNextEvent(); } } void setDirty(bool dirty) { dirty_ dirty; } void setRepaintCallback(std::functionvoid() callback) { onRepaint_ std::move(callback); } void stop() { stop_ true; } private: void waitForNextEvent() { // 這里在真實瀏覽器中會等待 socket、定時器、窗口消息等事件 } std::dequeEvent queue_; bool dirty_ false; bool stop_ false; std::functionvoid() onRepaint_; };真實 LibCore 的實現會比這個復雜很多它要處理跨平臺 socket、定時器、信號、子進程等。但核心思想一樣瀏覽器不是無腦while(true)循環畫幀而是“有事件就處理事件沒有事件就等待空閑時統一重繪”。4.4 宿主層與繪制后端Ladybird 的 UI 層通過宿主抽象來調用底層圖形庫。目前主流的宿主是基于 Qt6 的Qt 負責創建窗口、接收鼠標鍵盤事件、繪制位圖。此外還有 Headless 模式可以在沒有窗口的環境下加載頁面并截圖這對自動化測試和調試很有幫助。這種“宿主與引擎分離”的設計讓 Ladybird 以后可以接不同的 GUI 框架而不需要改動解析和布局核心邏輯。5. 從源碼構建 Ladybird環境準備與編譯5.1 推薦環境Ladybird 是一個大型 C 項目建議在 Linux 或 macOS 上構建Windows 原生支持較差可以借助 WSL2。硬件方面編譯過程比較吃內存建議至少 8GB 內存16GB 會更舒服。首次構建需要編譯大量代碼耗時可能較長請保證磁盤空間和耐心。5.2 Linux 環境安裝依賴不同發行版包名略有差異這里以 Debian/Ubuntu 為例sudo apt update sudo apt install build-essential cmake ninja-build ccache \ qt6-base-dev qt6-wayland如果構建過程中提示缺少某些庫比如libssl-dev、libxkbcommon-dev、libgl1-mesa-dev按錯誤提示安裝對應 dev 包即可。Ladybird 依賴的庫會隨著版本演進有所變化不要死記上面的列表要以官方 README 和構建報錯為準。5.3 macOS 環境安裝依賴macOS 上建議通過 Homebrew 安裝依賴xcode-select --install brew install cmake ninja ccache qt安裝完成后同樣可以進入源碼編譯流程。5.4 獲取源碼并執行構建腳本拉取源碼git clone https://github.com/LadybirdBrowser/ladybird.git cd ladybird項目提供了統一構建腳本Meta/ladybird.sh通常這樣用# 構建項目 ./Meta/ladybird.sh build # 運行瀏覽器 ./Meta/ladybird.sh run腳本會創建Build目錄并在首次構建時配置 CMake 和 Ninja 環境。如果你對腳本支持的命令不清楚可以執行./Meta/ladybird.sh --help需要注意的是Ladybird 處于快速開發階段main 分支變動很快。建議在閱讀或開發前確認當前 commit避免和別人寫文章時的代碼對不上。5.5 運行驗證構建成功后運行 Ladybird正常情況下會彈出一個瀏覽器窗口。你可以在地址欄輸入https://example.com或本地 HTML 文件路徑觀察頁面渲染效果。如果網絡環境受限也可以先在地址欄加載簡單的data:text/html,h1Hello驗證最基礎的 HTML 解析鏈路是否正常。這個小技巧在后續調試引擎時也會經常用到。6. 初識 Ladybird 源碼從啟動到渲染一條線6.1 從入口函數開始Ladybird 的代碼量雖然比 Chromium 小但直接亂翻依然會迷失方向。建議先找入口。如果你是閱讀源碼可以在Ladybird/目錄下尋找可執行程序的main函數。入口邏輯通常是這樣的初始化宿主環境比如 Qt 應用對象。創建瀏覽器窗口注冊地址欄和頁面視圖。創建 WebContent 進程或連接到已有內容進程。用戶輸入 URL 后調用頁面加載接口。頁面加載完成后監聽渲染事件并更新窗口內容。6.2 渲染一條線我們可以用一條 ASCII 簡圖來表示一個頁面從輸入到顯示的主鏈路輸入 URL ↓ 網絡請求LibHTTP / 系統網絡棧 ↓ HTML 文本 ↓ LibWebHTML 解析器 → DOM 樹 ↓ LibWebCSS 解析 → 樣式計算 ↓ LibWebLayout 布局樹 ↓ LibWebPaint 繪制指令 ↓ 宿主窗口顯示Qt / Headless 截圖建議按這條鏈路逐段閱讀而不是從中間某個類開始。6.3 閱讀順序建議我給初學者的源碼閱讀順序是先讀LibWeb的 HTML 解析器觀察 Token 到 DOM 的轉換過程。再讀 CSS 解析和樣式計算理解display、width、color等屬性如何影響渲染。然后讀布局模塊理解普通流和 Flex 布局的基本邏輯。最后回到LibJS先跑通一個簡單表達式再看它如何與 DOM 綁定。這樣從“網頁顯示”切入再進入“腳本執行”比一上來就啃 JS 引擎更平滑。7. 常見問題與排查思路構建和運行 Ladybird 時我整理了幾個高頻問題問題現象常見原因解決思路編譯進程被 OOM kill并行編譯任務太多內存不足降低-j參數增加 swap關閉其他大內存應用找不到 Qt6 頭文件系統源沒有 Qt6 或安裝的不是 dev 包安裝qt6-base-dev確認 CMake 能找到 Qt6運行時黑屏或無法彈窗Wayland/X11 相關依賴缺失安裝qt6-wayland或設置QT_QPA_PLATFORMxcb首次編譯非常慢沒有使用 ccache 或編譯器優化級別高安裝 ccache之后增量構建會明顯加快Windows 下構建失敗項目以類 Unix 系統為主要開發環境使用 WSL2 或 Docker 容器某些網站 JS 運行異常LibJS 仍在完善兼容性不夠先用標準測試用例定位再決定是否提 issue這里展開說幾個OOM 問題Ladybird 的 C 模板和頭文件依賴很多如果并發編譯任務開得太大內存很容易被打滿。遇到std::bad_alloc或進程被 kill 時不要慌降低并行度重新編譯即可。黑屏問題Linux 下運行 GUI 程序經常遇到圖形棧問題。一般優先嘗試讓 Qt 使用 xcb 模式QT_QPA_PLATFORMxcb ./Meta/ladybird.sh run如果當前環境是純 Wayland也有對應模式但需要安裝 Wayland 插件。頁面顯示異常如果你加載一個頁面后布局錯亂先不要直接判定“引擎壞了”。建議先用簡單的data:text/html或本地文件排除網絡問題再用headless模式截圖對比方便定位是解析問題還是繪制問題。8. 如何參與 Ladybird 開源貢獻8.1 從 Issue 和測試失敗項入手Ladybird 社區對新人比較友好。比較好的切入點有兩類標有good first issue的 GitHub Issue。Web 平臺測試WPT中的失敗用例。你不需要一開始就實現一個巨大功能可以先挑一個很小的失敗點比如某個 CSS 屬性沒有生效、某個 JS 內置函數返回結果不對把它修好。8.2 提交 PR 前的注意事項在提 PR 之前建議先看倉庫里的CONTRIBUTING文檔并遵守以下幾點保持 commit 粒度小一個 PR 盡量只解決一個問題。代碼格式遵循項目的 clang-format 配置。新增或修改代碼時盡量帶上對應測試。提交前運行相關庫的測試避免影響其他模塊。8.3 社區協作方式項目的討論主要圍繞 GitHub 展開同時也有社區聊天頻道用于同步開發進展。參與前不要直接“認領 Issue”先看是否已經有人在做避免重復勞動。如果你只是學習不打算貢獻也沒關系。把倉庫 clone 下來改一改日志輸出、加幾個斷點也是一種非常有效的學習方式。9. 工程建議學習 Ladybird 的幾個正確姿勢9.1 把它當作“大型 C 可讀樣本”Ladybird 代碼量比 Chromium 小一到兩個數量級但它覆蓋了瀏覽器引擎的完整主鏈路。對 C 工程能力提升來說它是一個很好的“大型項目閱讀樣本”。閱讀時不要試圖把每個類都搞清楚先抓住主線再橫向擴展。9.2 先用 WPT 定位問題再讀代碼Web Platform Tests 是瀏覽器兼容性的標準測試集。Ladybird 很多代碼的目標是讓更多 WPT 用例通過。你可以先跑一個失敗用例觀察失敗輸出再回到源碼里查對應實現。這種“問題驅動閱讀”比通讀源碼更高效。9.3 關注安全模型瀏覽器安全模型包括多進程隔離、跨域策略、CSP、權限管理等。Ladybird 雖然早期但已經在往現代瀏覽器安全架構靠攏。學習它的安全設計對后端安全、桌面應用安全都有借鑒意義。9.4 不要在 main 分支上固化印象Ladybird 迭代很快今天的代碼可能下周就重構了。寫文章、做筆記時盡量記錄當前 commit hash。復現問題和提交 Issue 時也要寫清楚版本號或 commit否則維護者很難判斷問題是否已經修復。9.5 結合標準文本閱讀Ladybird 的代碼注釋經常引用 WHATWG、ECMA-262 等規范。閱讀時打開標準原文對照代碼逐條理解能比單純看代碼更深入。這也是瀏覽器內核開發者的基本功。10. 總結Ladybird 是近幾年瀏覽器內核領域里少見的、完全獨立的新引擎項目。它不依賴 Chromium、Firefox 或 WebKit覆蓋了解析、布局、腳本執行、繪制等完整鏈路。對研究瀏覽器工作原理、學習大型 C 工程、參與開源共建來說它都是非常合適的對象。本文主要分享了它的背景、核心庫結構、技術架構、源碼編譯方法、閱讀主線和常見問題處理方式。你可以先按照第 5 部分的步驟把項目跑起來再順著第 6 部分的鏈路閱讀源碼。如果你在構建過程中遇到其他問題優先查看官方 README、GitHub Issues 和項目的Documentation目錄。動手實踐比收藏一堆資料更有價值下一步不妨從 clone 項目并跑通一個簡單的 WPT 用例開始。