core(runner): make LH.Audit.Context immutable (#10555)

This commit is contained in:
Brendan Kenny 2020-04-09 18:20:43 -04:00 коммит произвёл GitHub
Родитель 159fd93e48
Коммит 3e5c664c3f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 53 добавлений и 53 удалений

Просмотреть файл

@ -181,8 +181,9 @@ class BootupTime extends Audit {
// TODO: consider moving this to core gathering so you don't need to run the audit for warning
let runWarnings;
if (hadExcessiveChromeExtension) {
context.LighthouseRunWarnings.push(str_(UIStrings.chromeExtensionsWarning));
runWarnings = [str_(UIStrings.chromeExtensionsWarning)];
}
const summary = {wastedMs: totalBootupTime};
@ -211,6 +212,7 @@ class BootupTime extends Audit {
displayValue: totalBootupTime > 0 ?
str_(i18n.UIStrings.seconds, {timeInMs: totalBootupTime}) : '',
details,
runWarnings,
};
}
}

Просмотреть файл

@ -44,7 +44,7 @@ class FirstContentfulPaint3G extends Audit {
static async audit(artifacts, context) {
const trace = artifacts.traces[Audit.DEFAULT_PASS];
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
/** @type {LH.Config.Settings} */
/** @type {Immutable<LH.Config.Settings>} */
const settings = {...context.settings, throttlingMethod: 'simulate', throttling: regular3G};
const metricComputationData = {trace, devtoolsLog, settings};
const metricResult = await ComputedFcp.request(metricComputationData, context);

Просмотреть файл

@ -64,7 +64,7 @@ class ResourceBudget extends Audit {
}
/**
* @param {LH.Budget} budget
* @param {Immutable<LH.Budget>} budget
* @param {Record<LH.Budget.ResourceType,ResourceEntry>} summary
* @return {Array<BudgetItem>}
*/

Просмотреть файл

@ -80,7 +80,7 @@ class TimingBudget extends Audit {
}
/**
* @param {LH.Budget} budget
* @param {Immutable<LH.Budget>} budget
* @param {LH.Artifacts.TimingSummary} summary
* @return {Array<BudgetItem>}
*/

Просмотреть файл

@ -25,7 +25,8 @@ function makeComputedArtifact(computableArtifact) {
* @return {ReturnType<C['compute_']>}
*/
const request = (artifacts, context) => {
const computedCache = context.computedCache;
// NOTE: break immutability solely for this caching-controller function.
const computedCache = /** @type {Map<string, ArbitraryEqualityMap>} */ (context.computedCache);
const computedName = computableArtifact.name;
const cache = computedCache.get(computedName) || new ArbitraryEqualityMap();

Просмотреть файл

@ -12,7 +12,7 @@ const NetworkAnalysis = require('./network-analysis.js');
class LoadSimulator {
/**
* @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Config.Settings}} data
* @param {{devtoolsLog: LH.DevtoolsLog, settings: Immutable<LH.Config.Settings>}} data
* @param {LH.Audit.Context} context
* @return {Promise<Simulator>}
*/

Просмотреть файл

@ -51,7 +51,8 @@ class ResourceSummary {
'third-party': {count: 0, size: 0},
};
const budget = Budget.getMatchingBudget(context.settings.budgets, mainResourceURL);
let firstPartyHosts = /** @type {Array<string>} */ ([]);
/** @type {ReadonlyArray<string>} */
let firstPartyHosts = [];
if (budget && budget.options && budget.options.firstPartyHostnames) {
firstPartyHosts = budget.options.firstPartyHostnames;
} else {

Просмотреть файл

@ -136,9 +136,9 @@ class Budget {
* Returns the budget that applies to a given URL.
* If multiple budgets match based on thier 'path' property,
* then the last-listed of those budgets is returned.
* @param {Array<LH.Budget>|null} budgets
* @param {Immutable<Array<LH.Budget>>|null} budgets
* @param {string} url
* @return {LH.Budget | undefined} budget
* @return {Immutable<LH.Budget> | undefined} budget
*/
static getMatchingBudget(budgets, url) {
if (budgets === null) return;

Просмотреть файл

@ -273,7 +273,9 @@ async function saveAssets(artifacts, audits, pathWithBasename) {
* @return {Promise<void>}
*/
async function saveLanternNetworkData(devtoolsLog, outputPath) {
const context = /** @type {LH.Audit.Context} */ ({computedCache: new Map()});
/** @type {LH.Audit.Context} */
// @ts-ignore - the full audit context isn't needed for analysis.
const context = {computedCache: new Map()};
const networkAnalysis = await NetworkAnalysisComputed.request(devtoolsLog, context);
const lanternData = LoadSimulatorComputed.convertAnalysisToSaveableLanternData(networkAnalysis);

Просмотреть файл

@ -248,14 +248,14 @@ class Runner {
// Members of LH.Audit.Context that are shared across all audits.
const sharedAuditContext = {
settings,
LighthouseRunWarnings: runWarnings,
computedCache: new Map(),
};
// Run each audit sequentially
const auditResults = [];
for (const auditDefn of audits) {
const auditResult = await Runner._runAudit(auditDefn, artifacts, sharedAuditContext);
const auditResult = await Runner._runAudit(auditDefn, artifacts, sharedAuditContext,
runWarnings);
auditResults.push(auditResult);
}
@ -268,11 +268,12 @@ class Runner {
* Otherwise returns error audit result.
* @param {LH.Config.AuditDefn} auditDefn
* @param {LH.Artifacts} artifacts
* @param {Pick<LH.Audit.Context, 'settings'|'LighthouseRunWarnings'|'computedCache'>} sharedAuditContext
* @param {Pick<LH.Audit.Context, 'settings'|'computedCache'>} sharedAuditContext
* @param {Array<string>} runWarnings
* @return {Promise<LH.Audit.Result>}
* @private
*/
static async _runAudit(auditDefn, artifacts, sharedAuditContext) {
static async _runAudit(auditDefn, artifacts, sharedAuditContext, runWarnings) {
const audit = auditDefn.implementation;
const status = {
msg: `Auditing: ${i18n.getFormatted(audit.meta.title, 'en-US')}`,
@ -341,6 +342,8 @@ class Runner {
return narrowedArtifacts;
}, /** @type {LH.Artifacts} */ ({}));
const product = await audit.audit(narrowedArtifacts, auditContext);
runWarnings.push(...product.runWarnings || []);
auditResult = Audit.generateAuditResult(audit, product);
} catch (err) {
// Log error if it hasn't already been logged above.

Просмотреть файл

@ -49,7 +49,6 @@ async function main() {
computedCache: new Map(),
options: {},
settings: /** @type {any} */ ({}),
LighthouseRunWarnings: [],
});
const items =

Просмотреть файл

@ -113,8 +113,8 @@ variants/core-js-2-only-polyfill
3410 variants/core-js-2-only-polyfill/es6-function-name/main.bundle.min.js
variants/core-js-2-preset-env-esmodules
3567 total
2259 variants/core-js-2-preset-env-esmodules/false/main.bundle.min.js
4121 total
2813 variants/core-js-2-preset-env-esmodules/false/main.bundle.min.js
1308 variants/core-js-2-preset-env-esmodules/true/main.bundle.min.js
variants/core-js-3-only-polyfill
@ -232,13 +232,13 @@ variants/core-js-3-only-polyfill
3410 variants/core-js-3-only-polyfill/es6-function-name/main.bundle.min.js
variants/core-js-3-preset-env-esmodules
3567 total
2259 variants/core-js-3-preset-env-esmodules/false/main.bundle.min.js
4121 total
2813 variants/core-js-3-preset-env-esmodules/false/main.bundle.min.js
1308 variants/core-js-3-preset-env-esmodules/true/main.bundle.min.js
variants/only-plugin
2793 total
1152 variants/only-plugin/-babel-plugin-transform-spread/main.bundle.min.js
3347 total
1706 variants/only-plugin/-babel-plugin-transform-spread/main.bundle.min.js
827 variants/only-plugin/-babel-plugin-transform-regenerator/main.bundle.min.js
814 variants/only-plugin/-babel-plugin-transform-classes/main.bundle.min.js

Просмотреть файл

@ -654,11 +654,11 @@ describe('Runner', () => {
static get meta() {
return basicAuditMeta;
}
static audit(artifacts, context) {
context.LighthouseRunWarnings.push(warningString);
static audit() {
return {
numericValue: 5,
score: 1,
runWarnings: [warningString],
};
}
},
@ -670,31 +670,6 @@ describe('Runner', () => {
});
});
it('includes any LighthouseRunWarnings from errored audits in LHR', () => {
const warningString = 'Audit warning just before a terrible error!';
const config = new Config({
settings: {
auditMode: __dirname + '/fixtures/artifacts/empty-artifacts/',
},
audits: [
class WarningAudit extends Audit {
static get meta() {
return basicAuditMeta;
}
static audit(artifacts, context) {
context.LighthouseRunWarnings.push(warningString);
throw new Error('Terrible.');
}
},
],
});
return Runner.run(null, {config, driverMock}).then(results => {
assert.deepStrictEqual(results.lhr.runWarnings, [warningString]);
});
});
describe('lhr.runtimeError', () => {
const NO_FCP = LHError.errors.NO_FCP;
class RuntimeErrorGatherer extends Gatherer {

2
types/artifacts.d.ts поставляемый
Просмотреть файл

@ -509,7 +509,7 @@ declare global {
export interface MetricComputationDataInput {
devtoolsLog: DevtoolsLog;
trace: Trace;
settings: Config.Settings;
settings: Immutable<Config.Settings>;
simulator?: LanternSimulator;
}

8
types/audit.d.ts поставляемый
Просмотреть файл

@ -8,19 +8,17 @@ import ArbitraryEqualityMap = require('../lighthouse-core/lib/arbitrary-equality
declare global {
module LH.Audit {
export interface Context {
export type Context = Immutable<{
/** audit options */
options: Record<string, any>;
settings: Config.Settings;
/** Push to this array to add top-level warnings to the LHR. */
LighthouseRunWarnings: Array<string>;
/**
* Nested cache for already-computed computed artifacts. Keyed first on
* the computed artifact's `name` property, then on input artifact(s).
* Values are Promises resolving to the computedArtifact result.
*/
computedCache: Map<string, ArbitraryEqualityMap>;
}
}>;
export interface ScoreOptions {
scorePODR: number;
@ -85,6 +83,8 @@ declare global {
notApplicable?: boolean;
/** Extra information about the page provided by some types of audits, in one of several possible forms that can be rendered in the HTML report. */
details?: Audit.Details;
/** If an audit encounters unusual execution circumstances, strings can be put in this optional array to add top-level warnings to the LHR. */
runWarnings?: Array<string>;
}
/** The Audit.Product type for audits that do not return a `numericValue`. */

17
types/externs.d.ts поставляемый
Просмотреть файл

@ -76,6 +76,23 @@ declare global {
T[P];
};
/** Recursively makes all properties of T read-only. */
export type Immutable<T> =
T extends Function ? T :
T extends Array<infer R> ? ImmutableArray<R> :
T extends Map<infer K, infer V> ? ImmutableMap<K, V> :
T extends Set<infer M> ? ImmutableSet<M> :
T extends object ? ImmutableObject<T> :
T
// Intermediate immutable types. Prefer e.g. Immutable<Set<T>> over direct use.
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
type ImmutableObject<T> = {
readonly [K in keyof T]: Immutable<T[K]>;
};
/**
* Exclude void from T
*/