Chrome Devtools Coverage: how to save or capture code used code?
Google Chrome-DevtoolsGoogle Chrome-Devtools Problem Overview
The Coverage tool is good at finding used and unused code. However, there doesn't appear to be a way to save or export only the used code. Even hiding unused code would be helpful.
I'm attempting to reduce the amount of Bootstrap CSS in my application; the file is more than 7000 lines. The only way to get just the used code is to carefully scroll thru the file, look for green sections, then copy that code to a new file. It's time-consuming and unreliable.
Is there a different way? Chrome 60 does not seem to have added this functionality.
Google Chrome-Devtools Solutions
Solution 1 - Google Chrome-Devtools
You can do this with puppeteer
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage()
//Start sending raw DevTools Protocol commands are sent using `client.send()`
//First off enable the necessary "Domains" for the DevTools commands we care about
const client = await page.target().createCDPSession()
await client.send('Page.enable')
await client.send('DOM.enable')
await client.send('CSS.enable')
const inlineStylesheetIndex = new Set();
client.on('CSS.styleSheetAdded', stylesheet => {
const { header } = stylesheet
if (header.isInline || header.sourceURL === '' || header.sourceURL.startsWith('blob:')) {
inlineStylesheetIndex.add(header.styleSheetId);
}
});
//Start tracking CSS coverage
await client.send('CSS.startRuleUsageTracking')
await page.goto(`http://localhost`)
// const content = await page.content();
// console.log(content);
const rules = await client.send('CSS.takeCoverageDelta')
const usedRules = rules.coverage.filter(rule => {
return rule.used
})
const slices = [];
for (const usedRule of usedRules) {
// console.log(usedRule.styleSheetId)
if (inlineStylesheetIndex.has(usedRule.styleSheetId)) {
continue;
}
const stylesheet = await client.send('CSS.getStyleSheetText', {
styleSheetId: usedRule.styleSheetId
});
slices.push(stylesheet.text.slice(usedRule.startOffset, usedRule.endOffset));
}
console.log(slices.join(''));
await page.close();
await browser.close();
})();
Solution 2 - Google Chrome-Devtools
You can do this with Headless Chrome and puppeteer:
- In a new folder install puppeteer using npm (this will include Headless Chrome for you):
npm i puppeteer --save
- Put the following in a file called
csscoverage.js
and change localhost to point to your website.
:
const puppeteer = require('puppeteer');
const util = require('util');
const fs = require("fs");
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.coverage.startCSSCoverage();
await page.goto('https://localhost'); // Change this
const css_coverage = await page.coverage.stopCSSCoverage();
console.log(util.inspect(css_coverage, { showHidden: false, depth: null }));
await browser.close();
let final_css_bytes = '';
let total_bytes = 0;
let used_bytes = 0;
for (const entry of css_coverage) {
final_css_bytes = "";
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';
}
filename = entry.url.split('/').pop();
fs.writeFile('./'+filename, final_css_bytes, error => {
if (error) {
console.log('Error creating file:', error);
} else {
console.log('File saved');
}
});
}
})();
3. Run it with node csscoverage.js
This will output all the CSS you're using into the separate files they appear in (stopping you from merging external libraries into your own code, like the other answer does).
Solution 3 - Google Chrome-Devtools
I talked with the engineer who owns this feature. As of Chrome 64 there's still no way to export the results of a coverage analysis.
Star issue #717195 to help the team prioritize this feature request.
Solution 4 - Google Chrome-Devtools
I love this simple solution. It works with the Coverage tool in Chrome without any further installation. You can simply use the json file that the Coverage tool lets you export:
Solution 5 - Google Chrome-Devtools
- first of all you need to download and install "Google Chrome Dev".
- on Google chrome Dev go to Inspect element > Sources > Ctrl+shift+p
- Enter "coverage" and select "Start Instrumenting coverage and reload Page"
- Then use Export icon this will give you a json file.
you can also visit : Chrome DevTools: Export your raw Code Coverage Data
Solution 6 - Google Chrome-Devtools
I downloaded the latest version of canary and the export button was present.
I then used this PHP script to parse the json
file returned. (Where key '6' in the array is the resource to parse). I hope it helps someone!
$a = json_decode(file_get_contents('coverage3.json'));
$sText = $a[6]->text;
$sOut = "";
foreach ($a[6]->ranges as $iPos => $oR) {
$sOut .= substr($sText, $oR->start, ($oR->end-$oR->start))." \n";
}
echo '<style rel="stylesheet" type="text/css">' . $sOut . '</style>';
Solution 7 - Google Chrome-Devtools
Chrome canary 73 can do it. You will need Windows or Mac OS. There is an export function (Down arrow icon) next to the record and clear buttons. You'll get a json file and then you can use that to programmatically remove the unused lines.
Solution 8 - Google Chrome-Devtools
Here's a version that will keep media queries, based on Christopher Schiefer's:
$jsont = <<<'EOD'
{ "url":"test"}
EOD;
$a = json_decode($jsont);
$sText = $a->text;
preg_match_all('(@media(?>[^{]|(?0))*?{)', $sText, $mediaStartsTmp, PREG_OFFSET_CAPTURE);
preg_match_all("/\}(\s|\\n|\\t)*\}/", $sText, $mediaEndsTmp, PREG_OFFSET_CAPTURE);
$mediaStarts = empty($mediaStartsTmp) ? array() : $mediaStartsTmp[0];
$mediaEnds = empty($mediaEndsTmp) ? array() : $mediaEndsTmp[0];
$sOut = "";
$needMediaClose = false;
foreach ($a->ranges as $iPos => $oR) {
if ($needMediaClose) { //you are in a media query
//add closing bracket if you were in a media query and are past it
if ($oR->start > $mediaEnds[0][1]) {
$sOut .= "}\n";
array_splice($mediaEnds, 0, 1);
$needMediaClose = false;
}
}
if (!$needMediaClose) {
//remove any skipped media queries
while (!empty($mediaEnds) && $oR->start > $mediaEnds[0][1]) {
array_splice($mediaStarts, 0, 1);
array_splice($mediaEnds, 0, 1);
}
}
if (!empty($mediaStarts) && $oR->start > $mediaStarts[0][1]) {
$sOut .= "\n" . $mediaStarts[0][0] . "\n";
array_splice($mediaStarts, 0, 1);
$needMediaClose = true;
}
$sOut .= mb_substr($sText, $oR->start, ($oR->end-$oR->start))." \n";
}
if ($needMediaClose) { $sOut .= '}'; }
echo '<style rel="stylesheet" type="text/css">' . $sOut . '</style>';
Solution 9 - Google Chrome-Devtools
That's my python code to extract the code:
import json
code_coverage_filename = 'Coverage-20210613T173016.json'
specific_file_url = 'https://localhost:3000/b.css'
with open(code_coverage_filename) as f:
data = json.load(f)
for entry in data:
pass # print entry['url']
if entry['url'] == specific_file_url:
text = ""
for range in entry['ranges']:
range_start = range['start']
range_end = range['end']
text += entry['text'][int(range_start):int(range_end)]+"\n"
print text
However, there is a problem. Chrome debugger doesn't mark these kind of lines
@media (min-width: 768px) {
So it's a bit problematic to use this technique
Solution 10 - Google Chrome-Devtools
More practical version based on Atoms.
Improved to work without any files.
PHP Sandbox http://sandbox.onlinephpfunctions.com/
JSON Formater to be converted to 1line https://www.freeformatter.com/json-formatter.html#ad-output
Unmify it https://unminify.com/
$jsont = <<<'EOD'
{ "url":"test"}
EOD;
$a = json_decode($jsont);
$sText = $a->text;
$sOut = "";
foreach ($a->ranges as $iPos => $oR) {
$sOut .= substr($sText, $oR->start, ($oR->end-$oR->start))." \n";
}
echo '<style rel="stylesheet" type="text/css">' . $sOut . '</style>';