Sass和PostCSS是分工明确的上下游搭档:Sass负责将含变量、嵌套等语法的源码编译为标准CSS,PostCSS再对其执行前缀补全、压缩等优化;二者顺序不可颠倒,否则PostCSS会因解析SCSS语法而报错。
Sass 和 PostCSS 不是替代关系,而是分工明确的上下游搭档:前者负责「写得清楚」,后者负责「发得靠谱」。
Sass 编译必须在 PostCSS 处理之前Sass 的核心任务是把带变量、嵌套、@mixin、@function 的源码转成标准 CSS;它不处理浏览器兼容、不压缩、不加前缀。如果跳过这步直接喂给 PostCSS,你会得到语法错误——因为 PostCSS 解析器只认合法 CSS,不认识 $color 或 @if。
sass-loader(Webpack)或 dart-sass CLI 必须排在 postcss-loader 前面 vite-plugin-sass 的执行顺序早于 postcss 阶段(默认满足) PostCSS 报错 Unknown word 或 Unexpected token "$",基本就是 Sass 没先编译 autoprefixer 不能替代 Sass 的结构能力autoprefixer 是 PostCSS 最常用插件,但它只做一件事:查 CanIUse 数据库,按配置补 -webkit-、-ms- 等前缀。它无法:
$primary: #3498db) @mixin btn-base) @for $i from 1 through 12 { .col-#{$i} { ... } }) 这些都得靠 Sass 在编译前组织好。试图用纯 PostCSS + 插件模拟,要么代码冗长,要么失去可维护性。
立即学习“前端免费学习笔记(深入)”;
cssnano 压缩对未编译的 Sass 无效cssnano 工作对象是标准 CSS AST,它压缩的是属性合并、空格移除、颜色简写等。如果你把 .scss 文件直接丢给 cssnano,它会直接报错退出。
input.scss → dart-sass → output.css → postcss(含 cssnano)→ dist.css postcss-loader 放在 sass-loader 前面,导致压缩阶段输入仍是 SCSS 语法 cssnano 压缩已编译 CSS 效率高;若强行让它处理未编译源码,构建直接中断 sourceMap 调试链容易断在中间环节开发时依赖浏览器 DevTools 点击样式跳转源文件,这个体验高度依赖完整的 sourceMap 链:.scss → .css → .min.css。但很多配置会悄悄切断它:
sass-loader 默认开启 sourceMap,但若 postcss-loader 没配 sourceMap: true,后续步骤就丢失映射 cssnano 默认会丢弃 sourceMap,需显式设 preset: ['default', { discardComments: { removeAll: true } }] 并保持 sourceMap 传递 postcss-sass 这类融合工具时,要确认它是否透传原始 .scss 的位置信息(Dart-Sass 实现通常支持,Node-Sass 已废弃,不推荐)真正难调试的不是语法错误,而是样式生效了但改了 SCSS 却没反应——八成是某处 sourceMap 或 watch 配置漏掉了。