Remove unused CSS / JavaScript code from your project
Older Article
This article was published 7 years ago. Some information may be outdated or no longer applicable.
We’re going to look at a newer addition to Chrome Developer Tools and a Node.js library that lets developers work with DevTools programmatically.
Code coverage
When most people hear “code coverage,” they think of a percentage showing how much of the codebase automated tests touch. That’s a perfectly valid definition.
But Chrome’s DevTools mean something different by it. The “coverage” tab (available in Chrome 59+) reveals CSS and JavaScript code that your application never actually uses. That means you can strip out unused bytes and make your site faster.
Enabling the coverage tab
You’ll need Chrome 59 or later installed to see this tab.
Open the “Command Menu” in Chrome by pressing Cmd+Shift+P on Mac or Ctrl+Shift+P on Windows and Linux. Type Show Coverage and you’re in.
You can also find the coverage tab by clicking the three horizontal dots under Sources, then selecting More tools > Coverage. The results show exactly how much of your CSS and JavaScript is actually being used:

It can also highlight the specific lines sitting in your codebase but doing nothing:

Some CSS rules only kick in after user actions like hover or click. Keep that in mind. The same goes for JavaScript.
At the time of writing, Chrome doesn’t have a built-in way to export only the code being used. But there’s a solution.
Puppeteer
Puppeteer is a Node.js API library that controls Chrome/Chromium over the DevTools protocol. Whatever you can do with DevTools in the browser, you can now do programmatically through Puppeteer. That includes:
- Taking screenshots or exporting pages to PDF
- Automating UI testing
- Generating pre-rendered content (Server-Side Rendering)
- Testing Chrome extensions
- And much more
Can we run code coverage checks with it? Absolutely.
Running coverage check via Puppeteer
Install Puppeteer first: npm i puppeteer. Then create a small JavaScript app to run the coverage check:
const puppeteer = require('puppeteer');
const util = require('util');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.coverage.startCSSCoverage();
await page.goto('http://localhost:8080');
const css_coverage = await page.coverage.stopCSSCoverage();
console.log(util.inspect(css_coverage, { showHidden: false, depth: null }));
await browser.close();
})();
This returns the following:
[ { url: 'http://localhost:8080/site.css',
ranges: [ { start: 0, end: 28 }, { start: 55, end: 86 } ],
text:
'.important {\n color: red;\n}\n.test {\n color: green;\n}\n.more {\n visibility: hidden;\n}' } ]
The ranges property is the key piece. It tells us which bytes the application actually uses. Bytes 0 to 28 and 55 to 86 are in play, which means bytes 29 through 54 are dead weight and should be removed.
Using Puppeteer together with Node.js’s built-in fs module, we can write a script that strips out unused code and saves only what’s needed.
Let’s update our code to iterate through the document (using the text property), then save the result to a new file containing only the CSS that’s actually doing work:
let final_css_bytes = '';
let total_bytes = 0;
let used_bytes = 0;
for (const entry of css_coverage) {
total_bytes += entry.text.length;
for (const range of entry.ranges) {
used_bytes += range.end - range.start - 1;
final_css_bytes += entry.text.slice(range.start, range.end) + '\n';
}
}
fs.writeFile('./final_css.css', final_css_bytes, (error) => {
if (error) {
console.log('Error creating file:', error);
} else {
console.log('File saved');
}
});
Run all your tests again after this. Removing code has benefits, but it can also break things. Make sure your site still works before pushing to production.
You can do the same thing for JavaScript files. And you can fold this step into your build process: strip comments, remove unused code via Puppeteer, then minify.
Conclusion
We looked at Chrome DevTools’ code coverage feature and how to automate those same checks with Puppeteer. For production applications, always make sure you’re only shipping the CSS and JavaScript that’s actually needed. Every unused byte slows things down.