Coverage 工具擅长查找已使用和未使用的代码。但是,似乎没有办法只保存或导出使用过的代码。即使隐藏未使用的代码也会有所帮助。
我正在尝试减少应用程序中 Bootstrap CSS 的数量;该文件超过7000行。获取使用过的代码的唯一方法是仔细滚动文件,寻找绿色部分,然后将该代码复制到一个新文件中。这是耗时且不可靠的。
有不同的方法吗? Chrome 60 似乎没有添加这个功能。
This feature is experimental and is not yet available in Firefox.
在 Firefox ESR 45.8.0 中,可以通过按 SHIFT F2
打开 GCLI Graphical Command Line Interpreter Christian Heilmann 上传 video CSSCoverage tool in Firefox Devtools
你可以用 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();
})();
您可以使用 Headless Chrome 和 puppeteer 执行此操作:
在一个新文件夹中使用 npm 安装 puppeteer(这将包括 Headless Chrome):
npm i puppeteer --save
将以下内容放入名为 csscoverage.js 的文件中,并将 localhost 更改为指向您的网站。
:
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');
}
});
}
})();
使用节点 csscoverage.js 运行它
这会将您正在使用的所有 CSS 输出到它们出现的单独文件中(阻止您将外部库合并到您自己的代码中,就像其他答案一样)。
我喜欢这个简单的解决方案。它可以与 Chrome 中的 Coverage 工具一起使用,无需任何进一步的安装。您可以简单地使用 Coverage 工具允许您导出的 json 文件:
https://nachovz.github.io/devtools-coverage-css-generator/
但请注意我的答案下方的评论!!!他是对的,这是有风险的。我仍然希望/等待更新。
首先,您需要下载并安装“Google Chrome Dev”。在 Google chrome Dev 上转到 Inspect element > Sources > Ctrl+shift+p 输入“coverage”并选择“Start Instrumenting coverage and reload Page” 然后使用 Export 图标,这将为您提供一个 json 文件。
您还可以访问:Chrome DevTools: Export your raw Code Coverage Data
var file = json[N]; var coverage_file = ""; file.ranges.forEach(range => coverage_file += file.text.substring(range.start, range.end));
。其中 N
是 json 中的文件数
我下载了最新版本的金丝雀,并且出现了导出按钮。
然后我使用这个 PHP 脚本来解析返回的 json
文件。 (其中数组中的键 '6' 是要解析的资源)。我希望它可以帮助某人!
$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>';
Chrome canary 73 可以做到。您将需要 Windows 或 Mac OS。记录和清除按钮旁边有一个导出功能(向下箭头图标)。您将获得一个 json 文件,然后您可以使用它以编程方式删除未使用的行。
这是一个保留媒体查询的版本,基于 Christopher Schiefer 的:
$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>';
这是我提取代码的python代码:
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
但是,有一个问题。 Chrome 调试器不会标记这些行
@media (min-width: 768px) {
所以使用这种技术有点问题
基于 Atoms 的更实用的版本。
改进为无需任何文件即可工作。
PHP 沙盒 http://sandbox.onlinephpfunctions.com/
要转换为 1 行 https://www.freeformatter.com/json-formatter.html#ad-output 的 JSON 格式化程序
$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>';
node
来运行您的解决方案?filter
并获取未使用的规则,将它们分开并将未使用的规则加载为延迟样式。也许它们被用于其他内部页面。