Use PerfCascade to show waterfall on page summary and individual runs from collected HAR (#997)

This pull request adds support for a waterfall view on the page summary(defaults: off) and and each individual run HTML output using PerfCascade. (#876) A CLI option is available to turn on the waterfall view on the page summary using --html.showWaterfallSummary
This commit is contained in:
Jonathan Lee 2016-06-11 16:24:20 -04:00 committed by GitHub
parent f0cc234186
commit b8685411fa
12 changed files with 657 additions and 2 deletions

View File

@ -147,6 +147,18 @@ module.exports = {
})
.tap((results) => {
results.browserScripts.forEach((run, runIndex) => {
// take the HAR from this run and add it to the
// run data
const runHar = api.pickAPage(results.har, runIndex);
run.har = runHar;
// if we have firstPaint, add it to the HAR(s)
if (run.timings.firstPaint) {
run.har.log.pages[0].pageTimings._firstPaint = run.timings.firstPaint;
results.har.log.pages[runIndex].pageTimings._firstPaint = run.timings.firstPaint;
}
// Kind of ugly way to add visualMetrics to a run
// it's outside of browserScripts today
// we could instead pass browsertime.visualMetrics maybe

View File

@ -957,3 +957,433 @@ ul.menu {
.hidden-small {
display: inline; }
#page-selector {
display: none;
clear: both;
margin: 1em 0; }
* {
box-sizing: border-box; }
#output {
margin: 2em 0;
font-size: 12px;
line-height: 1em; }
.water-fall-holder {
fill: #ccc; }
svg.water-fall-chart {
width: 100%;
overflow: visible; }
.water-fall-chart .left-fixed-holder {
overflow: visible; }
.water-fall-chart .marker-holder {
width: 100%; }
.water-fall-chart .line-holder {
stroke-width: 1;
stroke: #ccc;
stroke-opacity: 0.5; }
.water-fall-chart .line-holder.active {
stroke: #69009e;
stroke-width: 2;
stroke-opacity: 1; }
.water-fall-chart .type-onload .line-holder {
stroke: #c0c0ff; }
.water-fall-chart .type-oncontentload .line-holder {
stroke: #d888df; }
.water-fall-chart .labels {
width: 100%; }
.water-fall-chart .labels .inner-label {
pointer-events: none; }
.water-fall-chart .time-block.active {
opacity: 0.8; }
.water-fall-chart .line-end,
.water-fall-chart .line-start {
display: none;
stroke-width: 1;
stroke-opacity: 0.5;
stroke: #000; }
.water-fall-chart .line-end.active,
.water-fall-chart .line-start.active {
display: block; }
.water-fall-chart .mark-holder text {
-webkit-writing-mode: tb;
writing-mode: vertical-lr;
writing-mode: tb; }
.left-fixed-holder .label-full-bg {
fill: #fff;
opacity: 0.9; }
.time-scale line {
stroke: #0cc;
stroke-width: 1; }
.time-scale text {
font-weight: bold; }
.row-item .even {
fill: #ccc;
opacity: 0.05; }
.row-item .odd {
fill: #000;
opacity: 0.05; }
.row-item:hover .odd,
.row-item:hover .even {
fill: #000;
opacity: 0.1; }
.row-item .rect-holder text {
fill: #aaa; }
.row-item.status5xx .even {
fill: #f66; }
.row-item.status5xx .odd {
fill: #f00; }
.row-item.status4xx .even {
fill: #c33; }
.row-item.status4xx .odd {
fill: #c00; }
.row-item.status3xx .even {
fill: #ff6; }
.row-item.status3xx .odd {
fill: #ff0; }
.row-item.status5xx .even,
.row-item.status5xx .odd,
.row-item.status4xx .even,
.row-item.status4xx .odd,
.row-item.status3xx .even,
.row-item.status3xx .odd {
opacity: 0.3; }
.row-item.status5xx:hover .even,
.row-item.status5xx:hover .odd,
.row-item.status4xx:hover .even,
.row-item.status4xx:hover .odd,
.row-item.status3xx:hover .even,
.row-item.status3xx:hover .odd {
opacity: 0.5; }
.lables {
overflow: hidden; }
/*block colours*/
.block-css {
fill: #a6d18f; }
.block-iframe,
.block-html,
.block-svg,
.block-internal {
fill: #82a8de; }
.block-img,
.block-image {
fill: #b394cf; }
.block-script,
.block-javascript,
.block-js {
fill: #e0b483; }
.block-link {
fill: #89afe6; }
.block-swf,
.block-flash {
fill: #42aab1; }
.block-font {
fill: #e15d4e; }
.block-xmlhttprequest,
.block-ajax {
fill: #f00; }
/*remove?*/
.block-plain,
.block-other {
fill: #b3b3b3; }
.block-total {
fill: #ccc; }
.block-unload {
fill: #909; }
.block-redirect {
fill: #ffff60; }
.block-appcache {
fill: #1f831f; }
.block-dns {
fill: #1f7c83; }
.block-tcp {
fill: #e58226; }
.block-ttfb {
fill: #1fe11f; }
.block-response {
fill: #1977dd; }
.block-dom {
fill: #9cc; }
.block-dom-content-loaded {
fill: #d888df; }
.block-onload {
fill: #c0c0ff; }
.block-ssl {
fill: #c141cd; }
.block-ms-first-paint-event {
fill: #8fbc83; }
.block-dom-interactive-event {
fill: #d888df; }
.block-network-server {
fill: #8cd18c; }
.block-custom-measure {
fill: #f00; }
.block-navigation-api-total {
fill: #ccc; }
.block-blocking,
.block-blocked {
fill: #cdcdcd; }
.block-undefined {
fill: #0f0; }
.block-blocked {
fill: #ccc; }
/*TODO: define colour*/
.block-dns {
fill: #1f7c83; }
.block-connect {
fill: #e58226; }
.block-ssl {
fill: #c141cd; }
.block-send {
fill: #1fe110; }
/*TODO: define colour*/
.block-wait {
fill: #1fe11f; }
/*TODO: define colour*/
.block-receive {
fill: #1977dd; }
/* Info overlay SVG - wrapper */
.info-overlay {
fill: #fff;
stroke: #cdcdcd; }
.info-overlay-close-btn {
fill: rgba(205, 205, 205, 0.5);
transform: translate(-23px, -23px);
cursor: pointer; }
.info-overlay-close-btn text {
fill: #111;
pointer-events: none; }
.info-overlay-close-btn:focus {
border: solid 1px #36c; }
/* Info overlay HTML - types */
.type-css {
background: #406B29; }
/*a6d18f - 40%*/
.type-iframe,
.type-html,
.type-svg,
.type-internal {
background: #1C4278; }
/*82a8de - 40%*/
.type-img,
.type-image {
background: #4D2E69; }
/*b394cf - 40%*/
.type-script,
.type-javascript,
.type-js {
background: #7A4E1D; }
/*e0b483 - 40%*/
.type-link {
background: #89afe6; }
/*89afe6 - 40%*/
.type-swf,
.type-flash {
background: #234980; }
/*#42aab1 - 40%*/
.type-font {
background: #AE2A1B; }
/*#e15d4e - 40%*/
.type-xmlhttprequest,
.type-ajax {
background: #CC0000; }
/* f00 40%*/
.type-plain,
.type-other {
background: #808080; }
/*#b3b3b3 - 40%*/
/* Info overlay HTML - base */
.info-overlay-holder * {
padding: 0;
margin: 0;
font-size: 12px; }
.info-overlay-holder body {
position: relative;
height: 450px;
clear: both;
padding: 0;
margin: 0;
width: 100%;
background: #fff;
color: #666; }
.info-overlay-holder body .wrapper {
height: 450px;
width: 100%;
overflow: scroll; }
/* Info overlay HTML - header */
.info-overlay-holder header {
color: #fff;
box-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.25); }
.info-overlay-holder .requestID {
font-weight: bold; }
.info-overlay-holder h3 {
font-size: 1.1em;
padding: 1em;
margin: 0;
font-weight: normal; }
.info-overlay-holder h3 strong {
font-size: 1.1em; }
.info-overlay-holder .tab-nav ul {
margin: 0;
padding: 0; }
.info-overlay-holder .tab-nav li {
margin: 0;
padding: 0;
display: inline-block; }
.info-overlay-holder button {
background: transparent;
outline: 0;
border: 0;
border-bottom: solid 2px transparent;
padding: 0.5em 1em;
margin: 0 0.25em; }
.info-overlay-holder li:first-child button {
margin-left: 1em; }
.info-overlay-holder button:focus, .info-overlay-holder button:hover {
border-color: rgba(255, 255, 255, 0.6); }
.info-overlay-holder button.active {
border-color: #fff;
cursor: default; }
/* Info overlay HTML - content */
.info-overlay-holder dt {
float: left;
clear: both;
margin-top: 0.5em;
width: 25%;
text-align: right;
font-weight: bold; }
.info-overlay-holder dd {
float: left;
width: 73%;
margin: 0.5em 0 0 2%;
padding: 0 0 0.5em 0; }
.info-overlay-holder dt:after {
content: ":"; }
.info-overlay-holder pre {
font-size: 11px;
line-height: 23px;
border-radius: 0;
background: #f6f3f3; }
.info-overlay-holder .tab {
float: left;
width: 100%;
height: 350px;
padding: 12px 12px 24px; }
.info-overlay-holder .tab h2 {
font-size: 1.2em;
margin: 0.5em 0 0;
padding: 0.5em 0 0.5em 1em;
clear: both;
border-top: solid 1px #efefef; }
.info-overlay-holder .tab pre {
overflow-y: hidden; }
.info-overlay-holder .tab .preview {
width: auto;
max-width: 100%;
max-height: 500px;
border: solid 1px #666; }
.info-overlay-holder .tab dl:after {
content: "";
display: table;
clear: both; }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -111,6 +111,7 @@ class HTMLBuilder {
menu: 'pages',
pageTitle: name + ' ' + url,
pageDescription: '',
showWaterfallSummary: locals.options.html.showWaterfallSummary,
headers: this.summaryPages,
h: helpers
}, locals);

View File

@ -0,0 +1,167 @@
#page-selector {display: none; clear: both; margin: 1em 0;}
* {box-sizing: border-box;}
#output {margin: 2em 0; font-size: 12px; line-height: 1em;}
.water-fall-holder {fill:#ccc;}
svg.water-fall-chart {width:100%; overflow: visible;}
.water-fall-chart .left-fixed-holder {overflow: visible;}
.water-fall-chart .marker-holder {width:100%;}
.water-fall-chart .line-holder {stroke-width:1; stroke: #ccc; stroke-opacity:0.5;}
.water-fall-chart .line-holder.active {stroke: #69009e; stroke-width:2; stroke-opacity:1;}
.water-fall-chart .type-onload .line-holder {stroke: #c0c0ff;}
.water-fall-chart .type-oncontentload .line-holder {stroke: #d888df;}
.water-fall-chart .labels {width:100%;}
.water-fall-chart .labels .inner-label {pointer-events: none;}
.water-fall-chart .time-block.active {opacity: 0.8;}
.water-fall-chart .line-end,
.water-fall-chart .line-start {display: none; stroke-width:1; stroke-opacity:0.5; stroke: #000;}
.water-fall-chart .line-end.active,
.water-fall-chart .line-start.active {display: block;}
.water-fall-chart .mark-holder text {-webkit-writing-mode: tb; writing-mode:vertical-lr; writing-mode: tb;}
.left-fixed-holder .label-full-bg {fill: #fff; opacity: 0.9}
.time-scale line {stroke:#0cc; stroke-width:1;}
.time-scale text {font-weight:bold;}
.row-item .even {fill: #ccc; opacity: 0.05;}
.row-item .odd {fill: #000; opacity: 0.05;}
.row-item:hover .odd,
.row-item:hover .even {fill: #000; opacity: 0.1}
.row-item .rect-holder text {fill: #aaa}
.row-item.status5xx .even {fill: #f66;}
.row-item.status5xx .odd {fill: #f00;}
.row-item.status4xx .even{fill: #c33;}
.row-item.status4xx .odd {fill: #c00;}
.row-item.status3xx .even {fill: #ff6;}
.row-item.status3xx .odd {fill: #ff0;}
.row-item.status5xx .even,
.row-item.status5xx .odd,
.row-item.status4xx .even,
.row-item.status4xx .odd,
.row-item.status3xx .even,
.row-item.status3xx .odd {opacity: 0.3}
.row-item.status5xx:hover .even,
.row-item.status5xx:hover .odd,
.row-item.status4xx:hover .even,
.row-item.status4xx:hover .odd,
.row-item.status3xx:hover .even,
.row-item.status3xx:hover .odd {opacity: 0.5}
.lables { overflow: hidden;}
/*block colours*/
.block-css {fill: #a6d18f;}
.block-iframe,
.block-html,
.block-svg,
.block-internal {fill: #82a8de;}
.block-img,
.block-image {fill: #b394cf;}
.block-script,
.block-javascript,
.block-js {fill: #e0b483;}
.block-link {fill: #89afe6;}
.block-swf,
.block-flash {fill: #42aab1;}
.block-font {fill: #e15d4e;}
.block-xmlhttprequest,
.block-ajax {fill: #f00;} /*remove?*/
.block-plain,
.block-other {fill: #b3b3b3;}
.block-total {fill: #ccc;}
.block-unload {fill: #909;}
.block-redirect {fill: #ffff60;}
.block-appcache {fill: #1f831f;}
.block-dns {fill: #1f7c83;}
.block-tcp {fill: #e58226;}
.block-ttfb {fill: #1fe11f;}
.block-response {fill: #1977dd;}
.block-dom {fill: #9cc;}
.block-dom-content-loaded {fill: #d888df;}
.block-onload {fill: #c0c0ff;}
.block-ssl {fill: #c141cd; }
.block-ms-first-paint-event {fill: #8fbc83; }
.block-dom-interactive-event {fill: #d888df; }
.block-network-server {fill: #8cd18c; }
.block-custom-measure {fill: #f00; }
.block-navigation-api-total {fill: #ccc;}
.block-blocking,
.block-blocked {fill: #cdcdcd;}
.block-undefined {fill: #0f0;}
.block-blocked {fill: #ccc;} /*TODO: define colour*/
.block-dns {fill: #1f7c83;}
.block-connect {fill: #e58226;}
.block-ssl {fill:#c141cd;}
.block-send {fill: #1fe110;} /*TODO: define colour*/
.block-wait {fill: #1fe11f;} /*TODO: define colour*/
.block-receive {fill: #1977dd;}
/* Info overlay SVG - wrapper */
.info-overlay {fill: #fff; stroke: #cdcdcd; }
.info-overlay-close-btn {fill: rgba(205, 205, 205, 0.5); transform: translate(-23px, -23px); cursor: pointer;}
.info-overlay-close-btn text {fill: #111; pointer-events: none;}
.info-overlay-close-btn:focus {border: solid 1px #36c;}
/* Info overlay HTML - types */
.type-css {background: #406B29;}/*a6d18f - 40%*/
.type-iframe,
.type-html,
.type-svg,
.type-internal {background: #1C4278;} /*82a8de - 40%*/
.type-img,
.type-image {background: #4D2E69;} /*b394cf - 40%*/
.type-script,
.type-javascript,
.type-js {background: #7A4E1D;} /*e0b483 - 40%*/
.type-link {background: #89afe6;} /*89afe6 - 40%*/
.type-swf,
.type-flash {background: #234980;} /*#42aab1 - 40%*/
.type-font {background: #AE2A1B;} /*#e15d4e - 40%*/
.type-xmlhttprequest,
.type-ajax {background: #CC0000;} /* f00 40%*/
.type-plain,
.type-other {background: #808080;} /*#b3b3b3 - 40%*/
/* Info overlay HTML - base */
.info-overlay-holder * { padding: 0; margin:0; font-size: 12px;}
.info-overlay-holder body { position: relative; height: 450px; clear: both; padding: 0; margin:0; width:100%; background: #fff; color: #666;}
.info-overlay-holder body .wrapper { height: 450px; width: 100%; overflow: scroll;}
/* Info overlay HTML - header */
.info-overlay-holder header {color: #fff; box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.25);}
.info-overlay-holder .requestID {font-weight: bold;}
.info-overlay-holder h3 {font-size: 1.1em; padding: 1em; margin:0; font-weight: normal;}
.info-overlay-holder h3 strong {font-size: 1.1em;}
.info-overlay-holder .tab-nav ul {margin: 0; padding: 0;}
.info-overlay-holder .tab-nav li {margin: 0; padding: 0; display: inline-block;}
.info-overlay-holder button { background: transparent; outline:0; border:0; border-bottom: solid 2px transparent;
padding: 0.5em 1em; margin:0 0.25em;}
.info-overlay-holder li:first-child button {margin-left: 1em;}
.info-overlay-holder button:focus,.info-overlay-holder button:hover {border-color: rgba(255,255,255, 0.6);}
.info-overlay-holder button.active {border-color: #fff; cursor: default;}
/* Info overlay HTML - content */
.info-overlay-holder dt {float: left; clear: both; margin-top: 0.5em; width: 25%; text-align: right; font-weight: bold; }
.info-overlay-holder dd {float: left; width:73%; margin: 0.5em 0 0 2%; padding: 0 0 0.5em 0;}
.info-overlay-holder dt:after { content: ":"; }
.info-overlay-holder pre {font-size: 11px; line-height: 23px; border-radius: 0; background: #f6f3f3;}
.info-overlay-holder .tab {float: left; width:100%; height: 350px; padding:12px 12px 24px;}
.info-overlay-holder .tab h2 {font-size: 1.2em; margin:0.5em 0 0; padding: 0.5em 0 0.5em 1em; clear: both; border-top: solid 1px #efefef;}
.info-overlay-holder .tab pre {overflow-y: hidden;}
.info-overlay-holder .tab .preview {width: auto; max-width: 100%; max-height: 500px; border: solid 1px #666;}
.info-overlay-holder .tab dl:after {content: ""; display: table; clear: both;}

View File

@ -33,3 +33,4 @@
@import 'components/sortable';
@import 'components/summarybox';
@import 'components/misc';
@import 'components/waterfall';

View File

@ -31,7 +31,7 @@ table
td First Visual Change (visual metric)
td.number #{visualMetrics.FirstVisualChange.toFixed(1)}
tr
td Last Visual Change (visual metric)
td Last Visual Change (visual metric)
td.number #{visualMetrics.LastVisualChange.toFixed(1)}
if (Object.keys(timings.userTimings.marks).length > 0)
each value, name in timings.userTimings.marks

View File

@ -27,6 +27,8 @@ block content
li: a(href='#coach') Coach
if d.browsertime && d.browsertime.pageSummary
li: a(href='#timings') Timings
if d.browsertime && d.browsertime.har
li: a(href='#waterfall') Waterfall
if d.pagexray && d.pagexray.pageSummary
li: a(href='#pagexray') Info
if d.webpagetest
@ -38,6 +40,9 @@ block content
if d.browsertime && d.browsertime.pageSummary
include ./browsertime/index.pug
if ( d.browsertime.har && showWaterfallSummary)
include ./waterfall/index.pug
if d.pagexray && d.pagexray.pageSummary
include ./pagexray/index.pug

View File

@ -19,6 +19,8 @@ block content
li: a(href='#coach') Advice
if d.browsertime && d.browsertime.run
li: a(href='#timings') Timing
if d.browsertime.run.har
li: a(href='#waterfall') Waterfall
if d.webpagetest && d.webpagetest.run
li: a(href='#webpagetest') WebPageTest
@ -30,6 +32,8 @@ block content
if d.browsertime && d.browsertime.run
include ./browsertime/index.pug
if d.browsertime.run.har
include ./waterfall/index.pug
if d.webpagetest && d.webpagetest.run
include ./webpagetest/run.pug

View File

@ -0,0 +1,25 @@
a#waterfall
h3 Waterfall
if (pageInfo.data.browsertime.run && pageInfo.data.browsertime.run.har)
- var dahar = pageInfo.data.browsertime.run.har
else
- var dahar = pageInfo.data.browsertime.har
if (dahar.log.pages.length > 1)
p Choose HAR:
select#page-selector
#output
script(src='../../js/perf-cascade.min.js')
script(type='text/javascript').
var outputHolderEl = document.getElementById("output");
var pageSelectorEl = document.getElementById("page-selector");
var options = {
rowHeight: 20, //default: 23
showAlignmentHelpers : true, //default: true
showIndicatorIcons: false, //default: true
leftColumnWith: 30 ,//default: 25
pageSelector: pageSelectorEl
};
var har = !{JSON.stringify(dahar.log)};
var perfCascadeSvg = perfCascade.fromHar(har, options);
outputHolderEl.appendChild(perfCascadeSvg);

View File

@ -209,9 +209,16 @@ module.exports.parseCommandLine = function parseCommandLine() {
default: false,
group: 'Budget'
})
/**
Html options
*/
.option('html.showWaterfallSummary', {
describe: 'Set to true to show waterfalls on summary HTML report',
default: false,
type: 'boolean',
group: 'HTML'
})
/*
.option('html.generateHTML', {
describe: 'Generate HTML results. You may skip it when you store the data elsewhere.',