【问题标题】:Chrome Devtools Coverage: how to save or capture code used code?Chrome Devtools Coverage:如何保存或捕获代码使用的代码?
【发布时间】:2017-12-19 18:48:17
【问题描述】:

Coverage 工具擅长查找已使用和未使用的代码。但是,似乎没有办法只保存或导出使用过的代码。即使隐藏未使用的代码也会有所帮助。

我正在尝试减少我的应用程序中的 Bootstrap CSS 数量;该文件超过7000行。获取使用过的代码的唯一方法是仔细滚动文件,寻找绿色部分,然后将该代码复制到新文件中。这既费时又不可靠。

有不同的方法吗? Chrome 60 似乎没有添加这个功能。

【问题讨论】:

标签: google-chrome-devtools


【解决方案1】:

我与拥有此功能的工程师进行了交谈。从 Chrome 64 开始,仍然无法导出覆盖率分析的结果。

Star issue #717195 以帮助团队优先考虑此功能请求。

【讨论】:

    【解决方案2】:

    你可以用 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();
    })();
    

    【讨论】:

    • 您使用哪个版本的node 运行您的解决方案?
    • @dryleaf nodejs 8.6
    • 谢谢。看到 puppeteer 文档后,我能够在 8.0.0 上运行。这是一个不错的 CSS hack。 +1 给出了很好的答案。我将如何进行 JS hack?
    • 我想我们也可以filter 获取未使用的规则,将它们分开并加载未使用的规则作为延迟样式。也许它们被用于其他内部页面。
    • 如果我只想专注于 bootstrap.css 而让所有其他文件保持原样怎么办?我需要如何更改上面的编码?
    【解决方案3】:

    Chrome canary 73 可以做到。您将需要 Windows 或 Mac OS。记录和清除按钮旁边有一个导出功能(向下箭头图标)。您将获得一个 json 文件,然后您可以使用它以编程方式删除未使用的行。

    【讨论】:

    • 任何从 json 中提取的脚本?
    【解决方案4】:
    1. 首先您需要下载并安装“Google Chrome Dev”。
    2. 在 Google chrome Dev 上转到 Inspect element > Sources > Ctrl+shift+p
    3. 输入“coverage”并选择“Start Instrumenting coverage and reload Page”
    4. 然后使用导出图标 这会给你一个 json 文件。

    您也可以访问:Chrome DevTools: Export your raw Code Coverage Data

    【讨论】:

    • 如果您只需要从 json 中获取文件的覆盖文本,您可以使用以下 js 代码:var file = json[N]; var coverage_file = ""; file.ranges.forEach(range => coverage_file += file.text.substring(range.start, range.end));。其中N是json中文件的个数
    • “下载并安装“Google Chrome Dev”是什么意思?F12不够用?
    • 谷歌浏览器开发!=谷歌浏览器。我认为下载覆盖文本仅在 Google Chrome Dev 上可用。 Google chrome Dev 是为开发人员构建的 chrome 版本。
    • 不确定它是何时添加的,但在我输入此选项时,此选项位于 Chrome 的最新 (mac) 版本中 - 版本 89.0.4389.90(官方构建)(x86_64)
    【解决方案5】:

    我下载了最新版本的 canary,并且出现了导出按钮。

    然后我使用这个 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>';
    

    【讨论】:

    • 非常感谢!但是你有一个小错误(或者可能当时生成的coverage.json不同),substr的第三个参数应该是长度,但是在coverage.json中出现了结束字符,所以它应该是:$ sOut .= substr($sText, $oR->start, ($oR->end-$oR->start));
    • 另外,您可能希望使用 mb_substr() 而不是 substr() 来处理多字节字符(有时用于 CSS 中的图标)。
    【解决方案6】:

    您可以使用 Headless Chrome 和 puppeteer

    1. 在一个新文件夹中使用 npm 安装 puppeteer(这将包括 Headless Chrome):

    npm i puppeteer --save

    1. 将以下内容放入名为 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');
        }
      });
    }
    })();
    
    1. 使用node csscoverage.js 运行它

    这会将您正在使用的所有 CSS 输出到它们出现的单独文件中(阻止您将外部库合并到您自己的代码中,就像其他答案一样)。

    【讨论】:

    • 添加等待页面.setDefaultNavigationTimeout(0);避免在运行重负载或加载较难的页面时超时
    【解决方案7】:

    基于 Atoms 的更实用的版本。

    改进后无需任何文件即可工作。

    PHP 沙盒http://sandbox.onlinephpfunctions.com/

    JSON Formater 转换为 1line https://www.freeformatter.com/json-formatter.html#ad-output

    取消它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>';
    

    【讨论】:

      【解决方案8】:

      这是一个保留媒体查询的版本,基于 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>';
      

      【讨论】:

        【解决方案9】:

        我喜欢这个简单的解决方案。它可以与 Chrome 中的 Coverage 工具一起使用,无需进一步安装。您可以简单地使用 Coverage 工具允许您导出的 json 文件:

        https://nachovz.github.io/devtools-coverage-css-generator/

        【讨论】:

        • 它不需要像@media (min-width: 768px) 这样的css行,所以风险很大
        【解决方案10】:

        这是我提取代码的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) {
        

        所以使用这种技术有点问题

        【讨论】:

          猜你喜欢
          • 2015-11-13
          • 2022-01-06
          • 2021-10-11
          • 1970-01-01
          • 1970-01-01
          • 2013-11-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多