-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
core(runner): asset manager helper #13519
Changes from all commits
552fe50
739a058
48cf364
2f011d1
71c67e4
e32c855
972bf83
8abf951
7111b21
b8a2da3
d073017
07ef5d9
382886d
fac8b10
b7f53f0
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 |
---|---|---|
|
@@ -16,7 +16,6 @@ const stackPacks = require('./lib/stack-packs.js'); | |
const assetSaver = require('./lib/asset-saver.js'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const URL = require('./lib/url-shim.js'); | ||
const Sentry = require('./lib/sentry.js'); | ||
const generateReport = require('../report/generator/report-generator.js').generateReport; | ||
const LHError = require('./lib/lh-error.js'); | ||
|
@@ -29,8 +28,8 @@ const {version: lighthouseVersion} = require('../package.json'); | |
class Runner { | ||
/** | ||
* @template {LH.Config.Config | LH.Config.FRConfig} TConfig | ||
* @param {(runnerData: {requestedUrl: string, config: TConfig, driverMock?: Driver}) => Promise<LH.Artifacts>} gatherFn | ||
* @param {{config: TConfig, computedCache: Map<string, ArbitraryEqualityMap>, url?: string, driverMock?: Driver}} runOpts | ||
* @param {(runnerData: {config: TConfig, driverMock?: Driver}) => Promise<LH.Artifacts>} gatherFn | ||
* @param {{config: TConfig, computedCache: Map<string, ArbitraryEqualityMap>, driverMock?: Driver}} runOpts | ||
* @return {Promise<LH.RunnerResult|undefined>} | ||
*/ | ||
static async run(gatherFn, runOpts) { | ||
|
@@ -52,47 +51,7 @@ class Runner { | |
data: sentryContext?.extra, | ||
}); | ||
|
||
// User can run -G solo, -A solo, or -GA together | ||
// -G and -A will run partial lighthouse pipelines, | ||
// and -GA will run everything plus save artifacts and lhr to disk. | ||
|
||
// Gather phase | ||
// Either load saved artifacts off disk or from the browser | ||
let artifacts; | ||
let requestedUrl; | ||
if (settings.auditMode && !settings.gatherMode) { | ||
// No browser required, just load the artifacts from disk. | ||
const path = Runner._getDataSavePath(settings); | ||
artifacts = assetSaver.loadArtifacts(path); | ||
requestedUrl = artifacts.URL.requestedUrl; | ||
|
||
if (!requestedUrl) { | ||
throw new Error('Cannot run audit mode on empty URL'); | ||
} | ||
if (runOpts.url && !URL.equalWithExcludedFragments(runOpts.url, requestedUrl)) { | ||
throw new Error('Cannot run audit mode on different URL'); | ||
} | ||
Comment on lines
-72
to
-74
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. Removing this check should be the only functional change to legacy mode. I didn't think it was needed because we can proceed with the 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. The check makes more sense from the context of the CLI. Currently you can do 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 would prefer just logging a warning, since we could just ignore the passed in URL. 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'm fine with just a warning. -G/A is pretty advanced usage so we don't really need these runtime failures to protect us, IMO 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. A report warning, then, not logger. This will otherwise be ignored and is sure to mess me up eventually so a loud warning is necessary :) 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 would prefer switching to a fatal error in the CLI than that. We would need to send the warning message all the way down to The warning is quiet, but Lighthouse is still performing the more correct and expected operation IMO. |
||
} else { | ||
// verify the url is valid and that protocol is allowed | ||
if (runOpts.url && URL.isValid(runOpts.url) && URL.isProtocolAllowed(runOpts.url)) { | ||
// Use canonicalized URL (with trailing slashes and such) | ||
requestedUrl = new URL(runOpts.url).href; | ||
} else { | ||
throw new LHError(LHError.errors.INVALID_URL); | ||
} | ||
|
||
artifacts = await gatherFn({ | ||
requestedUrl, | ||
config: runOpts.config, | ||
driverMock: runOpts.driverMock, | ||
}); | ||
|
||
// -G means save these to ./latest-run, etc. | ||
if (settings.gatherMode) { | ||
const path = Runner._getDataSavePath(settings); | ||
await assetSaver.saveArtifacts(artifacts, path); | ||
} | ||
} | ||
const artifacts = await this.gatherAndManageArtifacts(gatherFn, runOpts); | ||
|
||
// Potentially quit early | ||
if (settings.gatherMode && !settings.auditMode) return; | ||
|
@@ -133,7 +92,7 @@ class Runner { | |
/** @type {LH.RawIcu<LH.Result>} */ | ||
const i18nLhr = { | ||
lighthouseVersion, | ||
requestedUrl, | ||
requestedUrl: artifacts.URL.requestedUrl, | ||
finalUrl: artifacts.URL.finalUrl, | ||
fetchTime: artifacts.fetchTime, | ||
gatherMode: artifacts.GatherContext.gatherMode, | ||
|
@@ -184,6 +143,47 @@ class Runner { | |
} | ||
} | ||
|
||
/** | ||
* User can run -G solo, -A solo, or -GA together | ||
* -G and -A will run partial lighthouse pipelines, | ||
* and -GA will run everything plus save artifacts and lhr to disk. | ||
* | ||
* @template {LH.Config.Config | LH.Config.FRConfig} TConfig | ||
* @param {(runnerData: {config: TConfig, driverMock?: Driver}) => Promise<LH.Artifacts>} gatherFn | ||
* @param {{config: TConfig, driverMock?: Driver}} options | ||
* @return {Promise<LH.Artifacts>} | ||
*/ | ||
static async gatherAndManageArtifacts(gatherFn, options) { | ||
const settings = options.config.settings; | ||
|
||
// Gather phase | ||
// Either load saved artifacts from disk or from the browser. | ||
let artifacts; | ||
if (settings.auditMode && !settings.gatherMode) { | ||
// No browser required, just load the artifacts from disk. | ||
const path = this._getDataSavePath(settings); | ||
artifacts = assetSaver.loadArtifacts(path); | ||
const requestedUrl = artifacts.URL.requestedUrl; | ||
|
||
if (!requestedUrl) { | ||
throw new Error('Cannot run audit mode on empty URL'); | ||
} | ||
} else { | ||
artifacts = await gatherFn({ | ||
config: options.config, | ||
driverMock: options.driverMock, | ||
}); | ||
|
||
// -G means save these to disk (e.g. ./latest-run). | ||
if (settings.gatherMode) { | ||
const path = this._getDataSavePath(settings); | ||
await assetSaver.saveArtifacts(artifacts, path); | ||
} | ||
} | ||
|
||
return artifacts; | ||
} | ||
|
||
/** | ||
* This handles both the auditMode case where gatherer entries need to be merged in and | ||
* the gather/audit case where timingEntriesFromRunner contains all entries from this run, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,12 +143,22 @@ function createMockDriver() { | |
}; | ||
} | ||
|
||
/** @param {() => jest.Mock} runProvider */ | ||
function mockRunnerModule(runProvider) { | ||
const runnerModule = {getGathererList: () => []}; | ||
Object.defineProperty(runnerModule, 'run', { | ||
get: runProvider, | ||
}); | ||
function mockRunnerModule() { | ||
const runnerModule = { | ||
getGathererList: jest.fn().mockReturnValue([]), | ||
gatherAndManageArtifacts: jest.fn(), | ||
run: jest.fn(), | ||
reset, | ||
}; | ||
|
||
jest.mock('../../../runner.js', () => runnerModule); | ||
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. these mock commands are tricky when it comes to es modules, b/c jest hoists them to the top to make them work. https://jestjs.io/docs/manual-mocks#using-with-es-module-imports can keep it as-is since still commonjs, or just continue to do the
no preference atm. 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 this way since it follows the format of |
||
|
||
function reset() { | ||
runnerModule.getGathererList.mockReturnValue([]); | ||
runnerModule.gatherAndManageArtifacts.mockReset(); | ||
runnerModule.run.mockReset(); | ||
} | ||
|
||
return runnerModule; | ||
} | ||
|
||
|
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.
So turns out this creates a circular dependency that messes with our DT bundle.
url-shim.js
might not be the best place for this @brendankenny.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.
runner-helpers.js
maybe?