Dart Sass 發佈公告

由 Natalie Weizenbaum 發佈於 2016 年 10 月 31 日

過去幾個月,我一直默默地進行一個新專案。今天,我準備向全世界宣布 Dart Sass。這是一個全新的 Sass 實作,旨在快速、易於安裝且易於修改。它尚未完成——我正穩步地完成 sass-spec 的所有測試——所以今天我只發佈了 1.0.0-alpha.1 版本。但它已經足夠穩定,您可以下載、試用並開始提交問題

您可以從發佈頁面下載一個獨立的壓縮檔——只需解壓縮它,將資料夾添加到您的路徑中,然後執行 dart-sass。Dart 也能編譯成 JavaScript,所以如果您安裝了 npm,您可以透過執行 npm install -g dart-sass 來安裝 JS 版本。此外,如果您本身就是 Dart 的使用者,您可以使用 pub global activate sass 安裝它。(依據現今 Dart 安裝方式調整)

為何重寫 Sass?為何重寫 Sass? 永久連結

在過去幾年中,主要有兩個 Sass 的實作版本。Ruby Sass 是原始版本,主要由我編寫,並得到 Chris 的大力協助。它的層級較高且易於修改,因此我們在新功能的迭代和首次發佈都在這裡進行。然後是 LibSass,一個 C++ 的實作版本,最初由 AaronHampton 建立,現在由 MarcelMichael 負責維護。它的層級較低,這使得它速度非常快,並且易於安裝和嵌入到其他語言中。尤其是它的 Node.js 綁定,是在 JavaScript 世界中使用 Sass 的一種非常流行的方式。

每個實作的優點都彌補了另一個的缺點。LibSass 快速且可移植,而 Ruby Sass 速度慢且非 Ruby 使用者難以安裝。Ruby Sass 易於迭代,而 LibSass 的低階語言使得添加新功能變得更加困難。互補的關係可能是健康的,但也可能意味著兩種解決方案都不夠好。這就是我們在五月Marcel 正式離開 LibSass 團隊[1] 時的發現。

如果沒有兩個人的努力,我們就不再確定 LibSass 能否跟上 Chris 和我想要將變更引入語言的速度。而且很長一段時間以來,Ruby Sass 對於涉及大型樣式表的使用案例來說太慢了。我們需要一個新的實作,一個可以快速生成 CSS *並且*快速添加新功能的實作。

為何選擇 Dart?為何選擇 Dart? 永久連結

我們考慮了一些可能的語言,最終決定選擇 Dart,原因有很多。首先,它*非常快*——Dart VM 通常比 JavaScript VM 快得多,而且早期基準測試[2] 表明,對於大型樣式表,Dart Sass 比 Ruby Sass 快 5-10 倍,而且只比 LibSass 慢約 1.5 倍。我大膽猜測它比慣用的 JS 實作快約 1.5-2 倍,但我不能確定。而且 Dart 的效能一直在不斷提升。

同時,Dart 也很容易上手——比 C++ 容易得多,某種程度上來說,對於這樣一個大型專案,它甚至比 Ruby 更容易使用。當然,熟悉 Dart 的人數不如 JavaScript 多,但語言實作通常不會獲得太多外部貢獻。新的實作主要由我負責,而 Dart 正是我目前最熟悉的語言(當我不在開發 Sass 時,我就在 Dart 團隊工作)。使用 Dart 能讓我大幅提升開發速度。

與 Ruby 或 JavaScript 不同,Dart 是*靜態類型*語言,因此每個值的類型都可以在不執行程式碼的情況下確定。與 C++ 不同的是,它具有*垃圾回收*機制,因此我們不必過於擔心清理工作。這使得程式碼易於編寫、修改和維護。也許更重要的是,它易於轉換成其他程式語言,這將有助於 LibSass 更快地獲得新功能。

我們選擇 Dart 的最後一個原因是只有少數其他語言才能吹噓的:JavaScript 相容性。Dart 可以編譯成 JavaScript,可以直接在 Node.js 中使用,甚至可能在瀏覽器中運行。Sass 生態系統的很大一部分建立在 node-sass 之上,我們打算讓 Dart Sass 的 JS 版本盡可能與 node-sass 的 API 相容,以便它可以輕鬆地整合到現有的工具和建構系統中。

唯一的缺點是速度會受到影響:Dart Sass 在 V8 上運行的速度大約是在 Dart VM 上運行速度的一半。然而,這仍然比 Ruby Sass 快 3 到 4 倍。最終,我們也希望為使用 JS 編譯版本的使用者提供一條輕鬆的途徑,讓他們可以盡可能順利地轉移到 Dart VM 版本。

