mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-10 13:44:39 +08:00
This reverts commit 28abe7802899b037a176426f883c750fec5a6d24. Bug: 772558, 846211,846551 Change-Id: Ib782b1fb5ee737f31deaa94630fb2bb1021b579b Reviewed-on: https://chromium-review.googlesource.com/1077597 Reviewed-by: Pavel Feldman <pfeldman@chromium.org> Reviewed-by: Patrick Hulce <phulce@chromium.org> Commit-Queue: Paul Irish <paulirish@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#563121} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 8405e18c05b9e5a1c714db1e204de6aaae3be24d
303 lines
9.4 KiB
JavaScript
303 lines
9.4 KiB
JavaScript
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
/**
|
|
* @implements {SDK.SDKModelObserver<!SDK.ServiceWorkerManager>}
|
|
* @unrestricted
|
|
*/
|
|
Audits2.AuditController = class extends Common.Object {
|
|
constructor(protocolService) {
|
|
super();
|
|
|
|
protocolService.registerStatusCallback(
|
|
message => this.dispatchEventToListeners(Audits2.Events.AuditProgressChanged, {message}));
|
|
|
|
for (const preset of Audits2.Presets)
|
|
preset.setting.addChangeListener(this.recomputePageAuditability.bind(this));
|
|
|
|
SDK.targetManager.observeModels(SDK.ServiceWorkerManager, this);
|
|
SDK.targetManager.addEventListener(
|
|
SDK.TargetManager.Events.InspectedURLChanged, this.recomputePageAuditability, this);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!SDK.ServiceWorkerManager} serviceWorkerManager
|
|
*/
|
|
modelAdded(serviceWorkerManager) {
|
|
if (this._manager)
|
|
return;
|
|
|
|
this._manager = serviceWorkerManager;
|
|
this._serviceWorkerListeners = [
|
|
this._manager.addEventListener(
|
|
SDK.ServiceWorkerManager.Events.RegistrationUpdated, this.recomputePageAuditability, this),
|
|
this._manager.addEventListener(
|
|
SDK.ServiceWorkerManager.Events.RegistrationDeleted, this.recomputePageAuditability, this),
|
|
];
|
|
|
|
this.recomputePageAuditability();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!SDK.ServiceWorkerManager} serviceWorkerManager
|
|
*/
|
|
modelRemoved(serviceWorkerManager) {
|
|
if (this._manager !== serviceWorkerManager)
|
|
return;
|
|
|
|
Common.EventTarget.removeEventListeners(this._serviceWorkerListeners);
|
|
this._manager = null;
|
|
this.recomputePageAuditability();
|
|
}
|
|
|
|
/**
|
|
* @return {boolean}
|
|
*/
|
|
_hasActiveServiceWorker() {
|
|
if (!this._manager)
|
|
return false;
|
|
|
|
const mainTarget = this._manager.target();
|
|
if (!mainTarget)
|
|
return false;
|
|
|
|
const inspectedURL = mainTarget.inspectedURL().asParsedURL();
|
|
const inspectedOrigin = inspectedURL && inspectedURL.securityOrigin();
|
|
for (const registration of this._manager.registrations().values()) {
|
|
if (registration.securityOrigin !== inspectedOrigin)
|
|
continue;
|
|
|
|
for (const version of registration.versions.values()) {
|
|
if (version.controlledClients.length > 1)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return {boolean}
|
|
*/
|
|
_hasAtLeastOneCategory() {
|
|
return Audits2.Presets.some(preset => preset.setting.get());
|
|
}
|
|
|
|
/**
|
|
* @return {?string}
|
|
*/
|
|
_unauditablePageMessage() {
|
|
if (!this._manager)
|
|
return null;
|
|
|
|
const mainTarget = this._manager.target();
|
|
const inspectedURL = mainTarget && mainTarget.inspectedURL();
|
|
if (inspectedURL && !/^(http|chrome-extension)/.test(inspectedURL)) {
|
|
return Common.UIString(
|
|
'Can only audit HTTP/HTTPS pages and Chrome extensions. ' +
|
|
'Navigate to a different page to start an audit.');
|
|
}
|
|
|
|
// Audits don't work on most undockable targets (extension popup pages, remote debugging, etc).
|
|
// However, the tests run in a content shell which is not dockable yet audits just fine,
|
|
// so disable this check when under test.
|
|
if (!Host.isUnderTest() && !Runtime.queryParam('can_dock'))
|
|
return Common.UIString('Can only audit tabs. Navigate to this page in a separate tab to start an audit.');
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return {!Promise<string>}
|
|
*/
|
|
async _evaluateInspectedURL() {
|
|
const mainTarget = this._manager.target();
|
|
const runtimeModel = mainTarget.model(SDK.RuntimeModel);
|
|
const executionContext = runtimeModel && runtimeModel.defaultExecutionContext();
|
|
let inspectedURL = mainTarget.inspectedURL();
|
|
if (!executionContext)
|
|
return inspectedURL;
|
|
|
|
// Evaluate location.href for a more specific URL than inspectedURL provides so that SPA hash navigation routes
|
|
// will be respected and audited.
|
|
try {
|
|
const result = await executionContext.evaluate(
|
|
{
|
|
expression: 'window.location.href',
|
|
objectGroup: 'audits',
|
|
includeCommandLineAPI: false,
|
|
silent: false,
|
|
returnByValue: true,
|
|
generatePreview: false
|
|
},
|
|
/* userGesture */ false, /* awaitPromise */ false);
|
|
if (!result.exceptionDetails && result.object) {
|
|
inspectedURL = result.object.value;
|
|
result.object.release();
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
|
|
return inspectedURL;
|
|
}
|
|
|
|
/**
|
|
* @return {!Object}
|
|
*/
|
|
getFlags() {
|
|
const flags = {};
|
|
for (const runtimeSetting of Audits2.RuntimeSettings)
|
|
runtimeSetting.setFlags(flags, runtimeSetting.setting.get());
|
|
return flags;
|
|
}
|
|
|
|
/**
|
|
* @return {!Array<string>}
|
|
*/
|
|
getCategoryIDs() {
|
|
const categoryIDs = [];
|
|
for (const preset of Audits2.Presets) {
|
|
if (preset.setting.get())
|
|
categoryIDs.push(preset.configID);
|
|
}
|
|
return categoryIDs;
|
|
}
|
|
|
|
/**
|
|
* @param {{force: boolean}=} options
|
|
* @return {!Promise<string>}
|
|
*/
|
|
async getInspectedURL(options) {
|
|
if (options && options.force || !this._inspectedURL)
|
|
this._inspectedURL = await this._evaluateInspectedURL();
|
|
return this._inspectedURL;
|
|
}
|
|
|
|
recomputePageAuditability() {
|
|
const hasActiveServiceWorker = this._hasActiveServiceWorker();
|
|
const hasAtLeastOneCategory = this._hasAtLeastOneCategory();
|
|
const unauditablePageMessage = this._unauditablePageMessage();
|
|
|
|
let helpText = '';
|
|
if (hasActiveServiceWorker) {
|
|
helpText = Common.UIString(
|
|
'Multiple tabs are being controlled by the same service worker. ' +
|
|
'Close your other tabs on the same origin to audit this page.');
|
|
} else if (!hasAtLeastOneCategory) {
|
|
helpText = Common.UIString('At least one category must be selected.');
|
|
} else if (unauditablePageMessage) {
|
|
helpText = unauditablePageMessage;
|
|
}
|
|
|
|
this.dispatchEventToListeners(Audits2.Events.PageAuditabilityChanged, {helpText});
|
|
}
|
|
};
|
|
|
|
|
|
/** @typedef {{setting: !Common.Setting, configID: string, title: string, description: string}} */
|
|
Audits2.Preset;
|
|
|
|
/** @type {!Array.<!Audits2.Preset>} */
|
|
Audits2.Presets = [
|
|
// configID maps to Lighthouse's Object.keys(config.categories)[0] value
|
|
{
|
|
setting: Common.settings.createSetting('audits2.cat_perf', true),
|
|
configID: 'performance',
|
|
title: 'Performance',
|
|
description: 'How long does this app take to show content and become usable'
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.cat_pwa', true),
|
|
configID: 'pwa',
|
|
title: 'Progressive Web App',
|
|
description: 'Does this page meet the standard of a Progressive Web App'
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.cat_best_practices', true),
|
|
configID: 'best-practices',
|
|
title: 'Best practices',
|
|
description: 'Does this page follow best practices for modern web development'
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.cat_a11y', true),
|
|
configID: 'accessibility',
|
|
title: 'Accessibility',
|
|
description: 'Is this page usable by people with disabilities or impairments'
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.cat_seo', true),
|
|
configID: 'seo',
|
|
title: 'SEO',
|
|
description: 'Is this page optimized for search engine results ranking'
|
|
},
|
|
];
|
|
|
|
/** @typedef {{setting: !Common.Setting, description: string, setFlags: function(!Object, string), options: (!Array|undefined), title: (string|undefined)}} */
|
|
Audits2.RuntimeSetting;
|
|
|
|
/** @type {!Array.<!Audits2.RuntimeSetting>} */
|
|
Audits2.RuntimeSettings = [
|
|
{
|
|
setting: Common.settings.createSetting('audits2.device_type', 'mobile'),
|
|
description: ls`Apply mobile emulation during auditing`,
|
|
setFlags: (flags, value) => {
|
|
flags.disableDeviceEmulation = value === 'desktop';
|
|
},
|
|
options: [
|
|
{label: ls`Mobile`, value: 'mobile'},
|
|
{label: ls`Desktop`, value: 'desktop'},
|
|
],
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.throttling', 'default'),
|
|
setFlags: (flags, value) => {
|
|
switch (value) {
|
|
case 'devtools':
|
|
flags.throttlingMethod = 'devtools';
|
|
break;
|
|
case 'off':
|
|
flags.throttlingMethod = 'provided';
|
|
break;
|
|
default:
|
|
flags.throttlingMethod = 'simulate';
|
|
}
|
|
},
|
|
options: [
|
|
{
|
|
label: ls`Simulated Fast 3G, 4x CPU Slowdown`,
|
|
value: 'default',
|
|
title: 'Throttling is simulated, resulting in faster audit runs with similar measurement accuracy'
|
|
},
|
|
{
|
|
label: ls`Applied Fast 3G, 4x CPU Slowdown`,
|
|
value: 'devtools',
|
|
title: 'Typical DevTools throttling, with actual traffic shaping and CPU slowdown applied'
|
|
},
|
|
{
|
|
label: ls`No throttling`,
|
|
value: 'off',
|
|
title: 'No network or CPU throttling used. (Useful when not evaluating performance)'
|
|
},
|
|
],
|
|
},
|
|
{
|
|
setting: Common.settings.createSetting('audits2.clear_storage', true),
|
|
title: ls`Clear storage`,
|
|
description: ls`Reset storage (localStorage, IndexedDB, etc) before auditing. (Good for performance & PWA testing)`,
|
|
setFlags: (flags, value) => {
|
|
flags.disableStorageReset = !value;
|
|
},
|
|
},
|
|
];
|
|
|
|
Audits2.Events = {
|
|
PageAuditabilityChanged: Symbol('PageAuditabilityChanged'),
|
|
AuditProgressChanged: Symbol('AuditProgressChanged'),
|
|
RequestAuditStart: Symbol('RequestAuditStart'),
|
|
RequestAuditCancel: Symbol('RequestAuditCancel'),
|
|
};
|