babel死代码消除插件在真实项目中基本失效,因其仅识别if(false)和/*#\_\_pure\_\_*/标注,无法处理环境变量、平台判断等语义不可达分支。

不能只靠现成插件,必须结合项目语义写定制逻辑——Babel、Webpack、Clang 各有适用边界,选错工具会白忙活。
为什么 @babel/plugin-transform-dead-code-elimination 在真实项目里基本失效
它只识别 if (false) 或带 /*#__PURE__*/ 标注的调用,对 process.env.FEATURE_LOGIN === 'false'、__DEV__ && console.log()、typeof window !== 'undefined' && initDom() 这类环境驱动或平台判断的死分支完全无感。老旧项目里 dead code 往往藏在 feature flag、构建时注入的配置、历史遗留的条件导出里,语法合法但语义不可达——Babel 默认不模拟求值,也就无从删起。
常见错误现象:npm run build 后打包体积没变化,source-map-explorer 仍能看到整块被屏蔽的模块代码;线上运行时也从未触发,但依然在 bundle 里。
- 只处理严格相等(
===)、不等(!==)、真值否定(!process.env.X),避开==和类型转换场景 - 必须传入明确的
envMap配置,比如{ FEATURE_LOGIN: 'false', API_VERSION: 'v2' },不能依赖运行时 - 删除前需确认该表达式无副作用:不涉及函数调用、getter、
new实例化等
如何让 Webpack 插件识别并删除真正无依赖的文件
Webpack 的 fileDependencies 是可靠来源,但它只记录「被 import/require 过」的路径,不包含动态 require('./' + name)、import() 字符串拼接、或 Cocos Creator 类反射加载的资源。所以单纯比对 src/** 和依赖列表会误删。
使用场景:Vue/React 项目中长期迭代残留的未引用组件、工具函数、废弃页面路由文件。
- 入口目录需显式配置(如
src),避免扫描node_modules或public - 排除规则要覆盖构建产物(
dist)、配置文件(vue.config.js)、测试文件(**/__tests__/**) - 启用
isDelete: true前务必先生成unused-files.json人工核对,尤其注意import()动态加载的字符串字面量是否被静态分析捕获
Clang 插件适合剔除哪类 C/C++ 无用逻辑
Clang 插件能深入 AST 和控制流图(CFG),适合检测函数级、变量级、宏定义级的死逻辑,比如永远不进入的 if 分支、未使用的 static 函数、被 #ifdef 屏蔽整段的 API 实现。它不处理 JS 那种运行时环境判断,但对编译期可判定的 C 预处理器逻辑非常精准。
性能影响:插件在编译阶段运行,会略微增加构建耗时;但相比运行时检测,它是零开销的静态保障。
- 必须继承
RecursiveASTVisitor并重写VisitIfStmt、VisitFunctionDecl等方法 - 对
#ifdef DEBUG类宏,需配合Preprocessor接口获取宏定义状态,不能只看 AST 节点 - 删除操作不是直接改源码,而是通过
DiagnosticEngine报告 + 外部脚本清理,或用Rewriter生成 patch 文件
跨文件未使用导出的剔除为什么不能只靠 Babel
Babel 是单文件 AST 变换器,它看不到 utils.js 里某个 export function throttle() 是否在 main.js 或 feature/login.js 中被 import 过。必须借助打包工具的 module graph 或 ESLint 的跨文件引用分析结果。
容易踩的坑:export default 和 export * from './x' 无法安全剔除,因为它们可能被动态 import 或第三方库间接引用;而具名导出(export const x = 1)只要确认全项目无 import,就可放心删。
- 推荐流程:先用
eslint-plugin-unused-imports扫描,输出 JSON;再由 Babel 插件读取该 JSON,在ExportNamedDeclaration阶段过滤local.name - 必须区分
export { x as y }和export { x }:前者要查y是否被引用,后者查x - 若项目含 TypeScript,需确保 ESLint 配置启用
@typescript-eslint/parser,否则类型导出会被漏判
真正难的不是删代码,是判断「删了会不会坏」——环境变量求值要保守,跨文件引用要闭环验证,C 预处理器逻辑得和构建系统对齐。所有自动化剔除都该默认只报告、不执行,人工确认后再走清理流程。










