Skip to content

Commit

Permalink
core(gather-runner): load a blank data URI, rather than about:blank (#…
Browse files Browse the repository at this point in the history
…4310)

* core(gather-runner): load a blank data URI, rather than about:blank

* move to public method on driver API

* add to EmulationDriver

* extract blank-page to file. slightest bit blue.

* put a logo on it.

* require html's source into bundle

* use intermediary blank page

* await onload. docs, lol.

* skip loadBlank on first pass

* move initial loadBlank into setupDriver. update docs.
(no functional change)

* fix tests.

* skip first load based on passIndex
  • Loading branch information
paulirish authored and patrickhulce committed Feb 6, 2018
1 parent 1b96506 commit 3030b4f
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 24 deletions.
13 changes: 13 additions & 0 deletions lighthouse-core/gather/blank-page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Resetting page...</title>
<style>
html, body {
height: 100%;
background: hsl(231, 99%, 99%);
overflow: hidden;
}
</style>
<body>
9 changes: 9 additions & 0 deletions lighthouse-core/gather/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,15 @@ class Driver {
};
}

/**
* Return a promise that resolves `pauseAfterLoadMs` after the load event fires.
* @param {number} pauseAfterLoadMs
* @return {!Promise}
*/
waitForLoadEvent(pauseAfterLoadMs = 0) {
return this._waitForLoadEvent(pauseAfterLoadMs).promise;
}

/**
* Return a promise that resolves `pauseAfterLoadMs` after the load event
* fires and a method to cancel internal listeners and timeout.
Expand Down
69 changes: 45 additions & 24 deletions lighthouse-core/gather/gather-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
*/
// @ts-nocheck
'use strict';
const fs = require('fs');

const log = require('lighthouse-logger');
const Audit = require('../audits/audit');
const LHError = require('../lib/errors');
const URL = require('../lib/url-shim');
const NetworkRecorder = require('../lib/network-recorder.js');
const blankPageSource = fs.readFileSync(__dirname + '/blank-page.html', 'utf8');
const logoPageSource = fs.readFileSync(__dirname + '/logo-page.html', 'utf8');

