chore: simplify overrides management in trace viewer (#5606)
This commit is contained in:
parent
0102e080f6
commit
5ae2661134
|
|
@ -15,23 +15,25 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as trace from '../common/traceEvents';
|
import * as trace from '../common/traceEvents';
|
||||||
import { ContextEntry } from './traceModel';
|
import { ContextEntry, ContextResources } from './traceModel';
|
||||||
export * as trace from '../common/traceEvents';
|
export * as trace from '../common/traceEvents';
|
||||||
|
|
||||||
export type SerializedFrameSnapshot = {
|
export type SerializedFrameSnapshot = {
|
||||||
html: string;
|
html: string;
|
||||||
resourcesByUrl: { [key: string]: { resourceId: string, frameId: string }[] };
|
resources: { [key: string]: { resourceId: string, sha1?: string } };
|
||||||
overriddenUrls: { [key: string]: boolean };
|
|
||||||
resourceOverrides: { [key: string]: string };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FrameSnapshot {
|
export class FrameSnapshot {
|
||||||
private _snapshots: trace.FrameSnapshotTraceEvent[];
|
private _snapshots: trace.FrameSnapshotTraceEvent[];
|
||||||
private _index: number;
|
private _index: number;
|
||||||
contextEntry: ContextEntry;
|
private _contextEntry: ContextEntry;
|
||||||
|
private _contextResources: ContextResources;
|
||||||
|
private _frameId: string;
|
||||||
|
|
||||||
constructor(contextEntry: ContextEntry, events: trace.FrameSnapshotTraceEvent[], index: number) {
|
constructor(frameId: string, contextEntry: ContextEntry, contextResources: ContextResources, events: trace.FrameSnapshotTraceEvent[], index: number) {
|
||||||
this.contextEntry = contextEntry;
|
this._frameId = frameId;
|
||||||
|
this._contextEntry = contextEntry;
|
||||||
|
this._contextResources = contextResources;
|
||||||
this._snapshots = events;
|
this._snapshots = events;
|
||||||
this._index = index;
|
this._index = index;
|
||||||
}
|
}
|
||||||
|
|
@ -80,14 +82,19 @@ export class FrameSnapshot {
|
||||||
let html = visit(snapshot.html, this._index);
|
let html = visit(snapshot.html, this._index);
|
||||||
if (snapshot.doctype)
|
if (snapshot.doctype)
|
||||||
html = `<!DOCTYPE ${snapshot.doctype}>` + html;
|
html = `<!DOCTYPE ${snapshot.doctype}>` + html;
|
||||||
html += `<script>${this.contextEntry.created.snapshotScript}</script>`;
|
html += `<script>${this._contextEntry.created.snapshotScript}</script>`;
|
||||||
|
|
||||||
const resourcesByUrl = this.contextEntry.resourcesByUrl;
|
const resources: { [key: string]: { resourceId: string, sha1?: string } } = {};
|
||||||
const overriddenUrls = this.contextEntry.overriddenUrls;
|
for (const [url, contextResources] of this._contextResources) {
|
||||||
const resourceOverrides: any = {};
|
const contextResource = contextResources.find(r => r.frameId === this._frameId) || contextResources[0];
|
||||||
for (const o of this._snapshots[this._index].snapshot.resourceOverrides)
|
if (contextResource)
|
||||||
resourceOverrides[o.url] = o.sha1;
|
resources[url] = { resourceId: contextResource.resourceId };
|
||||||
return { html, resourcesByUrl, overriddenUrls: overriddenUrls, resourceOverrides };
|
}
|
||||||
|
for (const o of this.traceEvent().snapshot.resourceOverrides) {
|
||||||
|
const resource = resources[o.url];
|
||||||
|
resource.sha1 = o.sha1;
|
||||||
|
}
|
||||||
|
return { html, resources };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import path from 'path';
|
||||||
import querystring from 'querystring';
|
import querystring from 'querystring';
|
||||||
import type { TraceModel } from './traceModel';
|
import type { TraceModel } from './traceModel';
|
||||||
import { TraceServer } from './traceServer';
|
import { TraceServer } from './traceServer';
|
||||||
|
import type { SerializedFrameSnapshot } from './frameSnapshot';
|
||||||
|
|
||||||
export class SnapshotServer {
|
export class SnapshotServer {
|
||||||
private _resourcesDir: string | undefined;
|
private _resourcesDir: string | undefined;
|
||||||
|
|
@ -104,9 +105,7 @@ export class SnapshotServer {
|
||||||
|
|
||||||
private _serveServiceWorker(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
private _serveServiceWorker(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
||||||
function serviceWorkerMain(self: any /* ServiceWorkerGlobalScope */) {
|
function serviceWorkerMain(self: any /* ServiceWorkerGlobalScope */) {
|
||||||
const pageToResourcesByUrl = new Map<string, { [key: string]: { resourceId: string, frameId: string }[] }>();
|
const snapshotResources = new Map<string, { [key: string]: { resourceId?: string, sha1?: string } }>();
|
||||||
const pageToOverriddenUrls = new Map<string, { [key: string]: boolean }>();
|
|
||||||
const snapshotToResourceOverrides = new Map<string, { [key: string]: string | undefined }>();
|
|
||||||
|
|
||||||
self.addEventListener('install', function(event: any) {
|
self.addEventListener('install', function(event: any) {
|
||||||
});
|
});
|
||||||
|
|
@ -171,28 +170,22 @@ export class SnapshotServer {
|
||||||
|
|
||||||
if (request.mode === 'navigate') {
|
if (request.mode === 'navigate') {
|
||||||
const htmlResponse = await fetch(`/snapshot-data?pageId=${parsed.pageId}&snapshotId=${parsed.snapshotId || ''}×tamp=${parsed.timestamp || ''}&frameId=${parsed.frameId || ''}`);
|
const htmlResponse = await fetch(`/snapshot-data?pageId=${parsed.pageId}&snapshotId=${parsed.snapshotId || ''}×tamp=${parsed.timestamp || ''}&frameId=${parsed.frameId || ''}`);
|
||||||
const { html, resourcesByUrl, overriddenUrls, resourceOverrides } = await htmlResponse.json();
|
const { html, resources }: SerializedFrameSnapshot = await htmlResponse.json();
|
||||||
if (!html)
|
if (!html)
|
||||||
return respondNotAvailable();
|
return respondNotAvailable();
|
||||||
pageToResourcesByUrl.set(parsed.pageId, resourcesByUrl);
|
snapshotResources.set(parsed.snapshotId + '@' + parsed.timestamp, resources);
|
||||||
pageToOverriddenUrls.set(parsed.pageId, overriddenUrls);
|
|
||||||
snapshotToResourceOverrides.set(parsed.snapshotId + '@' + parsed.timestamp, resourceOverrides);
|
|
||||||
const response = new Response(html, { status: 200, headers: { 'Content-Type': 'text/html' } });
|
const response = new Response(html, { status: 200, headers: { 'Content-Type': 'text/html' } });
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourcesByUrl = pageToResourcesByUrl.get(parsed.pageId);
|
const resources = snapshotResources.get(parsed.snapshotId + '@' + parsed.timestamp)!;
|
||||||
const overriddenUrls = pageToOverriddenUrls.get(parsed.pageId);
|
|
||||||
const resourceOverrides = snapshotToResourceOverrides.get(parsed.snapshotId + '@' + parsed.timestamp);
|
|
||||||
const urlWithoutHash = removeHash(request.url);
|
const urlWithoutHash = removeHash(request.url);
|
||||||
const resourcesWithUrl = resourcesByUrl?.[urlWithoutHash] || [];
|
const resource = resources[urlWithoutHash];
|
||||||
const resource = resourcesWithUrl.find(r => r.frameId === parsed.frameId) || resourcesWithUrl[0];
|
|
||||||
if (!resource)
|
if (!resource)
|
||||||
return respond404();
|
return respond404();
|
||||||
|
|
||||||
const overrideSha1 = resourceOverrides?.[urlWithoutHash];
|
const fetchUrl = resource.sha1 ?
|
||||||
const fetchUrl = overrideSha1 ?
|
`/resources/${resource.resourceId}/override/${resource.sha1}` :
|
||||||
`/resources/${resource.resourceId}/override/${overrideSha1}` :
|
|
||||||
`/resources/${resource.resourceId}`;
|
`/resources/${resource.resourceId}`;
|
||||||
const fetchedResponse = await fetch(fetchUrl);
|
const fetchedResponse = await fetch(fetchUrl);
|
||||||
const headers = new Headers(fetchedResponse.headers);
|
const headers = new Headers(fetchedResponse.headers);
|
||||||
|
|
@ -201,7 +194,7 @@ export class SnapshotServer {
|
||||||
// as the original request url.
|
// as the original request url.
|
||||||
// Response url turns into resource base uri that is used to resolve
|
// Response url turns into resource base uri that is used to resolve
|
||||||
// relative links, e.g. url(/foo/bar) in style sheets.
|
// relative links, e.g. url(/foo/bar) in style sheets.
|
||||||
if (overriddenUrls?.[urlWithoutHash]) {
|
if (resource.sha1) {
|
||||||
// No cache, so that we refetch overridden resources.
|
// No cache, so that we refetch overridden resources.
|
||||||
headers.set('Cache-Control', 'no-cache');
|
headers.set('Cache-Control', 'no-cache');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export class TraceModel {
|
||||||
contextEntries = new Map<string, ContextEntry>();
|
contextEntries = new Map<string, ContextEntry>();
|
||||||
pageEntries = new Map<string, { contextEntry: ContextEntry, pageEntry: PageEntry }>();
|
pageEntries = new Map<string, { contextEntry: ContextEntry, pageEntry: PageEntry }>();
|
||||||
resourceById = new Map<string, trace.NetworkResourceTraceEvent>();
|
resourceById = new Map<string, trace.NetworkResourceTraceEvent>();
|
||||||
|
contextResources = new Map<string, ContextResources>();
|
||||||
|
|
||||||
appendEvents(events: trace.TraceEvent[]) {
|
appendEvents(events: trace.TraceEvent[]) {
|
||||||
for (const event of events)
|
for (const event of events)
|
||||||
|
|
@ -39,9 +40,8 @@ export class TraceModel {
|
||||||
created: event,
|
created: event,
|
||||||
destroyed: undefined as any,
|
destroyed: undefined as any,
|
||||||
pages: [],
|
pages: [],
|
||||||
resourcesByUrl: {},
|
|
||||||
overriddenUrls: {}
|
|
||||||
});
|
});
|
||||||
|
this.contextResources.set(event.contextId, new Map());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'context-destroyed': {
|
case 'context-destroyed': {
|
||||||
|
|
@ -104,14 +104,12 @@ export class TraceModel {
|
||||||
pageEntry.snapshotsByFrameId[event.frameId] = snapshots;
|
pageEntry.snapshotsByFrameId[event.frameId] = snapshots;
|
||||||
}
|
}
|
||||||
snapshots.push(event);
|
snapshots.push(event);
|
||||||
const contextEntry = this.contextEntries.get(event.contextId)!;
|
|
||||||
for (const override of event.snapshot.resourceOverrides) {
|
for (const override of event.snapshot.resourceOverrides) {
|
||||||
if (override.ref) {
|
if (override.ref) {
|
||||||
const refOverride = snapshots[snapshots.length - 1 - override.ref]?.snapshot.resourceOverrides.find(o => o.url === override.url);
|
const refOverride = snapshots[snapshots.length - 1 - override.ref]?.snapshot.resourceOverrides.find(o => o.url === override.url);
|
||||||
override.sha1 = refOverride?.sha1;
|
override.sha1 = refOverride?.sha1;
|
||||||
delete override.ref;
|
delete override.ref;
|
||||||
}
|
}
|
||||||
contextEntry.overriddenUrls[override.url] = true;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -122,11 +120,11 @@ export class TraceModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
appendResource(event: trace.NetworkResourceTraceEvent) {
|
appendResource(event: trace.NetworkResourceTraceEvent) {
|
||||||
const contextEntry = this.contextEntries.get(event.contextId)!;
|
const contextResources = this.contextResources.get(event.contextId)!;
|
||||||
let responseEvents = contextEntry.resourcesByUrl[event.url];
|
let responseEvents = contextResources.get(event.url);
|
||||||
if (!responseEvents) {
|
if (!responseEvents) {
|
||||||
responseEvents = [];
|
responseEvents = [];
|
||||||
contextEntry.resourcesByUrl[event.url] = responseEvents;
|
contextResources.set(event.url, responseEvents);
|
||||||
}
|
}
|
||||||
responseEvents.push({ frameId: event.frameId, resourceId: event.resourceId });
|
responseEvents.push({ frameId: event.frameId, resourceId: event.resourceId });
|
||||||
this.resourceById.set(event.resourceId, event);
|
this.resourceById.set(event.resourceId, event);
|
||||||
|
|
@ -159,7 +157,7 @@ export class TraceModel {
|
||||||
const frameSnapshots = pageEntry.snapshotsByFrameId[frameId];
|
const frameSnapshots = pageEntry.snapshotsByFrameId[frameId];
|
||||||
for (let index = 0; index < frameSnapshots.length; index++) {
|
for (let index = 0; index < frameSnapshots.length; index++) {
|
||||||
if (frameSnapshots[index].snapshotId === snapshotId)
|
if (frameSnapshots[index].snapshotId === snapshotId)
|
||||||
return new FrameSnapshot(contextEntry, frameSnapshots, index);
|
return new FrameSnapshot(frameId, contextEntry, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +170,7 @@ export class TraceModel {
|
||||||
if (timestamp && snapshot.timestamp <= timestamp)
|
if (timestamp && snapshot.timestamp <= timestamp)
|
||||||
snapshotIndex = index;
|
snapshotIndex = index;
|
||||||
}
|
}
|
||||||
return snapshotIndex >= 0 ? new FrameSnapshot(contextEntry, frameSnapshots, snapshotIndex) : undefined;
|
return snapshotIndex >= 0 ? new FrameSnapshot(frameId, contextEntry, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, snapshotIndex) : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,10 +181,10 @@ export type ContextEntry = {
|
||||||
created: trace.ContextCreatedTraceEvent;
|
created: trace.ContextCreatedTraceEvent;
|
||||||
destroyed: trace.ContextDestroyedTraceEvent;
|
destroyed: trace.ContextDestroyedTraceEvent;
|
||||||
pages: PageEntry[];
|
pages: PageEntry[];
|
||||||
resourcesByUrl: { [key: string]: { resourceId: string, frameId: string }[] };
|
|
||||||
overriddenUrls: { [key: string]: boolean };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ContextResources = Map<string, { resourceId: string, frameId: string }[]>;
|
||||||
|
|
||||||
export type InterestingPageEvent = trace.DialogOpenedEvent | trace.DialogClosedEvent | trace.NavigationEvent | trace.LoadEvent;
|
export type InterestingPageEvent = trace.DialogOpenedEvent | trace.DialogClosedEvent | trace.NavigationEvent | trace.LoadEvent;
|
||||||
|
|
||||||
export type PageEntry = {
|
export type PageEntry = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue