Sass 與建置工具整合:Vite、Webpack 與元件框架
現代專案很少直接下 sass 指令,編譯這件事會併進建置工具。好消息是:多數情況什麼設定都不用。
Vite
npm i -D sass裝完就能用:
// main.js
import "./styles/main.scss";<style lang="scss" scoped>
.card { padding: 16px; }
</style>Vite 偵測到 .scss 就會自動處理,不需要外掛也不需要 loader。
全域注入變數
每個元件都要寫 @use "../abstracts" as a; 有點煩,可以讓 Vite 自動加上:
// vite.config.js
export default {
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/abstracts" as a;`,
},
},
},
resolve: {
alias: { "@": "/src" },
},
};之後每個 .scss 與 <style lang="scss"> 都能直接用 a.space(3)。
只能注入「不產生 CSS」的東西
// ❌ 每個元件都會多出一份 reset 的樣式
additionalData: `@use "@/styles/base/reset";`abstracts 裡只有定義,注入幾百次都不會產生樣式;base、components 裡有規則,注入就會爆炸。原則見 abstracts 該放什麼。
這個設定有隱形成本
從檔案本身看不出 a 是哪來的,新人會找不到。如果團隊會困惑,寧可每個檔案自己寫一行 @use。
Webpack
npm i -D sass sass-loader css-loader style-loader// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `@use "@/styles/abstracts" as a;`,
},
},
],
},
],
},
};loader 的順序是由後往前
陣列裡 sass-loader 在最後,卻是 最先 執行的。順序寫反會出現一堆看不懂的錯誤。
正式環境要把 CSS 抽成獨立檔案:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 把 style-loader 換成 MiniCssExtractPlugin.loaderVue 單檔元件
<style lang="scss" scoped>
@use "@/styles/abstracts" as a;
.card {
padding: a.space(3);
&__title {
@include a.truncate;
}
}
</style>scoped 會給每個元素加上唯一的屬性,樣式不會外洩。搭配 BEM 時其實可以不用 scoped,類別名本身就夠獨特了。
深層選取器
scoped 的樣式選不到子元件內部,需要穿透:
.wrapper :deep(.child) {
color: red;
}CSS Modules
// Card.module.scss
.card {
padding: 16px;
}import styles from "./Card.module.scss";
<div className={styles.card} />類別名會被編譯成獨特的字串,不會撞名。
CSS Modules 與 BEM 是兩套方案
用了 CSS Modules 就不需要 BEM 的長類別名了,.title 就夠。兩個一起用只會讓類別名變成 Card_card__title__x7f2q。
別名讓載入路徑好看
// ❌ 相對路徑一深就難讀
@use "../../../abstracts" as a;
// ✅
@use "@/styles/abstracts" as a;Vite 用 resolve.alias,Webpack 用 resolve.alias,兩者都要 同時 讓 Sass 認得。Sass 對 ~ 與 @ 開頭路徑的處理各家工具略有不同,設定完務必實測一次。
產出的順序
元件樣式的順序由 模組的引入順序 決定,不是檔案路徑:
import "./styles/main.scss"; // 全域樣式先
import Card from "./Card.vue"; // 元件樣式後不要賭順序
需要確保覆蓋關係時,靠選取器的設計而不是載入順序。順序在不同工具、不同模式下可能不一樣。
警告訊息在終端機
Sass 是在 Node 端 編譯的,@debug 與 @warn 的輸出會印在跑 npm run dev 的那個終端機裡,不是瀏覽器的主控台。
第三方套件的棄用警告很吵的話:
css: {
preprocessorOptions: {
scss: { quietDeps: true },
},
}常見問題
Vite 要裝什麼才能用 Sass?
只要把 sass 裝成開發相依就好,不需要任何外掛或 loader。Vite 偵測到 .scss 就會自動處理,import 進 JavaScript 或寫在單檔元件裡都能運作。
additionalData 該注入什麼?
只注入變數與混入這類不會產生 CSS 的東西。注入會產生規則的檔案會讓每個元件都多輸出一份樣式,這是這個設定最常見的誤用。
為什麼元件裡的樣式順序和預期不同?
因為元件樣式的載入順序由模組的引入順序決定,不是由檔案路徑決定。需要確保覆蓋關係時,應該靠選取器的設計而不是賭順序。
Sass 的警告訊息在瀏覽器看不到?
因為編譯是在 Node 端進行的,訊息會印在跑開發伺服器的那個終端機裡,不是瀏覽器的主控台。