-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
fix: save artifacts and assets in output path #1601
Changes from 6 commits
92fb9ab
415df64
6c707b8
c3e18ff
407e409
e311a48
a6b2d34
69ebf22
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 |
---|---|---|
|
@@ -249,6 +249,36 @@ function handleError(err: LighthouseError) { | |
} | ||
} | ||
|
||
function saveResults(results: Results, | ||
flags: {output: any, outputPath: string, saveArtifacts: boolean, saveAssets: boolean}) { | ||
let promise = Promise.resolve(results); | ||
const cwd = process.cwd(); | ||
const configuredPath = !flags.outputPath || flags.outputPath === 'stdout' ? | ||
assetSaver.getFilenamePrefix(results) : | ||
flags.outputPath.replace(/\.\w{2,4}$/, ''); | ||
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. instead of this edit we could do... const parsed = path.parse(flags.outputPath);
parsed.base = parsed.base.replace(parsed.ext, '');
path.format(parsed); but i don't know if that's really worth it. :) 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. I like the explicitness of it but not a huge fan of the triple lines, haha :) |
||
const resolvedPath = path.resolve(cwd, configuredPath); | ||
const pathWithBasename = resolvedPath.includes(cwd) ? | ||
resolvedPath.slice(cwd.length + 1) : resolvedPath; | ||
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. maybe i'm missing something obvious, but what does slicing accomplish here? 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. my read is that resolvedPath always includes cwd because we just did path.resolve on it. This is 1) the same as 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. Just nuked because with the default options the logging seemed a bit verbose to restate your |
||
|
||
// delete artifacts from result so reports won't include artifacts. | ||
const artifacts = results.artifacts; | ||
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. maybe keep this in the caller and pass in 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. I think it feels weird have this part of the saving logic outside |
||
results.artifacts = undefined; | ||
|
||
if (flags.saveArtifacts) { | ||
assetSaver.saveArtifacts(artifacts, pathWithBasename); | ||
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. as mentioned offline, we can remove --save-artifacts flag and the functions if we want. AFAIK, they havent been used for ages and are only for debugging. |
||
} | ||
|
||
if (flags.saveAssets) { | ||
promise = promise.then(_ => assetSaver.saveAssets(artifacts, results.audits, pathWithBasename)); | ||
} | ||
|
||
if (flags.output === Printer.OutputMode[Printer.OutputMode.pretty]) { | ||
promise = promise.then(_ => Printer.write(results, 'html', `${pathWithBasename}.report.html`)); | ||
} | ||
|
||
return promise.then(_ => Printer.write(results, flags.output, flags.outputPath)); | ||
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. you're inheriting this, but it seems kind of magical that we rely on 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. removed the need for it to return anything at all |
||
} | ||
|
||
function runLighthouse(url: string, | ||
flags: {port: number, skipAutolaunch: boolean, selectChrome: boolean, output: any, | ||
outputPath: string, interactive: boolean, saveArtifacts: boolean, saveAssets: boolean}, | ||
|
@@ -259,27 +289,7 @@ function runLighthouse(url: string, | |
.then(() => getDebuggableChrome(flags)) | ||
.then(chrome => chromeLauncher = chrome) | ||
.then(() => lighthouse(url, flags, config)) | ||
.then((results: Results) => { | ||
// delete artifacts from result so reports won't include artifacts. | ||
const artifacts = results.artifacts; | ||
results.artifacts = undefined; | ||
|
||
if (flags.saveArtifacts) { | ||
assetSaver.saveArtifacts(artifacts); | ||
} | ||
if (flags.saveAssets) { | ||
return assetSaver.saveAssets(artifacts, results).then(() => results); | ||
} | ||
return results; | ||
}) | ||
.then((results: Results) => Printer.write(results, flags.output, flags.outputPath)) | ||
.then((results: Results) => { | ||
if (flags.output === Printer.OutputMode[Printer.OutputMode.pretty]) { | ||
const filename = `${assetSaver.getFilenamePrefix(results)}.report.html`; | ||
return Printer.write(results, 'html', filename); | ||
} | ||
return results; | ||
}) | ||
.then((results: Results) => saveResults(results, flags)) | ||
.then((results: Results) => { | ||
if (flags.interactive) { | ||
return performanceXServer.hostExperiment({url, flags, config}, results); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,13 +48,12 @@ function getFilenamePrefix(results) { | |
/** | ||
* Generate basic HTML page of screenshot filmstrip | ||
* @param {!Array<{timestamp: number, datauri: string}>} screenshots | ||
* @param {!Results} results | ||
* @return {!string} | ||
*/ | ||
function screenshotDump(screenshots, results) { | ||
function screenshotDump(screenshots) { | ||
return ` | ||
<!doctype html> | ||
<title>screenshots ${getFilenamePrefix(results)}</title> | ||
<title>screenshots</title> | ||
<style> | ||
html { | ||
overflow-x: scroll; | ||
|
@@ -91,24 +90,24 @@ img { | |
/** | ||
* Save entire artifacts object to a single stringified 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. maybe add a line to the jsdoc that artifacts will be saved at 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. done |
||
* @param {!Artifacts} artifacts | ||
* @param {!string} artifactsFilename | ||
* @param {string} pathWithBasename | ||
*/ | ||
// Set to ignore because testing it would imply testing fs, which isn't strictly necessary. | ||
/* istanbul ignore next */ | ||
function saveArtifacts(artifacts, artifactsFilename) { | ||
artifactsFilename = artifactsFilename || 'artifacts.log'; | ||
function saveArtifacts(artifacts, pathWithBasename) { | ||
const fullPath = `${pathWithBasename}.artifacts.log`; | ||
// The networkRecords artifacts have circular references | ||
fs.writeFileSync(artifactsFilename, stringifySafe(artifacts)); | ||
log.log('artifacts file saved to disk', artifactsFilename); | ||
fs.writeFileSync(fullPath, stringifySafe(artifacts)); | ||
log.log('artifacts file saved to disk', fullPath); | ||
} | ||
|
||
/** | ||
* Filter traces and extract screenshots to prepare for saving. | ||
* @param {!Artifacts} artifacts | ||
* @param {!Results} results | ||
* @param {!Audits} audits | ||
* @return {!Promise<!Array<{traceData: !Object, html: string}>>} | ||
*/ | ||
function prepareAssets(artifacts, results) { | ||
function prepareAssets(artifacts, audits) { | ||
const passNames = Object.keys(artifacts.traces); | ||
const assets = []; | ||
|
||
|
@@ -118,10 +117,10 @@ function prepareAssets(artifacts, results) { | |
return chain.then(_ => artifacts.requestScreenshots(trace)) | ||
.then(screenshots => { | ||
const traceData = Object.assign({}, trace); | ||
const html = screenshotDump(screenshots, results); | ||
const html = screenshotDump(screenshots); | ||
|
||
if (results && results.audits) { | ||
const evts = new Metrics(traceData.traceEvents, results.audits).generateFakeEvents(); | ||
if (audits) { | ||
const evts = new Metrics(traceData.traceEvents, audits).generateFakeEvents(); | ||
traceData.traceEvents.push(...evts); | ||
} | ||
assets.push({ | ||
|
@@ -136,19 +135,21 @@ function prepareAssets(artifacts, results) { | |
/** | ||
* Writes trace(s) and associated screenshot(s) to disk. | ||
* @param {!Artifacts} artifacts | ||
* @param {!Results} results | ||
* @param {!Audits} audits | ||
* @param {string} pathWithBasename | ||
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. same thing with jsdoc, |
||
* @return {!Promise} | ||
*/ | ||
function saveAssets(artifacts, results) { | ||
return prepareAssets(artifacts, results).then(assets => { | ||
function saveAssets(artifacts, audits, pathWithBasename) { | ||
return prepareAssets(artifacts, audits).then(assets => { | ||
assets.forEach((data, index) => { | ||
const filenamePrefix = getFilenamePrefix(results); | ||
const traceData = data.traceData; | ||
fs.writeFileSync(`${filenamePrefix}-${index}.trace.json`, JSON.stringify(traceData, null, 2)); | ||
log.log('trace file saved to disk', filenamePrefix); | ||
const traceFilename = `${pathWithBasename}-${index}.trace.json`; | ||
fs.writeFileSync(traceFilename, JSON.stringify(traceData, null, 2)); | ||
log.log('trace file saved to disk', traceFilename); | ||
|
||
fs.writeFileSync(`${filenamePrefix}-${index}.screenshots.html`, data.html); | ||
log.log('screenshots saved to disk', filenamePrefix); | ||
const screenshotsFilename = `${pathWithBasename}-${index}.screenshots.html`; | ||
fs.writeFileSync(screenshotsFilename, data.html); | ||
log.log('screenshots saved to disk', screenshotsFilename); | ||
}); | ||
}); | ||
} | ||
|
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.
it would be great to get some of the PR's first comment captured here or in a doc on the method (readme too?).
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.
done