/**
* @typedef {!Object<string, !Array<!Promise<*>>>} GathererResults
Expand All @@ -21,20 +24,21 @@ const NetworkRecorder = require('../lib/network-recorder.js');
* Execution sequence when GatherRunner.run() is called:
*
* 1. Setup
* A. navigate to about:blank
* B. driver.connect()
* C. GatherRunner.setupDriver()
* i. assertNoSameOriginServiceWorkerClients
* ii. beginEmulation
* iii. enableRuntimeEvents
* iv. evaluateScriptOnLoad rescue native Promise from potential polyfill
* v. register a performance observer
* vi. register dialog dismisser
* vii. clearDataForOrigin
* i. navigate to a blank page
* ii. assertNoSameOriginServiceWorkerClients
* iii. retrieve and save userAgent
* iv. beginEmulation
* v. enableRuntimeEvents
* vi. evaluateScriptOnLoad rescue native Promise from potential polyfill
* vii. register a performance observer
* viii. register dialog dismisser
* iv. clearDataForOrigin
*
* 2. For each pass in the config:
* A. GatherRunner.beforePass()
* i. navigate to about:blank
* i. navigate to a blank page
* ii. Enable network request blocking for specified patterns
* iii. all gatherers' beforePass()
* B. GatherRunner.pass()
Expand All @@ -56,17 +60,27 @@ const NetworkRecorder = require('../lib/network-recorder.js');
*/
class GatherRunner {
/**
* Loads about:blank and waits there briefly. Since a Page.reload command does
* not let a service worker take over, we navigate away and then come back to
* reload. We do not `waitForLoad` on about:blank since a page load event is
* never fired on it.
* Loads a blank page and waits there briefly. Since a Page.reload command does
* not let a service worker take over, we navigate away and then come back to reload.
* @param {!Driver} driver
* @param {url=} url
* @param {number=} duration
* @return {!Promise}
*/
static loadBlank(driver, url = 'about:blank', duration = 300) {
return driver.gotoURL(url).then(_ => new Promise(resolve => setTimeout(resolve, duration)));
static loadBlank(driver, url) {
// The real about:blank doesn't fire onload and is full of mysteries (https://goo.gl/mdQkYr)
// To improve speed and avoid anomalies (https://goo.gl/Aho2R9), we use a basic data uri page
url = url || `data:text/html,${logoPageSource}`;
const blankPageUrl = `data:text/html,${blankPageSource}`;

// Only navigating to a single data-uri doesn't reliably trigger onload. (Why? Beats me.)
// Two data uris work, however the two need to be sufficiently different (Why? Beats me.)
// If they are too similar, Chrome considers the latter to be as superficial as a pushState
// Lastly, it's possible for two navigations to be racy, so we await onload inbetween.
return driver.gotoURL(blankPageUrl)
.then(_ => driver.waitForLoadEvent())
.then(_ => driver.gotoURL(url))
.then(_ => driver.waitForLoadEvent());
}

/**
Expand Down Expand Up @@ -98,8 +112,10 @@ class GatherRunner {
static setupDriver(driver, gathererResults, options) {
log.log('status', 'Initializing…');
const resetStorage = !options.flags.disableStorageReset;
// Enable emulation based on flags
return driver.assertNoSameOriginServiceWorkerClients(options.url)
// In the devtools/extension case, we can't still be on the site while trying to clear state
// So we first navigate to a blank page, then apply our emulation & setup
return GatherRunner.loadBlank(driver)
.then(_ => driver.assertNoSameOriginServiceWorkerClients(options.url))
.then(_ => driver.getUserAgent())
.then(userAgent => {
gathererResults.UserAgent = [userAgent];
Expand Down Expand Up @@ -195,11 +211,17 @@ class GatherRunner {
const blockedUrls = (options.config.blockedUrlPatterns || [])
.concat(options.flags.blockedUrlPatterns || []);
const blankPage = options.config.blankPage;
const blankDuration = options.config.blankDuration;
const pass = GatherRunner.loadBlank(options.driver, blankPage, blankDuration)
// Set request blocking before any network activity
// No "clearing" is done at the end of the pass since blockUrlPatterns([]) will unset all if
// neccessary at the beginning of the next pass.

// On the very first pass we're already on blank
const skipLoadBlank = options.passIndex === 0;
let pass = skipLoadBlank
? Promise.resolve()
: GatherRunner.loadBlank(options.driver, blankPage);

// Set request blocking before any network activity
// No "clearing" is done at the end of the pass since blockUrlPatterns([]) will unset all if
// neccessary at the beginning of the next pass.
pass = pass
.then(() => options.driver.blockUrlPatterns(blockedUrls))
.then(() => options.driver.setExtraHTTPHeaders(options.flags.extraHeaders));

Expand Down Expand Up @@ -400,15 +422,14 @@ class GatherRunner {
};

return driver.connect()
.then(_ => GatherRunner.loadBlank(driver))
.then(_ => GatherRunner.setupDriver(driver, gathererResults, options))

// Run each pass
.then(_ => {
// If the main document redirects, we'll update this to keep track
let urlAfterRedirects;
return passes.reduce((chain, config, passIndex) => {
const runOptions = Object.assign({}, options, {config});
const runOptions = Object.assign({}, options, {config}, {passIndex});
return chain
.then(_ => driver.setThrottling(options.flags, config))
.then(_ => GatherRunner.beforePass(runOptions, gathererResults))
Expand Down
24 changes: 24 additions & 0 deletions lighthouse-core/gather/logo-page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!doctype html>
<html>
<meta name="viewport" content="width=device-width">
<meta charset="utf-8">
<title>Resetting page....</title>
<style>
html, body {
background: hsl(231, 99%, 99%);
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
svg {
filter: saturate(20%);
width: 150px;
height: 150px;
margin-top: -50px;
}
</style>
<body>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 750 750"><path fill="#304ffe" d="M92.43 571.02c52.32 0 52.32-33.94 104.64-33.94s52.3 33.94 104.63 33.94c52.32 0 52.32-33.94 104.63-33.94 52.3 0 52.32 33.94 104.64 33.94s52.32-33.94 104.64-33.94c49.48 0 52.17 30.34 96.56 33.64a326.73 326.73 0 0 0 8.09-72.39c0-179.87-145.82-325.69-325.7-325.69s-325.7 145.82-325.7 325.7a326.75 326.75 0 0 0 7.9 71.5 98.88 98.88 0 0 0 15.67 1.18z"/><g transform="translate(-111.07 296.27)"><circle cx="593.87" cy="-88.78" r="3.53" fill="#fdd835"/><circle cx="624.87" cy="109.62" r="6.13" fill="#fff9c4"/><circle cx="253.47" cy="53.59" r="6.13" fill="#fff9c4"/><circle cx="353.42" cy="160.21" r="6.13" fill="#fff9c4"/><circle cx="598.48" cy="11.64" r="6.13" fill="#fff9c4"/><circle cx="727.63" cy="169.54" r="6.13" fill="#fff9c4"/><circle cx="240.27" cy="192.4" r="3.53" fill="#fdd835"/><circle cx="272.83" cy="121.09" r="3.53" fill="#fdd835"/><circle cx="294.74" cy="102.71" r="3.53" fill="#fdd835"/><circle cx="387.35" cy="20" r="3.53" fill="#fdd835"/><circle cx="679.87" cy="30.22" r="3.53" fill="#fdd835"/><circle cx="818.6" cy="177.65" r="3.53" fill="#fdd835"/><circle cx="328.68" cy="9.39" r="3.53" fill="#fdd835"/><circle cx="640.9" cy="179.2" r="3.53" fill="#fdd835"/><circle cx="747.87" cy="90.75" r="3.53" fill="#fdd835"/></g><path fill="#2979ff" d="M542.66 245.81a19.59 19.59 0 0 1 8.32 1.84 34.49 34.49 0 0 1 66.7-9h.12a23.25 23.25 0 0 1 0 46.5h-75.14a19.67 19.67 0 1 1 0-39.34z"/><path fill="#ffd54f" d="M362.98 213.56h84.84v78.5h-84.84z"/><path fill="#fff176" d="M362.98 213.56h29.95v78.5h-29.95z"/><ellipse cx="392.3" cy="233.21" fill="#fff176" rx="19.84" ry="24.89"/><path fill="#f4511e" d="M360.9 204.7a43.84 43.84 0 1 1 87.67 0"/><path fill="#e64a19" d="M405.1 160.87a43.51 43.51 0 0 1 43.47 43.83H405.1v-43.83z"/><rect width="104.64" height="11.31" x="352.42" y="203.29" fill="#f4511e" rx="5.66" ry="5.66"/><path fill="#c5cae9" d="M350.8 534.02l12.23-242.5h84.84l10.93 230.5z"/><path fill="#ff7043" d="M449.04 310.25l3.26 64.17m-92.45-22.6l-3.42 67.3 95.87-44.7-3.26-64.17zm95.67 85.84l3.27 64.18m-105.74-16.42l-3.42 67.3 109.16-50.88-3.27-64.18z"/><path fill="#e64a19" d="M349.99 255.9h109.49v35.82h-109.5z"/><path fill="#f4511e" d="M349.99 255.9h71.78v35.82h-71.78z"/><path fill="#ffe082" d="M403.98 255.9c0 13-12.1 23.5-27 23.5s-27-10.52-27-23.5" opacity=".5"/><path fill="#304ffe" d="M451.07 291.52h-42.9v219.5l52 23L449 291.52z" opacity=".5"/><path fill="#448aff" d="M319.66 433.3a16.6 16.6 0 0 1 7 1.55 29.23 29.23 0 0 1 56.53-7.63h.1a19.71 19.71 0 1 1 0 39.41h-63.63a16.67 16.67 0 1 1 0-33.34z"/><path fill="#ffe082" d="M364.42 212.37L29.8 164.58a3.65 3.65 0 0 0-1-.14c-8.67 0-16 31.9-16 71.15 0 39.26 7.33 71.07 16 71.07a3.66 3.66 0 0 0 .93-.13l334.64-47.88v-46.28z" opacity=".5"/><path fill="#00c853" d="M302.7 571.75c52.32 0 52.32-33.94 104.63-33.94 52.3 0 52.32 33.94 104.63 33.94 44.42 0 51.13-24.46 84.16-31.84-45.13-24.66-112.53-40.33-187.84-40.33-75.63 0-143.28 15.8-188.41 40.64 31.93 7.73 39.02 31.53 82.83 31.53z"/><path fill="#64dd17" d="M302.8 571.28c52.32 0 52.32-33.94 104.63-33.94h1.1l-.58-37.32c-74.9 0-142 15.5-187.08 39.91 31.16 7.98 38.55 31.35 81.93 31.35z"/></svg>
3 changes: 3 additions & 0 deletions lighthouse-core/test/gather/fake-driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ module.exports = {
gotoURL() {
return Promise.resolve('https://example.com');
},
waitForLoadEvent() {
return Promise.resolve();
},
beginEmulation() {
return Promise.resolve();
},
Expand Down
7 changes: 7 additions & 0 deletions lighthouse-core/test/gather/gather-runner-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn,
getUserAgent() {
return Promise.resolve('Fake user agent');
}
waitForLoadEvent() {
return Promise.resolve();
}
};
const EmulationMock = class extends Connection {
sendCommand(command, params) {
Expand Down Expand Up @@ -255,6 +258,8 @@ describe('GatherRunner', function() {
dismissJavaScriptDialogs: asyncFunc,
enableRuntimeEvents: asyncFunc,
cacheNatives: asyncFunc,
gotoURL: asyncFunc,
waitForLoadEvent: asyncFunc,
registerPerformanceObserver: asyncFunc,
cleanBrowserCaches: createCheck('calledCleanBrowserCaches'),
clearDataForOrigin: createCheck('calledClearStorage'),
Expand Down Expand Up @@ -314,6 +319,8 @@ describe('GatherRunner', function() {
dismissJavaScriptDialogs: asyncFunc,
enableRuntimeEvents: asyncFunc,
cacheNatives: asyncFunc,
gotoURL: asyncFunc,
waitForLoadEvent: asyncFunc,
registerPerformanceObserver: asyncFunc,
cleanBrowserCaches: createCheck('calledCleanBrowserCaches'),
clearDataForOrigin: createCheck('calledClearStorage'),
Expand Down

0 comments on commit 3030b4f

Please sign in to comment.