意見徵求:模組系統
由 Natalie Weizenbaum 發佈於 2018 年 11 月 27 日
許多針對 Sass 最常被提出的功能需求都與其導入機制有關。坦白說,我們從 Sass 早期版本就一直沿用的導入系統並不理想。它幾乎只是將一個 Sass 檔案的文字內容包含到另一個檔案中,這使得難以追蹤 mixin、函式和變數的定義位置,也難以確保任何新增內容不會與專案其他地方的內容衝突。更糟的是,它與 CSS 內建的 @import
規則重疊,迫使我們必須使用一堆啟發式方法來區分兩者。
由於這些問題以及其他原因,我們一直以來都想徹底改造 Sass 檔案之間的關聯方式。在過去幾年中,我一直與 Sass 核心團隊和 Sass 框架維護者合作,制定一個適合取代 @import
的模組系統提案。目前核心團隊對這個提案相當滿意,至少可以作為一個起點,因此我們想公開徵求社群的意見。
如果您想閱讀完整的提案,它可以在 GitHub 上找到。歡迎針對您的任何意見提出 issue。提案的主體是以規格書的形式撰寫,因此非常詳細,但目標、摘要和常見問題 (FAQ) 部分(如下所示)對於任何熟悉 Sass 的人都應該很容易理解。
目標目標的永久連結
高階目標高階目標的永久連結
這些是整個模組系統的哲學設計目標。雖然它們並未明確指定一個系統,但它們確實代表了許多低階設計決策背後的根本動機。
-
局部性。模組系統應該讓開發者只需查看該檔案即可理解 Sass 檔案。其中一個重要面向是,檔案中的名稱應該根據檔案的內容來解析,而不是根據編譯的全局狀態。這也適用於編寫程式碼:只要名稱與檔案中可見的任何名稱不衝突,作者就應該可以確信該名稱可以安全使用。
-
封裝性。模組系統應該允許作者,尤其是函式庫作者,選擇他們要公開的 API。他們應該能夠定義供內部使用的實體,而不會讓外部使用者存取或修改這些實體。函式庫實作到檔案中的組織方式應該足夠彈性,可以在不改變使用者可見的 API 的情況下進行更改。
-
可設定性。Sass 在程式語言中很不尋常,因為它的設計導致使用一些檔案,其唯一目的是產生副作用,特別是產生 CSS。還有一類更廣泛的函式庫,它們可能不會直接產生 CSS,但會定義用於計算的設定變數,包括計算其他頂層變數的值。模組系統應該允許使用者彈性地使用和設定具有副作用的模組。
低階目標低階目標的永久連結
這些目標基於實用性而非哲學。它們大多來自我們多年來收集的關於 @import
的使用者回饋。
-
單次導入。由於
@import
是字面上的文本包含,在編譯範圍內多次@import
同一個 Sass 檔案將會導致該檔案被多次編譯和執行。在最好的情況下,這會損害編譯時間卻幾乎沒有任何好處,而且當樣式本身被複製時,它還會導致 CSS 輸出過於臃腫。新的模組系統應該只編譯一個檔案一次。 -
向下相容性。我們希望盡可能讓使用者輕鬆遷移到新的模組系統,這意味著要讓它與使用
@import
的現有樣式表一起運作。僅使用@import
的現有樣式表應該與早期版本的 Sass 具有相同的導入行為,並且樣式表應該能夠將部分內容更改為@use
,而無需一次更改整個樣式表。
非目標非目標永久連結
基於各種原因,我們已明確決定不在此提案中追求這些潛在目標。其中一些目標可能會在未來的工作中考慮,但我們認為它們不會阻礙模組系統的發展。
-
動態導入。允許模組的路徑被動態定義,無論是通過包含變數還是將其包含在條件區塊中,都會偏離宣告式的特性。除了使樣式表更難閱讀之外,這也使任何形式的靜態分析更加困難(在一般情況下實際上是不可能的)。它還限制了未來實作最佳化的可能性。
-
一次導入多個檔案。除了長期以來不支持這個功能的原因——它會讓作者陷入難以除錯的隱蔽排序錯誤——之外,這也違反了局部性原則,因為它混淆了導入的檔案以及名稱的來源。
-
僅限延伸的導入。導入一個檔案,使其產生的 CSS 除非被
@extend
否則不會被輸出的想法很酷,但這也是很多額外的工作。這個功能最有可能在未來的版本中出現,但它並非核心功能,因此不包含在最初的模組系統中。 -
與上下文無關的模組。我們很容易想要讓載入的模組形式(包括它產生的 CSS 和所有變數的解析值)完全獨立於導致其載入的入口點。這將使得在多個編譯之間共用載入的模組成為可能,甚至可能將它們序列化到檔案系統以進行增量編譯。
然而,這在實務上是不可行的。產生 CSS 的模組幾乎總是基於某些配置,而這些配置可能會被不同的入口點更改,從而使快取失效。此外,多個模組可能依賴於同一個共用模組,並且一個模組可能會在另一個模組使用它之前修改其配置。一般來說,禁止這種情況實際上等同於禁止模組基於變數產生 CSS。
幸運的是,實作可以自由地快取它們可以靜態確定與上下文無關的資訊,包括原始碼樹,甚至可能包括常數摺疊的變數值和 CSS 樹。除了這些之外,完全的上下文獨立性不太可能提供更多價值。
-
更嚴格的規範。擁有眾多成員的大型團隊通常需要更嚴格的 Sass 樣式表撰寫規則,以落實最佳實務並快速發現錯誤。很容易想利用新的模組系統來進一步提升嚴格性;例如,我們可以讓部份檔案直接產生 CSS 變得更困難,或者我們可以拒絕將我們希望人們避免使用的函式移至新的內建模組。
然而,儘管很誘人,我們希望在新系統中盡可能簡化所有現有的使用案例,*即使我們認為應該避免這些案例*。這個模組系統已經與現有行為大相徑庭,並且需要 Sass 使用者進行大量的工作來支援。我們希望盡可能簡化這個轉換過程,其中一部分就是避免增加任何不必要的步驟,讓使用者在新模組系統中使用現有的樣式表。
一旦生態系統中徹底採用
@use
,我們就可以開始考慮以 lints 或 TypeScript 風格的--strict-*
旗標的形式提高嚴格性。 -
程式碼分割。將單體 CSS 分割成可以延遲載入的獨立區塊的能力對於維護大型應用程式的快速載入時間至關重要。然而,這與此模組系統嘗試解決的問題無關。此系統主要關注的是 Sass API(mixins、函式和佔位符)的作用域,而不是宣告生成的 CSS 區塊之間的依賴關係。
我們相信此模組系統可以與外部程式碼分割系統協同工作。例如,模組系統可用於載入用於設定個別元件樣式的程式庫,每個元件都被編譯成自己的 CSS 檔案。然後,這些 CSS 檔案可以使用特殊註釋或自定義 at-rules 宣告彼此之間的依賴關係,並由程式碼分割後處理器將它們拼接在一起。
摘要摘要永久連結
此提案新增了兩個 at-rules,@use
和 @forward
,它們只能出現在樣式表的頂層,位於任何規則(@charset
除外)之前。它們的目的是完全取代 @import
,@import
最終將被棄用,甚至最終會從語言中移除。
@use
@use
永久連結
@use
讓目前的樣式表可以存取來自另一個樣式表的 CSS、變數、mixins 和函式。預設情況下,變數、mixins 和函式在基於 URL 基礎名稱的命名空間中可用。
@use "bootstrap";
.element {
@include bootstrap.float-left;
}
除了命名空間之外,@use
和 @import
之間還有一些重要的區別
- 無論樣式表被使用多少次,
@use
只會執行一次樣式表並包含其 CSS。 @use
只會讓名稱在目前的樣式表中可用,而不是全域可用。- 名稱以
-
或_
開頭的成員對於使用@use
的目前樣式表是私有的。 - 如果樣式表包含
@extend
,則該延伸只會應用於它匯入的樣式表,而不是匯入它的樣式表。
請注意,佔位符選擇器*沒有*命名空間,但它們*確實*遵守隱私性。
控制命名空間控制命名空間永久連結
雖然 @use
規則的預設命名空間由其 URL 的基礎名稱決定,但也可以使用 as
明確設定。
@use "bootstrap" as b;
.element {
@include b.float-left;
}
特殊的構造 as *
也可用於引入頂層命名空間中的所有內容。請注意,如果多個模組公開了同名的成員,並且都使用 as *
引入,Sass 將會產生 錯誤。
@use "bootstrap" as *;
.element {
@include float-left;
}
設定函式庫設定函式庫的永久連結
使用 @import
時,函式庫通常是透過設定全域變數來覆寫函式庫中定義的 !default
變數來進行設定。由於變數在 @use
中不再是全域的,因此它支援一種更明確的函式庫設定方式:with
子句。
// bootstrap.scss
$paragraph-margin-bottom: 1rem !default;
p {
margin-top: 0;
margin-bottom: $paragraph-margin-bottom;
}
@use "bootstrap" with (
$paragraph-margin-bottom: 1.2rem
);
這會在評估 bootstrap 的 $paragraph-margin-bottom
變數之前,將其設定為 1.2rem
。with
子句只允許設定在被引入的模組中定義(或轉發)的變數,而且只有在這些變數使用 !default
定義時才允許設定,這樣可以保護使用者避免 拼寫錯誤。
@forward
@forward 的永久連結
@forward
規則會將另一個模組的變數、mixin 和函式包含到目前模組公開的 API 中,但不會讓它們在目前模組的程式碼中可見。它允許函式庫作者將他們的函式庫拆分到許多不同的原始碼檔案中,而不會犧牲這些檔案內的局部性。與 @use
不同,@forward
不會向名稱添加任何命名 空間。
// bootstrap.scss
@forward "functions";
@forward "variables";
@forward "mixins";
可見性控制可見性控制的永久連結
@forward
規則可以選擇只顯示特定 名稱
@forward "functions" show color-yiq;
它也可以隱藏那些只想在函式庫內部使用 的名稱
@forward "functions" hide assert-ascending;
額外前綴額外前綴的永久連結
如果您透過一個整合模組轉發子模組,您可能需要為該模組手動添加一些命名空間。您可以使用 as
子句來完成此操作,它會為每個被轉發的成員名稱添加 前綴
// material/_index.scss
@forward "theme" as theme-*;
這樣,使用者可以使用具有良好作用域名稱的主題 變數的整合模組
@use "material" with ($theme-primary: blue);
或者他們可以使用具有更簡潔 名稱的子模組
@use "material/theme" with ($primary: blue);
@import
相容性@import 相容性的永久連結
Sass 生態系統不會在一夜之間切換到 @use
,所以在過渡期間它需要與 @import
良好地互通。這在兩個方向上都受到 支援
-
當一個包含
@import
的檔案被@use
時,其全域命名空間中的所有內容都被視為單個模組。然後,可以使用其命名空間照常引用此模組的 成員。 -
當一個包含
@use
的檔案被@import
時,其公開 API 中的所有內容都會被添加到引入樣式表的全域作用域中。這允許函式庫控制其匯出的特定名稱,即使對於使用@import
而不是@use
的使用者也是如此。
為了允許函式庫維持現有的以 @import
為導向的 API,並在必要時使用明確的命名空間,此提案還增加了對僅對 @import
可見,而對 @use
不可見的檔案的支援。它們的寫法是 "file.import.scss"
,並在使用者撰寫 @import "file"
時被引入。
內建模組內建模組的永久連結
新的模組系統還將新增七個內建模組:math
、color
、string
、list
、map
、selector
和 meta
。這些模組將包含所有現有的內建 Sass 函式。由於這些模組(通常)會使用命名空間引入,因此使用 Sass 函式而不會與純 CSS 函式發生衝突將會容易得多。
這也讓 Sass 新增函式更加安全。我們預計未來會在這些模組中新增一些便利的函式。
meta.load-css()
meta.load-css() 永久連結
這個提案也新增了一個內建 mixin,meta.load-css($url, $with: ())
。這個 mixin 會動態載入指定網址的模組,並包含其 CSS(雖然它的函式、變數和 mixin 並不會被載入)。這是巢狀匯入的替代方案,它有助於解決動態匯入的一些使用案例,而不會產生許多如果可以動態載入新成員時會出現的問題。
常見問題常見問題 永久連結
-
為什麼使用這種隱私模型? 我們考慮了許多用於宣告成員為私有的模型,包括類似 JS 的模型,其中只有從模組明確匯出的成員才可見,以及使用明確
@private
關鍵字的類似 C# 的模型。然而,這些模型涉及更多的樣板程式碼,而且它們對於可能在單一樣式規則中混合隱私的佔位符選擇器效果特別差。基於名稱的隱私也提供了一定程度的與程式庫已經使用的慣例的相容性。 -
我可以讓成員成為程式庫私有嗎? 沒有「程式庫」的語言層級概念,所以程式庫私有也不是內建的。然而,一個模組使用的成員不會自動對下游模組可見。如果一個模組沒有透過程式庫的主樣式表被
@forward
轉發,它對下游使用者將不可見,因此實際上是程式庫私有的。
作為一個慣例,我們建議程式庫將不打算直接由使用者使用的程式庫私有樣式表寫在名為src
的目錄中。 -
如何讓我的程式庫可設定? 如果你有一個由許多原始檔組成的大型程式庫,所有檔案都共用一些基於
!default
的核心設定,我們建議你在一個從程式庫入口點轉發並由程式庫檔案使用的檔案中定義該設定。例如:
// bootstrap.scss
@forward "variables";
@use "reboot";
// _variables.scss
$paragraph-margin-bottom: 1rem !default;
// _reboot.scss
@use "variables" as *;
p {
margin-top: 0;
margin-bottom: $paragraph-margin-bottom;
}
// User's stylesheet
@use "bootstrap" with (
$paragraph-margin-bottom: 1.2rem
);
傳送意見回饋傳送意見回饋 永久連結
這仍然只是一個提案。我們對模組系統的整體形狀相當滿意,但它還沒有完全定案,任何事情都可能隨著像您這樣的使用者提供的足夠意見回饋而改變。如果您有任何意見,請在 GitHub 上提交 issue或直接在 Twitter 上 @SassCSS 發推文。我們會接受從「看起來很棒」到「看起來很糟糕」的任何意見,當然,您提供的資訊越具體,我們就擁有越多資訊可以運用!