
最後更新:2026 年 5 月 28 日
Quire(53,992 行、1,620 KB 的 Dart 程式碼)於 2014 年以 Dart 打造,客戶端與伺服器端皆使用 Dart,並以 DQuery 和 Bootjack 取代 AngularDART 或 Polymer.dart,以便更精細地控制 DOM。核心決定包括全端強型別、客戶端與伺服器端共用資料模型、伺服器端採用事件迴圈,以及以 tree shaking 精簡 JS 輸出。這些決定到 2026 年依然適用。
Quire 不是第一個以 Dart 編寫的網頁應用程式,也不會是最後一個,但它可能是第一個在客戶端和伺服器端都如此倚重 Dart 的應用程式。

這是一款以樹狀結構為核心的趣味任務管理工具。整個專案共 53992 行、1620KB 的 Dart 程式碼,並採用了幾個來自社群的開源程式庫。
在開展這個專案之前,我們就是一群 Dart 愛好者,人稱 Rikulo 團隊。我們已發布多個 Dart 程式庫,包括 UI 框架、UI 程式庫、網頁伺服器、訊息伺服器和資料庫客戶端等。
2011 年 Dart 剛推出時,我們就看好它的未來,興奮不已,隨即在小部分專案中開始使用 Dart。最後,我們更著手建立一個以 Dart 為主體的完整應用程式。在此誠意分享我們的一些經驗,希望為你開發 Dart 提供參考。
選擇 Dart 的理由多不勝數。對我們來說,最重要的有:
選擇 Dart 也有缺點:
有強型別支援,以 Dart 編寫程式比 JavaScript 可靠得多。Dart 也比 Java 簡潔,有時(例如使用函式表達式時)甚至比原生 JavaScript 更簡潔。整體而言,使用 Dart 的體驗相當舒適,只有幾點例外:
在 Dart VM 登陸 Chrome 之前,你要把產品交付給用戶,就得先編譯成 JavaScript。能編譯成 JavaScript 的語言多不勝數,但 Dart 憑幾項額外優勢脫穎而出。
Dart 用於伺服器端,在 Dart 社群裏從來不是熱門話題,但我們認為 Dart 是伺服器端程式語言的有力人選,原因是:
相關閱讀:Quire 取得 ISO 認證,保障你的資料 — 多年後,Quire 的正式資料保護認證同樣體現了對伺服器端穩健與安全的重視。
Quire 引入約 30 個程式庫,其中 10 個來自社群,其餘由 Dart 團隊發布。如果你是 Dart 專家,可能會猜當中有 AngularDART 和 Polymer.dart,但其實兩者都沒有採用。
我們不使用 AngularDART,原因是:
我們也不使用 Polymer.dart,原因是:
我們客戶端技術架構的基石是 DQuery 和 Bootjack,兩者都是由 Rikulo 團隊發布的開源專案:
我們循此路徑建立應用程式架構,以便沿用在 JavaScript 世界累積的知識和技能。
Stream 是我們的網頁伺服器,以純 Dart 編寫,具備路由、過濾器和伺服器端 MVC 等功能。Stream 與事件迴圈模型配合順暢,編寫請求處理器,只需串連一連串非阻塞的常式。
這不僅比傳統的多執行緒模型更有效率,用起來也更愉快。我們亦透過 nginx 擴展網路服務並處理 HTTPS,再把請求交給 Stream。憑此架構,我們可以逐一啟動和停止 Dart VM,在不打斷用戶操作的情況下升級伺服器。
使用 Dart 的體驗令我們十分愉快,我們也期待 Dart 社群有更多令人興奮的發展。最後,如果你好奇 Dart 能做出甚麼成果,歡迎來試用我們的應用程式 Quire。它是免費的!
了解更多:Quire 後來如何重新構想並重建為 Mark II。

