Coverage面板直接标出当前运行中未执行的JS/CSS字节,需手动覆盖所有用户路径,注意SPA路由切换需重置统计、CSS伪类需真实触发、polyfill误报属正常,过滤node_modules/dist,压缩与source map影响准确性,导出CSV不含行号不可直接删代码。

Coverage 面板能直接标出哪些 JS/CSS 文件没被执行
Chrome DevTools 的 Coverage 面板(Cmd+Shift+P → 输入 show coverage)不是静态分析工具,它只记录当前页面加载和交互过程中实际执行/解析的字节。也就是说:它不猜、不推断,只反馈「这次运行」里哪些代码行被 V8 解析过、哪些 CSS 规则被计算过。所以结果高度依赖你是否完整触发了所有功能路径——比如没点开弹窗,弹窗里的 JS 就会被标记为未使用。
常见错误现象:Coverage 显示某 .js 文件 95% 未覆盖,但你确认它被 import 了——这通常是因为该模块只是被引入,但内部函数从未被调用;或者用了动态 import(),而你没触发对应路由或事件。
- 必须手动操作页面,覆盖所有用户路径(登录/列表页/详情页/编辑态/错误态等)
- 单页应用(SPA)需注意:路由切换不会自动刷新 Coverage 统计,要点击
Reload coverage按钮重置后再切页 - CSS 覆盖率看的是「浏览器是否将该规则应用于任何元素」,而非「是否出现在 DOM 中」;伪类(如
:hover)、媒体查询(@media)需真实触发才会计入
如何避免把 polyfill 或框架代码误判为“死代码”
像 core-js、regenerator-runtime 或 Vue/React 的 runtime 模块,往往在首屏就加载,但大部分逻辑只在特定条件下执行(如 Promise.finally() 在旧浏览器中才启用 polyfill)。Coverage 会把这些模块标为大量未覆盖——但这不是 bug,是设计使然。
使用场景:你真正想清理的是业务代码中的废弃函数、注释掉的组件、老版本 API 封装层,而不是基础兼容性代码。
- 过滤掉
node_modules/和dist/目录下的文件:在 Coverage 表格顶部搜索框输入-node_modules -dist - 对疑似 polyfill 的文件,右键 →
Block URL,刷新页面看是否报错;若无异常,再结合构建产物(如webpack --display-modules)交叉验证 - 注意
eval和内联 script:Coverage 对它们支持有限,可能显示为(index)或无法定位行号,这类需单独用source-map-explorer分析
覆盖率数字不准?检查是否启用了代码压缩或 source map
如果项目用了 Terser 压缩(默认开启),Coverage 会基于压缩后代码统计,但你看到的 source map 映射是原始文件——导致高亮错位、行覆盖率看起来“跳变”。这不是面板故障,而是映射延迟或缺失造成的视觉误差。
参数差异:devtool: 'source-map' 比 'cheap-module-source-map' 更准,但构建更慢;生产环境若关了 source map,Coverage 就只能显示压缩后文件,基本没法人工判断。
- 开发时确保
devtool设为'source-map'或'inline-source-map' - 禁用 Terser 的
mangle(变量名混淆)选项,否则函数名变成a()、b(),无法识别业务语义 - Webpack 5+ 用户注意:若用了
experiments.outputModule: true,Coverage 可能无法识别 ESM 动态导入,建议暂时关闭测试
导出数据后怎么安全删除“未使用”的代码
Coverage 提供的 CSV 导出(点击右上角 ••• → Export)只含文件路径、总字节数、已使用字节数,不含具体行号。这意味着你不能靠它直接删函数——它告诉你“A.js 用了 12%”,但不告诉你哪 12% 是什么。
性能影响:盲目删除被 Coverage 标红的文件,可能导致运行时 ReferenceError 或 TypeError,尤其当代码有副作用(如全局变量注入、原型扩展、addEventListener 注册)时。
- 优先从「独立工具模块」下手:比如
utils/dateHelper.js全红,且 grep 全项目没搜到dateHelper调用,可删 - 对组件文件,先查
git log -S 'export default.*MyComponent'看最近是否被移除引用 - 用
eslint-plugin-unused-imports或ts-prune(TS 项目)做二次验证,它们能发现未被 import 的导出,Coverage 发现不了这个维度
真正容易被忽略的是动态 require、字符串拼接的路径、webpack 的 require.context——Coverage 完全看不到这些加载的模块,但它们可能正被用着。别只盯着红色数字做决定。

















