-
-
Notifications
You must be signed in to change notification settings - Fork 27k
Add Lighthouse audit command #7990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// @remove-file-on-eject | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
'use strict'; | ||
|
||
const { createServer } = require('http'); | ||
const { writeFileSync } = require('fs'); | ||
const { join } = require('path'); | ||
const { choosePort } = require('react-dev-utils/WebpackDevServerUtils'); | ||
const open = require('open'); | ||
const handler = require('serve-handler'); | ||
const lighthouse = require('lighthouse'); | ||
const chromeLauncher = require('chrome-launcher'); | ||
const paths = require('../config/paths'); | ||
|
||
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; | ||
const HOST = process.env.HOST || '0.0.0.0'; | ||
|
||
// https://github.com/GoogleChrome/lighthouse/blob/master/docs/readme.md#using-programmatically | ||
const launchChromeAndRunLighthouse = (url, opts) => { | ||
return chromeLauncher | ||
.launch({ chromeFlags: opts.chromeFlags }) | ||
.then(chrome => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be able to use async/await if that helps clean it up. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We have Node ">8.10" as our requirement for |
||
opts.port = chrome.port; | ||
return lighthouse(url, opts).then(results => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to forward arguments to lighthouse. They have some cool customizations through their CLI. For example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, this would make sense. Or better yet - or perhaps also - we could load a config file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. async/await may make it a bit simpler to cover failure cases such as any of this process throwing in which case we should probably clean up the browser and server instances. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. I just left this as per the docs for now - and forgot that we don't support Node 6. |
||
return chrome.kill().then(() => results.report); | ||
}); | ||
}); | ||
}; | ||
|
||
const server = createServer((request, response) => | ||
handler(request, response, { | ||
renderSingle: true, | ||
public: paths.appBuild, | ||
}) | ||
); | ||
|
||
choosePort(HOST, DEFAULT_PORT) | ||
.then(() => choosePort(HOST, DEFAULT_PORT)) | ||
.then(port => { | ||
if (port == null) { | ||
console.log('Unable to find a free port'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we do something like this in error cases for consistency elsewhere? console.error(
chalk.bold.red(...)
) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, this should be polished - it also needs some line spacing. |
||
process.exit(1); | ||
} | ||
|
||
server.listen(port); | ||
|
||
console.log('Server started, beginning audit...'); | ||
|
||
return launchChromeAndRunLighthouse(`http://${HOST}:${port}`, { | ||
ianschmitz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
output: 'html', | ||
}); | ||
}) | ||
.then(report => { | ||
console.log('Audit finished, writing report...'); | ||
|
||
const reportPath = join(paths.appPath, 'lighthouse-audit.html'); | ||
writeFileSync(reportPath, report); | ||
|
||
console.log('Opening report in browser...'); | ||
|
||
open(reportPath, { url: true }); | ||
|
||
console.log('Exiting...'); | ||
|
||
server.close(); | ||
}) | ||
.catch(() => { | ||
console.log('Something went wrong, exiting...'); | ||
server.close(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,6 +114,7 @@ module.exports = function( | |
build: 'react-scripts build', | ||
test: 'react-scripts test', | ||
eject: 'react-scripts eject', | ||
lighthouse: 'react-scripts audit', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what I had... but it turns out it conflicts with Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah doh! Of course |
||
}; | ||
|
||
// Setup the eslint config | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running chrome in headless would be amazing! I could see some cool CI use cases to fail when below a threshold. Potentially using puppeteer would make that trivial for us, removes the need to have chrome installed to use this functionality, and also provides the option to run headed if needed for debugging etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/justinribeiro/lighthouse-jest-example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, so there's an option for headless. I left it "headfull" as the default intentionally - I feel that for some people, it's nice to see how it works - I guess we can rely on a flag or config for opting out of that?
What do you think @ianschmitz?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, including
puppeteer
as a direct dependency would greatly increase thenode_modules
size which isn't great:When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win)
.Documentation could likely handle this:
If you want to run this in CI, make sure Chrome/Chromium is installed...
(or use puppeteer etc.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I think we should also handle this in the script... I'm sure we can.