Sass @forward:把模組聚合成單一入口
@forward 與 @use 常被搞混,但兩者的差別只有一句話:
@use是載入來自己用;@forward是把成員傳遞出去給別人用。
| 我自己用得到嗎 | 載入我的人拿得到嗎 | |
|---|---|---|
@use "colors" | ✅ | ❌ |
@forward "colors" | ❌ | ✅ |
它要解決什麼
沒有 @forward 的話,每個檔案都得自己知道所有零件的路徑:
// components/_card.scss
@use "../abstracts/variables" as v;
@use "../abstracts/mixins" as mx;
@use "../abstracts/functions" as fn;三十個元件檔就要重複三十次。有了 @forward,在 abstracts 目錄放一個入口:
// abstracts/_index.scss
@forward "variables";
@forward "mixins";
@forward "functions";元件檔就只剩一行:
// components/_card.scss
@use "../abstracts" as a;
.card {
padding: a.$gap;
@include a.center;
}之後 abstracts 裡新增檔案,只要在 _index.scss 補一行 @forward,三十個元件檔一個都不用改。
自己也要用的話,兩行都要寫
@forward 不會讓自己拿到成員:
// abstracts/_index.scss
@forward "variables";
@use "variables" as v; // 自己也要用,得再寫一次
.debug-grid {
outline: 1px solid v.$brand;
}這兩行並存是完全正常的寫法。
show:只轉發指定的成員
白名單,明確定義這個模組對外的介面:
@forward "button" show $radius, btn-base, is-active;只有列出的三個成員會傳遞出去,其他都藏起來。變數要寫 $,混入 與 函式 直接寫名字。
hide:藏起指定的成員
黑名單,其餘全部轉發:
@forward "button" hide $internal-padding, reset-button;兩者的取捨
show 讓介面明確,但每加一個成員就要改一次清單;hide 省事,但外面可能拿到你不打算公開的東西。要當成套件給別人用就 show,專案內部自己用 hide 就夠了。
只是想藏一兩個內部工具的話,其實用 私有成員(名稱加底線開頭)更簡單,不必寫 hide。
as 加前綴
多個模組聚合到同一個入口時,名稱可能撞在一起。as 加上前綴可以避免:
// _index.scss
@forward "button" as btn-*;
@forward "card" as card-*;@use "components" as c;
.a {
@include c.btn-base; // 來自 _button.scss 的 base
@include c.card-base; // 來自 _card.scss 的 base
}兩個模組都有 base 混入也不會衝突。
轉發時預設值也能改
@forward 也支援 with,用來調整被轉發模組的預設值:
// abstracts/_index.scss
@forward "variables" with (
$gap: 24px !default
);結尾的 !default 很重要,它表示「這是我調整過的新預設值,載入我的人仍然可以再覆寫」。省略的話就會寫死,外面就不能再改了。
完整的目錄結構
scss/
├── main.scss
├── abstracts/
│ ├── _index.scss ← 全是 @forward
│ ├── _variables.scss
│ └── _mixins.scss
└── components/
├── _index.scss ← 全是 @forward
├── _button.scss
└── _card.scss// main.scss
@use "abstracts" with ($gap: 24px);
@use "base";
@use "components";入口檔不要寫成 @use
_index.scss 若寫 @use "variables",成員就只有 _index.scss 自己拿得到,外面載入這個目錄什麼都取不到。聚合用的入口檔一律 @forward。
檔案怎麼分見 7-1 檔案架構。
常見問題
@forward 之後可以在同一個檔案裡用那些成員嗎?
不行。@forward 只負責把成員傳遞出去,自己不會拿到。同一個檔案若也要使用,必須另外再寫一次 @use,兩行並存是正常且常見的寫法。
show 和 hide 差在哪?
show 是白名單,只轉發列出的成員;hide 是黑名單,轉發列出的以外的全部。想明確控制模組對外的介面就用 show,只是要藏掉一兩個內部工具就用 hide。
轉發時可以加前綴嗎?
可以,寫成 as btn-* 就會讓所有轉發出去的成員名稱都加上 btn- 前綴。這樣多個模組被聚合到同一個入口時,名稱不會互相衝突。
入口檔要用 @forward 還是 @use?
純粹用來聚合的 _index.scss 應該整份都是 @forward,因為它自己不使用那些成員,只是把它們傳遞給載入這個目錄的人。若寫成 @use,外面的檔案就什麼都拿不到。