其他實作會發生什麼事?其他實作會發生什麼事? 永久連結

LibSass 的開發沒有任何改變。Michael 正努力添加 Sass 3.5 的功能,我們預計隨著新語言功能的添加,這個過程將會繼續下去。唯一的區別是,LibSass 不再需要與最新版本的語言嚴格相容才能啟動該版本,因為它將不再是唯一具有合理效能的實作。

更大的彈性意味著 LibSass 可以更快發布版本,並優先考慮使用者最想要的功能。嚴格的相容性意味著,像CSS 自訂屬性支援這樣的重大功能,在對應的 Ruby Sass 版本中所有細微棘手的邊緣情況(例如:root 統一)都實作完成之前,都無法發布。我們仍然會盡可能保持相容性,但我們不會讓它阻礙開發速度。

另一方面,除非出現新的維護者,否則 Ruby Sass 最終將會消失。我們不想突然進行轉換,以免造成生態系統的分裂:Chris 和我承諾維護它一年,其中包括讓語言與 Dart Sass 中的任何新增功能保持同步。如果有人有興趣在該期限之後自願擔任維護者,我們很樂意指導他們,並在未來一年教導他們程式碼庫。但是,如果沒有人挺身而出,Ruby Sass 將被正式視為已棄用且不再維護。

我想強調的是,我們決定停止開發 Ruby Sass 並非輕率之舉。這是一個重大的改變,對我來說並不容易——我持續開發 Ruby Sass 將近十年,要放下這段歷史很困難。但 Chris 和我已經徹底討論過,我們確信這是正確的決定。我們投入在 Sass 的時間有限,繼續將時間花在一個對許多大型用戶來說速度慢到不切實際的實作上,已經沒有意義了。

接下來呢?接下來呢?永久連結

在我們發布 Dart Sass 的第一個穩定版本之前,我們的待辦事項清單上還有一些重要的項目。

  • 完全兼容 sass-spec。Dart Sass 在語言的許多角落仍然存在錯誤,尤其是關於 @extend 的部分。我不認為有任何單獨的不兼容性特別難以解決,而且 sass-spec 非常全面,所以只要穩步減少失敗的規格數量,直到它歸零即可。

  • 在 npm 套件中提供與 node-sass render() 足夠接近的兼容性。node-sass 的 render() API 是 JavaScript 世界中 LibSass 的主要入口點。建構系統使用它來執行 Sass,使用者使用它來定義自訂 Sass 函式,Eyeglass 也使用它將模組傳遞給 Sass。我們希望支援這個 API,使其與 JS 編譯的 Dart Sass 擁有足夠的相容性,讓現有的生態系統可以正常運作。

  • 在 Ruby Sass 中提供與 Dart Sass 的兼容性。在某些情況下,Dart Sass 會刻意與 Ruby Sass 不同,尤其是在 Ruby Sass 的行為被認為是錯誤的情況下。我們應該在 Ruby Sass 中加入棄用訊息,並且如果能在最小程度的干擾下,加入對新行為的支援。

我們最終還想做更多的事情,例如在瀏覽器中支援 Sass,並為 Dart VM 上的 Sass 提供與 node-sass 相容的包裝器,但這些並不會阻礙初始版本的發布。

展望未來展望未來永久連結

接下來的幾個月將會投入大量工作,使 Dart Sass 穩定且兼容,並將Sass 3.5 的功能整合到 LibSass 中。我認為 Dart Sass 的穩定版本和 LibSass 的 3.5 版本很可能在 2017 年初發布。到那時,我們將著眼於重大功能,並開始朝 Sass 4.0 及其全新的模組系統邁進。

Dart Sass 是一個重大的改變,但它也是一個令人興奮的改變。它將使我們能夠更快地將新功能交付到使用者手中,並使這些功能運行得更快。它將使用戶能夠輕鬆地安裝和運行參考實作。它也將首次為我們提供一種在純 JavaScript Sass 中高效運行 Sass 的方法。這些好處是巨大且 tangible 的,我相信它們值得我們付出這些成本。


  1. 我說「正式」是因為他仍然在盡可能地為專案貢獻,只是不再是以正式維護者的身份。↩︎

  2. 注意事項:我不是基準測試專家,而且這些測試是臨時的,並且是針對非典型的原始樣式表運行。如果有人有興趣進行更科學的基準測試,請告訴我!↩︎