根本原因是模块加载路径不统一、入口注入方式冲突或第三方库混用旧机制:@use "a"与@use "@/a"被dart sass视为两个模块,additionaldata重复注入与组件内@use并存导致双重解析,第三方@import混用破坏单例。

为什么改用 @use 还是打包出重复 CSS
根本原因不是语法没换,而是模块加载路径不统一、入口注入方式冲突、或第三方库混用旧机制。Dart Sass 会把 @use "a" 和 @use "@/a" 当作两个不同模块处理,各自编译一次;同样,vite.config.ts 里用 additionalData 注入 @use,但组件 SCSS 文件又自己 @use "index",等于触发两轮独立解析。
常见错误现象:
- 同一个颜色变量(如
t.$color-primary)在最终 CSS 中出现多次声明 - 某个
@mixin flex-center()的样式块被展开三遍,分散在不同组件区块里 - 构建后 CSS 体积比迁移前还大,且 sourceMap 开启时更夸张
实操建议:
- 所有
@use路径必须绝对统一:推荐全用别名路径(如@use "src/styles/tokens" as t),禁用相对路径(@use "../tokens") -
vite.config.ts的preprocessorOptions.scss.additionalData只写一行:@use "@/styles/index.scss" as *,且确保项目中再无其他地方显式@use "index" - 禁用
sourceMap: true上线构建——它会在 CSS 底部追加 base64 字符串,体积翻倍 - 检查第三方 Sass 库(如
bootstrap/scss)是否仍在用@import;若必须混用,把它放在index.scss最末尾,避免覆盖你自己的变量
@forward 怎么用才不破坏单例语义
@forward 不是“转发引用”,而是“暴露接口”。如果只写 @forward "mixins",下游文件仍需 @use "mixins" 才能访问,这就绕过了单例——Sass 会重新加载该文件。
正确做法是配合 as * 显式导出,并约束下游调用方式:
- 在
src/styles/index.scss中写:@forward "tokens" as t-*; @forward "mixins" as m-*; - 这样下游只需
@use "@/styles/index.scss" as i;,然后用i.t-color-primary和i.m-flex-center() - 禁止在组件 SCSS 里再单独
@use "tokens"或@use "mixins",否则打破模块唯一性 - 若某模块内部需要复用另一个模块的 mixin(如
_button.scss用flex-center),它应该@use "index" as i;,而不是直接引入子模块
如何验证重复打包问题已解决
别只看文件数或行数,直接查编译输出的 CSS 内容。一个变量或 mixin 的输出是否真正收敛,就看它在最终 CSS 中是否只存在一份。
实操步骤:
- 运行构建命令(如
vite build),打开生成的.css文件 - 搜索某个基础变量生成的样式,例如
color: #333或border-radius: 4px - 确认该规则只出现一次,且上下文清晰(比如只在
.btn或.card块内) - 反向验证:在任意组件 SCSS 中删掉对某个 mixin 的调用(如注释掉
@include i.m-flex-center()),再构建,确认对应 CSS 规则彻底消失
最容易被忽略的一点:模块化不是靠文件数量体现的,而是靠“谁定义、谁消费、谁负责”这条链路是否干净。哪怕只拆了 3 个文件,只要 @forward 和 @use 路径全走通、additionalData 配置无冗余、第三方库不抢跑,CSS 就不会重复。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











