Skip to content

Commit

Permalink
docs: examples of combining puppeteer & lighthouse (#4408)
Browse files Browse the repository at this point in the history
  • Loading branch information
ebidel authored and paulirish committed Feb 9, 2018
1 parent c3620b1 commit 3e34af7
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions docs/puppeteer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Recipes Puppeteer with Lighthouse

**Note**: https://github.com/GoogleChrome/lighthouse/issues/3837 tracks the discussion for making Lighthouse work in concert with Puppeteer.
Some things are possible today (login to a page using Puppeteer, audit it using Lighthouse) while others (A/B testing the perf of UI changes) are trickier or not yet possible.

### Inject JS/CSS before the page loads

The example below shows how to inject CSS into the page before Lighthouse audits the page.
A similar approach can be taken for injecting JavaScript.

```js
const puppeteer = require('puppeteer');
const lighthouse = require('lighthouse');
const {URL} = require('url');

(async() => {
const url = 'https://www.chromestatus.com/features';

// Use Puppeteer to launch Chrome. appMode launches headful chrome and doesn't size the viewport.
const browser = await puppeteer.launch({appMode: true});

// Wait for Lighthouse to open url, then customize network conditions.
// Note: this will re-establish these conditions when LH reloads the page. Think that's ok....
browser.on('targetchanged', async target => {
const page = await target.page();

function addStyleContent(content) {
const style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(content));
document.head.appendChild(style);
}

const css = '* {color: red}';

if (page && page.url() === url) {
// Note: can't use page.addStyleTag due to github.com/GoogleChrome/puppeteer/issues/1955.
// Do it ourselves.
const client = await page.target().createCDPSession();
await client.send('Runtime.evaluate', {
expression: `(${addStyleContent.toString()})('${css}')`
});
}
});

// Lighthouse will open URL. Puppeteer observes `targetchanged` and sets up network conditions.
// Possible race condition.
const lhr = await lighthouse(url, {
port: (new URL(browser.wsEndpoint())).port,
output: 'json',
logLevel: 'info',
});

console.log(`Lighthouse score: ${lhr.score}`);

await browser.close();
})();
```

### Connecting Puppeteer to a browser instance launched by chrome-launcher.

When using Lighthouse programmatically, you'll often use chrome-launcher to launch Chrome.
Puppeteer can reconnect to this existing browser instance like so:

```js
const chromeLauncher = require('chrome-launcher');
const puppeteer = require('puppeteer');
const lighthouse = require('lighthouse');
const request = require('request');
const util = require('util');

(async() => {

const URL = 'https://www.chromestatus.com/features';

const opts = {
//chromeFlags: ['--headless'],
logLevel: 'info',
output: 'json'
};

// Launch chrome using chrome-launcher.
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;

// Connect to it using puppeteer.connect().
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const {webSocketDebuggerUrl} = JSON.parse(resp.body);
const browser = await puppeteer.connect({browserWSEndpoint: webSocketDebuggerUrl});

// Run Lighthouse.
const lhr = await lighthouse(URL, opts, null);
console.log(`Lighthouse score: ${lhr.score}`);

await browser.disconnect();
await chrome.kill();

})();
```

0 comments on commit 3e34af7

Please sign in to comment.