SCSS无法动态扫描或清除CSS选择器,因其仅为编译时预处理器,不接触HTML或DOM;所有清理需借助Node.js等外部工具链进行三步比对:提取SCSS选择器、提取模板中class/id、取差集标记废弃。

SCSS 本身无法动态扫描或清除 CSS 选择器——它只是编译时预处理器,不接触 HTML 结构或运行时 DOM。 所有“自动清理废弃选择器”的需求,必须脱离 SCSS 单独构建扫描流程,SCSS 文件只能作为输入源之一,不能承担检测逻辑。
为什么不能用 @each 或 @if 在 SCSS 里做“动态扫描”
SCSS 编译阶段完全不知道你的 HTML 长什么样、哪些元素还存在、哪些 class 被 JS 动态增删过。它只按顺序展开变量、嵌套、混合宏,最终输出纯 CSS 字符串。试图在 .scss 文件里写逻辑去“查 DOM”或“读 HTML”,编译直接报错或静默忽略。
-
@debug只能打印编译时已知值(如变量内容),无法访问外部文件或页面结构 - 没有
fs.readFile()类 API,SCSS 不具备 I/O 能力 - 所谓“动态”仅限于编译期变量计算,不是运行时行为
真正可行的清理路径:用 Node.js 扫描 + 正则/AST 解析 + 比对
核心思路是三步比对:提取所有 SCSS 中定义的选择器 → 提取项目中所有 HTML/JSX/Templates 里实际出现的 class/id → 取差集标记为“疑似废弃”。
- 用
postcss+postcss-scss解析.scss文件,通过rule.selectors获取完整选择器列表(支持嵌套、& 运算、插值) - 用
cheerio(HTML)或@babel/parser(JSX)提取模板中的class、className、id属性值 - 注意:需展开 BEM 命名(如
.btn__text和.btn--primary要能匹配btn基础块)、忽略动态拼接(class={`${a} ${b}`}无法静态分析,应人工标记为“不可信”) - 推荐工具链:
purgecss(生产环境已验证)或unocss(按需生成),但它们不反向输出“废弃列表”,需二次开发
一个轻量实操示例:用 glob + postcss 提取 SCSS 选择器
以下 Node.js 脚本可导出所有 SCSS 中声明的一级选择器(不含注释、混合宏内部):
const postcss = require('postcss');
const scss = require('postcss-scss');
const glob = require('glob');
const fs = require('fs');
glob('src/**/*.scss', (err, files) => {
const selectors = new Set();
files.forEach(file => {
const css = fs.readFileSync(file, 'utf8');
postcss().process(css, { parser: scss }).then(result => {
result.root.walkRules(rule => {
rule.selectors.forEach(sel => {
// 剔除 &:hover 等伪类,只留基础类名
sel.split(/,\s*/).forEach(s => {
const base = s.trim().match(/\.([a-zA-Z0-9_-]+)/);
if (base) selectors.add(base[1]);
});
});
});
});
});
console.log([...selectors]); // 输出所有疑似 class 名
});
⚠️ 注意:rule.selectors 是字符串,含嵌套生成的完整选择器(如 .card .card__title),需按需切分;插值如 .#{$ns}-btn 无法解析出真实值,这类必须人工维护白名单。
真正难的不是提取,而是定义“废弃”——CSS 选择器可能被 JS 动态添加、服务端渲染条件注入、或用于状态钩子(如 .is-open)。漏删会破 UI,误删难定位。建议先用 purgecss --dry-run 对比前后体积,再逐条确认差异项。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











