Last active
          October 18, 2025 09:48 
        
      - 
            
      
        
      
    Star
      
          
          (147)
      
  
You must be signed in to star a gist 
- 
              
      
        
      
    Fork
      
          
          (19)
      
  
You must be signed in to fork a gist 
- 
      
- 
        Save ebidel/2e9f78f8bd3f025653aba711a4689694 to your computer and use it in GitHub Desktop. 
Revisions
- 
        ebidel revised this gist Feb 28, 2018 . 1 changed file with 1 addition and 205 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,205 +1 @@ Moved to https://github.com/ebidel/puppeteer-examples 
- 
        ebidel revised this gist Feb 26, 2018 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1 @@ <img width="741" alt="screen shot 2018-02-26 at 10 20 41 am" src="https://user-images.githubusercontent.com/238208/36687690-2de2bbaa-1adf-11e8-912b-e21cda0160ce.png"> 
- 
        ebidel revised this gist Feb 26, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,3 @@ <img width="741" alt="screen shot 2018-02-26 at 10 20 41 am" src="https://user-images.githubusercontent.com/238208/36687690-2de2bbaa-1adf-11e8-912b-e21cda0160ce.png">  
- 
        ebidel revised this gist Feb 26, 2018 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +1,3 @@ <img width="741" alt="screen shot 2018-02-26 at 10 20 41 am" src="https://user-images.githubusercontent.com/238208/36687690-2de2bbaa-1adf-11e8-912b-e21cda0160ce.png">  
- 
        ebidel created this gist Feb 26, 2018 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,205 @@ /** * @author ebidel@ (Eric Bidelman) * License Apache-2.0 * * Shows how to use Puppeeteer's code coverage API to measure CSS/JS coverage across * different points of time during loading. Great for determining if a lazy loading strategy * is paying off or working correctly. * * Install: * npm i puppeteer chalk cli-table * Run: * URL=https://example.com node coverage.js */ const puppeteer = require('puppeteer'); const chalk = require('chalk'); const Table = require('cli-table'); const URL = process.env.URL || 'https://www.chromestatus.com/features'; const EVENTS = [ 'domcontentloaded', 'load', 'networkidle0', ]; function formatBytesToKB(bytes) { if (bytes > 1024) { const formattedNum = new Intl.NumberFormat('en-US', {maximumFractionDigits: 1}).format(bytes / 1024); return `${formattedNum}KB`; } return `${bytes} bytes`; } class UsageFormatter { constructor(stats) { this.stats = stats; } static eventLabel(event) { return chalk.magenta(event); } summary(used = this.stats.usedBytes, total = this.stats.totalBytes) { const percent = Math.round((used / total) * 100); return `${formatBytesToKB(used)}/${formatBytesToKB(total)} (${percent}%)`; } shortSummary(used, total = this.stats.totalBytes) { const percent = Math.round((used / total) * 100); return used ? `${formatBytesToKB(used)} (${percent}%)` : 0; } /** * Constructors a bar chart for the % usage of each value. * @param {!{jsUsed: number, cssUsed: number, totalBytes: number}=} stats Usage stats. * @return {string} */ barGraph(stats = this.stats) { const maxBarWidth = 30; const jsSegment = ' '.repeat((stats.jsUsed / stats.totalBytes) * maxBarWidth); const cssSegment = ' '.repeat((stats.cssUsed / stats.totalBytes) * maxBarWidth); const unusedSegment = ' '.repeat(maxBarWidth - jsSegment.length - cssSegment.length); return chalk.bgRedBright(jsSegment) + chalk.bgBlueBright(cssSegment) + chalk.bgBlackBright(unusedSegment); } } const stats = new Map(); /** * @param {!Object} coverage * @param {string} type Either "css" or "js" to indicate which type of coverage. * @param {string} eventType The page event when the coverage was captured. */ function addUsage(coverage, type, eventType) { for (const entry of coverage) { if (!stats.has(entry.url)) { stats.set(entry.url, []); } const urlStats = stats.get(entry.url); let eventStats = urlStats.find(item => item.eventType === eventType); if (!eventStats) { eventStats = { cssUsed: 0, jsUsed: 0, get usedBytes() { return this.cssUsed + this.jsUsed; }, totalBytes: 0, get percentUsed() { return this.totalBytes ? Math.round(this.usedBytes / this.totalBytes * 100) : 0; }, eventType, url: entry.url, }; urlStats.push(eventStats); } eventStats.totalBytes += entry.text.length; for (const range of entry.ranges) { eventStats[`${type}Used`] += range.end - range.start - 1; } } } async function collectCoverage() { const browser = await puppeteer.launch({headless: true}); // Do separate load for each event. See // https://github.com/GoogleChrome/puppeteer/issues/1887 const collectPromises = EVENTS.map(async event => { console.log(`Collecting coverage @ ${UsageFormatter.eventLabel(event)}...`); const page = await browser.newPage(); await Promise.all([ page.coverage.startJSCoverage(), page.coverage.startCSSCoverage() ]); await page.goto(URL, {waitUntil: event}); const [jsCoverage, cssCoverage] = await Promise.all([ page.coverage.stopJSCoverage(), page.coverage.stopCSSCoverage() ]); addUsage(cssCoverage, 'css', event); addUsage(jsCoverage, 'js', event); await page.close(); }); await Promise.all(collectPromises); return browser.close(); } (async() => { await collectCoverage(); for (const [url, vals] of stats) { console.log('\n' + chalk.cyan(url)); const table = new Table({ head: [ 'Event', `${chalk.bgRedBright(' JS ')} ${chalk.bgBlueBright(' CSS ')} % used`, 'JS used', 'CSS used', 'Total bytes used' ], style: {head: ['white'], border: ['grey']} }); EVENTS.forEach(event => { const usageForEvent = vals.filter(val => val.eventType === event); if (usageForEvent.length) { for (const stats of usageForEvent) { const formatter = new UsageFormatter(stats); table.push([ UsageFormatter.eventLabel(stats.eventType), formatter.barGraph(), formatter.shortSummary(stats.jsUsed), // !== 0 ? `${formatBytesToKB(stats.jsUsed)}KB` : 0, formatter.shortSummary(stats.cssUsed), formatter.summary() ]); } } else { table.push([UsageFormatter.eventLabel(event), 'no usage found', '-', '-', '-']); } }); console.log(table.toString()); } // Print total usage for each event. // console.log('\n'); EVENTS.forEach(event => { let totalBytes = 0; let totalUsedBytes = 0; const metrics = Array.from(stats.values()); const statsForEvent = metrics.map(eventStatsForUrl => { const statsForEvent = eventStatsForUrl.filter(stat => stat.eventType === event)[0]; // TODO: need to sum max totalBytes. Currently ignores stats if event didn't // have an entry. IOW, all total numerators should be max totalBytes seen for that event. if (statsForEvent) { totalBytes += statsForEvent.totalBytes; totalUsedBytes += statsForEvent.usedBytes; } }); const percentUsed = Math.round(totalUsedBytes / totalBytes * 100); console.log(`Total used @ ${chalk.magenta(event)}: ${formatBytesToKB(totalUsedBytes)}/${formatBytesToKB(totalBytes)} (${percentUsed}%)`); }); })(); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ <img width="741" alt="screen shot 2018-02-26 at 10 20 41 am" src="https://user-images.githubusercontent.com/238208/36687690-2de2bbaa-1adf-11e8-912b-e21cda0160ce.png">