Measuring JavaScript Code Coverage and Reducing Dead Code in Front‑end Projects
By using Chrome DevTools and Istanbul/NYC to measure JavaScript coverage, developers can detect dead and low‑usage code, then convert such modules into dynamic imports via build plugins, enabling tree‑shaking and code‑splitting that reduces bundle size and speeds up first‑screen rendering.
"You can't manage what you can't measure." – Peter Drucker.
In front‑end development, JavaScript is the main language, and the size of the code directly impacts page load time. Measuring dead code and code coverage is therefore a crucial optimization step.
Dead code refers to code that will never be executed; it can be removed at compile time through tree shaking.
Redundant code differs from dead code: it is code that is not executed in a specific runtime scenario (e.g., a component never loaded on the first screen).
Code coverage is a metric that describes the proportion of source code executed during a test or runtime. Chrome DevTools provides a Coverage panel that highlights executed (blue) and unexecuted (red) bytes for JS and CSS resources.
For more detailed analysis, the Istanbul/NYC tool instruments JavaScript/TypeScript code and reports four dimensions: line coverage, function coverage, branch coverage, and statement coverage.
// a.js
const a = 1;
const b = 2; /* dead code */
export default a;
// index.js
import a from './a.js';
export default function() {
console.log(a);
}The instrumentation inserts a global __coverage__ object that records execution counts for functions ( f ) and statements ( s ).
// global __coverage__ record
const c = (window.__coverage__ = {
f: [0], // function execution counts
s: [0, 0, 0] // statement execution counts
});
// function definition counts as a statement
c.s[0]++;
function add(a, b) {
c.f[0]++; // function called
c.s[1]++; // statement executed
return a + b;
}
c.s[2]++; // export statement executed
module.exports = { add };After running the instrumented code, a JSON report is generated and can be visualized in the terminal or as HTML:
nyc report --reporter=text
nyc report --reporter=lcov --exclude-after-remap=falseBy analyzing coverage data, developers can identify components whose first‑screen usage is below a threshold (e.g., <30%). Those components can be converted to dynamic imports, enabling code splitting and reducing the main bundle size.
// dynamic import example
import { createElement, useState, useEffect } from 'rax';
export default (props) => {
const [AsyncMod, setAsyncMod] = useState(null);
useEffect(() => {
const load = async () => {
const Module = await import('./ThisIsBigMod'); // key
try { setAsyncMod(Module); } catch (e) { console.log(e); }
};
load();
}, []);
if (!AsyncMod || !AsyncMod.default) return null;
return
;
};In the Alibaba Tbox workflow, two build plugins are used:
@ali/build-plugin-coverage – generates coverage data during the build.
@ali/build-plugin-async-components – rewrites low‑usage components into async imports based on a generated app.json configuration.
// build.json snippet
"plugins": [
"@ali/build-plugin-coverage",
["@ali/build-plugin-async-components", { "active": true }]
]After building, the __coverage__ variable is injected, the coverage plugin creates a modsPath list of low‑usage components, and the async‑components plugin automatically splits those modules, resulting in a slimmer main bundle and faster first‑screen rendering.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.