自本文撰寫以來,Dart 語言和 Quire 的程式碼庫都有大幅演進。Dart 2.0(健全型別系統)於 2018 年推出,Dart 3.0(空值安全、records、patterns)於 2023 年推出,而 Flutter 改變了跨平台 UI 的格局(Quire 自家的流動版團隊也改用了它)。
不過,上文記錄的底層架構決定,比你想像中更經得起時間考驗。
全端強型別依然物有所值。 強型別系統在建置階段攔截的執行期錯誤,與當年是同一類錯誤。JavaScript 透過 TypeScript 走近了型別化,但完全型別化的端到端技術架構依然罕見。Simon 所指的那類問題(無數細微的錯誤),仍是無型別技術架構送上正式環境的那類問題。
客戶端與伺服器端共用資料模型,依然省時省力。 資料模型被複製兩份(一份用 JS、一份用 Python,悄悄各自偏離)的問題,2026 年與 2014 年並無分別,解決方法(端到端使用同一種語言)也一樣。TypeScript-on-Node 的團隊建立 Quire 式的架構,正是基於這個原因。
網頁伺服器採用事件迴圈而非多執行緒,依然勝出。 Node、Deno、Bun 和 Dart 自家的 Stream 模式,在這點上看法一致。這個論點每隔幾年就會被重新辯論一次,結論始終相同。
Tree shaking 的重要性有增無減。 2014 年,Dart 的 tree shaking 編譯器是一大賣點。到了 2026 年,它已是所有以 JS 為目標的建置流程的基本配備。Webpack、Rollup、esbuild 和 Vite 都有這項功能。經驗依然成立,只是工具追上來了。
2014 年對 ShadowDOM 的疑慮,大多已經解決。 Polymer.dart 已被棄用,Web Components 日趨成熟。Simon 當年不採用 Polymer 的理由(樣式注入、框架協作),最終由平台本身解決了。至於「正式應用程式的核心不要採用最前沿的框架」這個大原則,到 2026 年對任何當下「令人興奮」的框架依然適用。
相關閱讀:How It's Made: A Flutter-Based Mobile Timeline — 看看 Quire 的流動版團隊如何運用 Flutter 打造時間軸檢視模式。
為一個行之多年的應用程式選擇語言技術架構,是少數事後代價高昂、難以回頭的工程決定。團隊選錯時,通常有四種情況反覆出現。
1. 預設選擇社群最大的語言。 JavaScript 的社群最大,但「最大」不等於「最適合你的問題」。型別系統強、工具完善而社群較小的語言,可能勝過保障薄弱、生態龐雜的語言。社群規模固然重要,卻不是唯一重要的因素。
2. 選用客戶端和伺服器端語言分家的技術架構。 每一個被複製的資料模型,都是一枚等待引爆的臭蟲。伺服器端用 Ruby、客戶端用 JS 的團隊,要永遠承擔這項成本。兩端共用同一種語言(Dart、TypeScript、Kotlin)的團隊,則可避開整類臭蟲。
3. 在最前沿技術尚未穩定時就採用。 Quire 團隊在 2014 年沒有採用 AngularDART 和 Polymer.dart,因為兩者都存在未解決的架構問題。AngularDART 後來大幅轉向,Polymer 則被棄用。大原則是:先讓框架在大規模正式環境中證明自己,才把應用程式的核心押在它身上。到 2026 年,這點對任何當下「令人興奮」的框架依然適用。
4. 為短期速度而放棄型別系統。 無型別語言在第一週感覺較快,但到第六個月,省下的時間會在除錯上加倍還回去。親身經歷過大規模無型別和強型別技術架構的工程團隊,幾乎不會自願走回頭路。
Quire 團隊 2014 年押注 Dart,事後看來是合理的,並不是因為 Dart 成為主流(它沒有),而是因為背後的準則(強型別、客戶端與伺服器端共用、事件迴圈、tree shaking)在其後十年成為業界共識。
經得起時間考驗的,是底層的工程原則,而非具體的工具選擇。在不確定下選擇語言,這個規律通常都成立:要為十年後仍能自圓其說的原則而選,而不是為今天量度得到的人氣而選。
Dart,客戶端和伺服器端皆是。應用程式約有 54,000 行 Dart 程式碼,引入約 30 個程式庫。
強型別、以類別為基礎的繼承模型,以及客戶端與伺服器端共用同一種語言。Dart 也比 JavaScript 更早提供一些現代功能。
團隊想要比 AngularDART 的繫結更精細的 DOM 控制,而且 Quire 的架構模式與 Angular 的邏輯並不吻合。至於 Polymer.dart,當時 ShadowDOM 與 Bootstrap 式的選擇器互相衝突,所以沒有採用。Polymer 後來被棄用,印證了這個決定。
兩者都是 Rikulo 團隊(Quire 的工程團隊)的開源程式庫。DQuery 是 jQuery 的部分 Dart 移植版本,專注於事件委派。Bootjack 是 Bootstrap 3 的完整移植版本,CSS 和 API 幾乎完全相同。
Quire 的網頁伺服器,以純 Dart 編寫,採用事件迴圈模型,內建路由、過濾器和伺服器端 MVC。Quire 把 Stream 置於 nginx 之後,由 nginx 負責擴展和 HTTPS。