debug-server-next
Version:
Dev server for hippy-core.
200 lines (199 loc) • 8.53 kB
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.
/* eslint-disable rulesdir/no_underscored_properties */
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as Platform from '../../core/platform/platform.js';
import * as Root from '../../core/root/root.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as Workspace from '../../models/workspace/workspace.js';
import * as LighthouseReport from '../../third_party/lighthouse/report/report.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
import * as Timeline from '../timeline/timeline.js';
const UIStrings = {
/**
*@description Label for view trace button when simulated throttling is enabled
*/
viewOriginalTrace: 'View Original Trace',
/**
*@description Text of the timeline button in Lighthouse Report Renderer
*/
viewTrace: 'View Trace',
/**
*@description Help text for 'View Trace' button
*/
thePerformanceMetricsAboveAre: 'The performance metrics above are simulated and won\'t match the timings found in this trace. Disable simulated throttling in "Lighthouse Settings" if you want the timings to match.',
};
const str_ = i18n.i18n.registerUIStrings('panels/lighthouse/LighthouseReportRenderer.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const MaxLengthForLinks = 40;
export class LighthouseReportRenderer extends LighthouseReport.ReportRenderer {
constructor(dom) {
super(dom);
}
static addViewTraceButton(el, reportUIFeatures, artifacts) {
if (!artifacts || !artifacts.traces || !artifacts.traces.defaultPass) {
return;
}
const simulated = artifacts.settings.throttlingMethod === 'simulate';
const container = el.querySelector('.lh-audit-group');
if (!container) {
return;
}
const disclaimerEl = container.querySelector('.lh-metrics__disclaimer');
// If it was a PWA-only run, we'd have a trace but no perf category to add the button to
if (!disclaimerEl) {
return;
}
const defaultPassTrace = artifacts.traces.defaultPass;
const text = simulated ? i18nString(UIStrings.viewOriginalTrace) : i18nString(UIStrings.viewTrace);
const timelineButton = reportUIFeatures.addButton({
text,
onClick: onViewTraceClick,
});
if (timelineButton) {
timelineButton.classList.add('lh-button--trace');
if (simulated) {
UI.Tooltip.Tooltip.install(timelineButton, i18nString(UIStrings.thePerformanceMetricsAboveAre));
}
}
async function onViewTraceClick() {
Host.userMetrics.actionTaken(Host.UserMetrics.Action.LighthouseViewTrace);
await UI.InspectorView.InspectorView.instance().showPanel('timeline');
Timeline.TimelinePanel.TimelinePanel.instance().loadFromEvents(defaultPassTrace.traceEvents);
}
}
static async linkifyNodeDetails(el) {
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
if (!mainTarget) {
return;
}
const domModel = mainTarget.model(SDK.DOMModel.DOMModel);
if (!domModel) {
return;
}
for (const origElement of el.getElementsByClassName('lh-node')) {
const origHTMLElement = origElement;
const detailsItem = origHTMLElement.dataset;
if (!detailsItem.path) {
continue;
}
const nodeId = await domModel.pushNodeByPathToFrontend(detailsItem.path);
if (!nodeId) {
continue;
}
const node = domModel.nodeForId(nodeId);
if (!node) {
continue;
}
const element = await Common.Linkifier.Linkifier.linkify(node, { tooltip: detailsItem.snippet, preventKeyboardFocus: undefined });
UI.Tooltip.Tooltip.install(origHTMLElement, '');
const screenshotElement = origHTMLElement.querySelector('.lh-element-screenshot');
origHTMLElement.textContent = '';
if (screenshotElement) {
origHTMLElement.append(screenshotElement);
}
origHTMLElement.appendChild(element);
}
}
static async linkifySourceLocationDetails(el) {
for (const origElement of el.getElementsByClassName('lh-source-location')) {
const origHTMLElement = origElement;
const detailsItem = origHTMLElement.dataset;
if (!detailsItem.sourceUrl || !detailsItem.sourceLine || !detailsItem.sourceColumn) {
continue;
}
const url = detailsItem.sourceUrl;
const line = Number(detailsItem.sourceLine);
const column = Number(detailsItem.sourceColumn);
const element = await Components.Linkifier.Linkifier.linkifyURL(url, {
lineNumber: line,
columnNumber: column,
inlineFrameIndex: 0,
maxLength: MaxLengthForLinks,
bypassURLTrimming: undefined,
className: undefined,
preventClick: undefined,
tabStop: undefined,
text: undefined,
});
UI.Tooltip.Tooltip.install(origHTMLElement, '');
origHTMLElement.textContent = '';
origHTMLElement.appendChild(element);
}
}
static handleDarkMode(el) {
if (ThemeSupport.ThemeSupport.instance().themeName() === 'dark') {
el.classList.add('dark');
}
}
}
// @ts-expect-error https://github.com/GoogleChrome/lighthouse/issues/11628
export class LighthouseReportUIFeatures extends LighthouseReport.ReportUIFeatures {
_beforePrint;
_afterPrint;
constructor(dom) {
super(dom);
this._beforePrint = null;
this._afterPrint = null;
}
setBeforePrint(beforePrint) {
this._beforePrint = beforePrint;
}
setAfterPrint(afterPrint) {
this._afterPrint = afterPrint;
}
/**
* Returns the html that recreates this report.
*/
getReportHtml() {
this.resetUIState();
// @ts-expect-error https://github.com/GoogleChrome/lighthouse/issues/11628
return Lighthouse.ReportGenerator.generateReportHtml(this.json);
}
/**
* Downloads a file (blob) using the system dialog prompt.
*/
async _saveFile(blob) {
const domain = new Common.ParsedURL.ParsedURL(this.json.finalUrl).domain();
const sanitizedDomain = domain.replace(/[^a-z0-9.-]+/gi, '_');
const timestamp = Platform.DateUtilities.toISO8601Compact(new Date(this.json.fetchTime));
const ext = blob.type.match('json') ? '.json' : '.html';
const basename = `${sanitizedDomain}-${timestamp}${ext}`;
const text = await blob.text();
Workspace.FileManager.FileManager.instance().save(basename, text, true /* forceSaveAs */);
}
async _print() {
const document = this.getDocument();
const clonedReport = document.querySelector('.lh-root').cloneNode(true);
const printWindow = window.open('', '_blank', 'channelmode=1,status=1,resizable=1');
if (!printWindow) {
return;
}
const style = printWindow.document.createElement('style');
style.textContent = Root.Runtime.cachedResources.get('third_party/lighthouse/report-assets/report.css') || '';
printWindow.document.head.appendChild(style);
printWindow.document.body.replaceWith(clonedReport);
// Linkified nodes are shadow elements, which aren't exposed via `cloneNode`.
await LighthouseReportRenderer.linkifyNodeDetails(clonedReport);
if (this._beforePrint) {
this._beforePrint();
}
printWindow.focus();
printWindow.print();
printWindow.close();
if (this._afterPrint) {
this._afterPrint();
}
}
getDocument() {
return this._document;
}
resetUIState() {
this._resetUIState();
}
}