必须用 @use 而非 @import:因 @import 全局污染变量/mixin,@use 强制命名空间隔离、自动剔除未用代码、支持精准跳转、需兼容层处理旧依赖;\_index.scss 是契约接口,仅汇总与导出;base/ 为根基建,utils/ 纯逻辑层,组件须视觉独立、无外部依赖、禁深层嵌套、严守 bem。

@use 是模块化组件库的强制起点,不是可选项——用 @import 写任何一行,整个架构就退化成不可预测的全局污染源。
为什么必须用 @use 而不是 @import
旧式 @import 会把所有变量、mixin 全部注入全局作用域,一旦两个组件文件都定义了 $border-radius,后引入的那个直接覆盖前一个,且毫无提示。而 @use 强制命名空间隔离:@use 'components/button' as btn 后,你只能通过 btn.$size-lg 访问,不可能误用或被覆盖。
- 编译时自动剔除未使用的 mixin 和变量,CSS 体积可控;
@import下哪怕只用了一个@include reset,整个_reset.scss都会打进输出 - VS Code + Dart Sass 插件能精准跳转到
@use的源文件;@import常报 “Definition not found” - 第三方依赖(如
node_modules里的旧 Sass 包)必须用@use兼容层包裹,否则整条依赖链失效
_index.scss 不是辅助文件,是组件库的契约接口
每个功能目录(components/、themes/、layout/)必须配一个 _index.scss,它只干两件事:汇总子模块 + 控制导出粒度。
- 不能写任何样式规则或
@include,它只是“路由表” - 用
@forward 'button' as btn-*;把按钮所有公开成员加前缀,避免和用户项目变量名冲突 - 用
@use 'variables' as vars+@forward 'variables' hide $private-var;可选择性隐藏内部变量
base/ 和 utils/ 的边界一旦模糊,组件就失去可移植性
base/ 是根级基础设施:只放 _reset.scss、:root { --color-primary: #3498db; }、全局字体设置。这里出现 .button 或 $card-shadow 就越界了。
utils/(或 abstracts/)是纯逻辑层:只存 _variables.scss(断点 map、主题色 map)、_mixins.scss(@mixin respond-to($bp))、_functions.scss(@function em($px))。它不输出任何 CSS。
- ❌ 错误:
utils/_mixins.scss里写@mixin card-shadow—— 这属于components/_card.scss的职责 - ✅ 正确:
components/_card.scss内部调用map-get($shadows, sm)+@include respond-to(md) - ⚠️ 性能注意:
_functions.scss中递归函数(如颜色明度计算)若没加@if global-variable-exists()缓存机制,每次调用都会重新编译
组件文件本身要满足“视觉独立 + 无外部依赖”
每个 _button.scss 应该对应一个视觉上可独立存在的 UI 单元,且内部不引用 pages/、不跨组件 @import、不写 !important。
- 禁止深层嵌套:
.header { .nav { &__item { } } }编译后是.header .nav .nav__item,权重高、难覆盖;改用平铺.nav__item - 状态样式(
&.is-active)、响应式(@include respond-to(sm))全在本文件内闭环 - BEM 命名必须严格:
.ms-button(块)、.ms-button__icon(元素)、.ms-button--primary(修饰符),前缀防冲突
真正难的不是第一次写对 @use 和 _index.scss,而是新增组件时,团队下意识先建 _index.scss、再 @forward、绝不手写 @import。一旦松动,模块边界就从设计文档里消失,变成靠人肉约定维系的东西。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











