mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	chore: extract snapshotter from trace viewer (#5618)
This commit is contained in:
		
							parent
							
								
									af89ab7a6f
								
							
						
					
					
						commit
						2ff6d54f26
					
				
							
								
								
									
										41
									
								
								src/server/snapshot/snapshot.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/server/snapshot/snapshot.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export type NodeSnapshot =
 | 
			
		||||
  // Text node.
 | 
			
		||||
  string |
 | 
			
		||||
  // Subtree reference, "x snapshots ago, node #y". Could point to a text node.
 | 
			
		||||
  // Only nodes that are not references are counted, starting from zero, using post-order traversal.
 | 
			
		||||
  [ [number, number] ] |
 | 
			
		||||
  // Just node name.
 | 
			
		||||
  [ string ] |
 | 
			
		||||
  // Node name, attributes, child nodes.
 | 
			
		||||
  // Unfortunately, we cannot make this type definition recursive, therefore "any".
 | 
			
		||||
  [ string, { [attr: string]: string }, ...any ];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export type ResourceOverride = {
 | 
			
		||||
  url: string,
 | 
			
		||||
  sha1?: string,
 | 
			
		||||
  ref?: number
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type FrameSnapshot = {
 | 
			
		||||
  doctype?: string,
 | 
			
		||||
  html: NodeSnapshot,
 | 
			
		||||
  resourceOverrides: ResourceOverride[],
 | 
			
		||||
  viewport: { width: number, height: number },
 | 
			
		||||
};
 | 
			
		||||
@ -14,34 +14,30 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import * as trace from '../common/traceEvents';
 | 
			
		||||
import { ContextResources } from './traceModel';
 | 
			
		||||
export * as trace from '../common/traceEvents';
 | 
			
		||||
import { FrameSnapshot, NodeSnapshot } from './snapshot';
 | 
			
		||||
 | 
			
		||||
export type SerializedFrameSnapshot = {
 | 
			
		||||
export type ContextResources = Map<string, { resourceId: string, frameId: string }[]>;
 | 
			
		||||
 | 
			
		||||
export type RenderedFrameSnapshot = {
 | 
			
		||||
  html: string;
 | 
			
		||||
  resources: { [key: string]: { resourceId: string, sha1?: string } };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class FrameSnapshot {
 | 
			
		||||
  private _snapshots: trace.FrameSnapshotTraceEvent[];
 | 
			
		||||
export class SnapshotRenderer {
 | 
			
		||||
  private _snapshots: FrameSnapshot[];
 | 
			
		||||
  private _index: number;
 | 
			
		||||
  private _contextResources: ContextResources;
 | 
			
		||||
  private _frameId: string;
 | 
			
		||||
 | 
			
		||||
  constructor(frameId: string, contextResources: ContextResources, events: trace.FrameSnapshotTraceEvent[], index: number) {
 | 
			
		||||
  constructor(frameId: string, contextResources: ContextResources, snapshots: FrameSnapshot[], index: number) {
 | 
			
		||||
    this._frameId = frameId;
 | 
			
		||||
    this._contextResources = contextResources;
 | 
			
		||||
    this._snapshots = events;
 | 
			
		||||
    this._snapshots = snapshots;
 | 
			
		||||
    this._index = index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  traceEvent(): trace.FrameSnapshotTraceEvent {
 | 
			
		||||
    return this._snapshots[this._index];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serialize(): SerializedFrameSnapshot {
 | 
			
		||||
    const visit = (n: trace.NodeSnapshot, snapshotIndex: number): string => {
 | 
			
		||||
  render(): RenderedFrameSnapshot {
 | 
			
		||||
    const visit = (n: NodeSnapshot, snapshotIndex: number): string => {
 | 
			
		||||
      // Text node.
 | 
			
		||||
      if (typeof n === 'string')
 | 
			
		||||
        return escapeText(n);
 | 
			
		||||
@ -51,7 +47,7 @@ export class FrameSnapshot {
 | 
			
		||||
          // Node reference.
 | 
			
		||||
          const referenceIndex = snapshotIndex - n[0][0];
 | 
			
		||||
          if (referenceIndex >= 0 && referenceIndex < snapshotIndex) {
 | 
			
		||||
            const nodes = snapshotNodes(this._snapshots[referenceIndex].snapshot);
 | 
			
		||||
            const nodes = snapshotNodes(this._snapshots[referenceIndex]);
 | 
			
		||||
            const nodeIndex = n[0][1];
 | 
			
		||||
            if (nodeIndex >= 0 && nodeIndex < nodes.length)
 | 
			
		||||
              (n as any)._string = visit(nodes[nodeIndex], referenceIndex);
 | 
			
		||||
@ -76,7 +72,7 @@ export class FrameSnapshot {
 | 
			
		||||
      return (n as any)._string;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const snapshot = this._snapshots[this._index].snapshot;
 | 
			
		||||
    const snapshot = this._snapshots[this._index];
 | 
			
		||||
    let html = visit(snapshot.html, this._index);
 | 
			
		||||
    if (snapshot.doctype)
 | 
			
		||||
      html = `<!DOCTYPE ${snapshot.doctype}>` + html;
 | 
			
		||||
@ -88,7 +84,7 @@ export class FrameSnapshot {
 | 
			
		||||
      if (contextResource)
 | 
			
		||||
        resources[url] = { resourceId: contextResource.resourceId };
 | 
			
		||||
    }
 | 
			
		||||
    for (const o of this.traceEvent().snapshot.resourceOverrides) {
 | 
			
		||||
    for (const o of snapshot.resourceOverrides) {
 | 
			
		||||
      const resource = resources[o.url];
 | 
			
		||||
      resource.sha1 = o.sha1;
 | 
			
		||||
    }
 | 
			
		||||
@ -106,10 +102,10 @@ function escapeText(s: string): string {
 | 
			
		||||
  return s.replace(/[&<]/ug, char => (escaped as any)[char]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function snapshotNodes(snapshot: trace.FrameSnapshot): trace.NodeSnapshot[] {
 | 
			
		||||
function snapshotNodes(snapshot: FrameSnapshot): NodeSnapshot[] {
 | 
			
		||||
  if (!(snapshot as any)._nodes) {
 | 
			
		||||
    const nodes: trace.NodeSnapshot[] = [];
 | 
			
		||||
    const visit = (n: trace.NodeSnapshot) => {
 | 
			
		||||
    const nodes: NodeSnapshot[] = [];
 | 
			
		||||
    const visit = (n: NodeSnapshot) => {
 | 
			
		||||
      if (typeof n === 'string') {
 | 
			
		||||
        nodes.push(n);
 | 
			
		||||
      } else if (typeof n[0] === 'string') {
 | 
			
		||||
@ -16,14 +16,19 @@
 | 
			
		||||
 | 
			
		||||
import * as http from 'http';
 | 
			
		||||
import querystring from 'querystring';
 | 
			
		||||
import type { NetworkResourceTraceEvent } from '../common/traceEvents';
 | 
			
		||||
import type { FrameSnapshot, SerializedFrameSnapshot } from './frameSnapshot';
 | 
			
		||||
import { HttpServer } from '../../../utils/httpServer';
 | 
			
		||||
import { SnapshotRenderer, RenderedFrameSnapshot } from './snapshotRenderer';
 | 
			
		||||
import { HttpServer } from '../../utils/httpServer';
 | 
			
		||||
 | 
			
		||||
export type NetworkResponse = {
 | 
			
		||||
  contentType: string;
 | 
			
		||||
  responseHeaders: { name: string, value: string }[];
 | 
			
		||||
  responseSha1: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface SnapshotStorage {
 | 
			
		||||
  resourceContent(sha1: string): Buffer;
 | 
			
		||||
  resourceById(resourceId: string): NetworkResourceTraceEvent;
 | 
			
		||||
  snapshotByName(snapshotName: string): FrameSnapshot | undefined;
 | 
			
		||||
  resourceById(resourceId: string): NetworkResponse;
 | 
			
		||||
  snapshotByName(snapshotName: string): SnapshotRenderer | undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SnapshotServer {
 | 
			
		||||
@ -149,7 +154,7 @@ export class SnapshotServer {
 | 
			
		||||
        }
 | 
			
		||||
        if (request.mode === 'navigate') {
 | 
			
		||||
          const htmlResponse = await fetch(`/snapshot-data?snapshotName=${snapshotId}`);
 | 
			
		||||
          const { html, resources }: SerializedFrameSnapshot  = await htmlResponse.json();
 | 
			
		||||
          const { html, resources }: RenderedFrameSnapshot  = await htmlResponse.json();
 | 
			
		||||
          if (!html)
 | 
			
		||||
            return respondNotAvailable();
 | 
			
		||||
          snapshotResources.set(snapshotId, resources);
 | 
			
		||||
@ -203,7 +208,7 @@ export class SnapshotServer {
 | 
			
		||||
    response.setHeader('Content-Type', 'application/json');
 | 
			
		||||
    const parsed: any = querystring.parse(request.url!.substring(request.url!.indexOf('?') + 1));
 | 
			
		||||
    const snapshot = this._snapshotStorage.snapshotByName(parsed.snapshotName);
 | 
			
		||||
    const snapshotData: any = snapshot ? snapshot.serialize() : { html: '' };
 | 
			
		||||
    const snapshotData: any = snapshot ? snapshot.render() : { html: '' };
 | 
			
		||||
    response.end(JSON.stringify(snapshotData));
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
@ -14,15 +14,15 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { BrowserContext } from '../../browserContext';
 | 
			
		||||
import { Page } from '../../page';
 | 
			
		||||
import * as network from '../../network';
 | 
			
		||||
import { helper, RegisteredListener } from '../../helper';
 | 
			
		||||
import { debugLogger } from '../../../utils/debugLogger';
 | 
			
		||||
import { Frame } from '../../frames';
 | 
			
		||||
import { BrowserContext } from '../browserContext';
 | 
			
		||||
import { Page } from '../page';
 | 
			
		||||
import * as network from '../network';
 | 
			
		||||
import { helper, RegisteredListener } from '../helper';
 | 
			
		||||
import { debugLogger } from '../../utils/debugLogger';
 | 
			
		||||
import { Frame } from '../frames';
 | 
			
		||||
import { SnapshotData, frameSnapshotStreamer, kSnapshotBinding, kSnapshotStreamer } from './snapshotterInjected';
 | 
			
		||||
import { calculateSha1 } from '../../../utils/utils';
 | 
			
		||||
import { FrameSnapshot } from '../common/traceEvents';
 | 
			
		||||
import { calculateSha1 } from '../../utils/utils';
 | 
			
		||||
import { FrameSnapshot } from './snapshot';
 | 
			
		||||
 | 
			
		||||
export type SnapshotterResource = {
 | 
			
		||||
  pageId: string,
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import type { NodeSnapshot } from '../common/traceEvents';
 | 
			
		||||
import { NodeSnapshot } from './snapshot';
 | 
			
		||||
 | 
			
		||||
export type SnapshotData = {
 | 
			
		||||
  doctype?: string,
 | 
			
		||||
@ -15,18 +15,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { StackFrame } from '../../../common/types';
 | 
			
		||||
 | 
			
		||||
export type NodeSnapshot =
 | 
			
		||||
  // Text node.
 | 
			
		||||
  string |
 | 
			
		||||
  // Subtree reference, "x snapshots ago, node #y". Could point to a text node.
 | 
			
		||||
  // Only nodes that are not references are counted, starting from zero, using post-order traversal.
 | 
			
		||||
  [ [number, number] ] |
 | 
			
		||||
  // Just node name.
 | 
			
		||||
  [ string ] |
 | 
			
		||||
  // Node name, attributes, child nodes.
 | 
			
		||||
  // Unfortunately, we cannot make this type definition recursive, therefore "any".
 | 
			
		||||
  [ string, { [attr: string]: string }, ...any ];
 | 
			
		||||
import { FrameSnapshot } from '../../snapshot/snapshot';
 | 
			
		||||
 | 
			
		||||
export type ContextCreatedTraceEvent = {
 | 
			
		||||
  timestamp: number,
 | 
			
		||||
@ -157,16 +146,3 @@ export type TraceEvent =
 | 
			
		||||
    NavigationEvent |
 | 
			
		||||
    LoadEvent |
 | 
			
		||||
    FrameSnapshotTraceEvent;
 | 
			
		||||
 | 
			
		||||
export type ResourceOverride = {
 | 
			
		||||
  url: string,
 | 
			
		||||
  sha1?: string,
 | 
			
		||||
  ref?: number
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type FrameSnapshot = {
 | 
			
		||||
  doctype?: string,
 | 
			
		||||
  html: NodeSnapshot,
 | 
			
		||||
  resourceOverrides: ResourceOverride[],
 | 
			
		||||
  viewport: { width: number, height: number },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -15,18 +15,19 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { BrowserContext, Video } from '../../browserContext';
 | 
			
		||||
import type { SnapshotterResource as SnapshotterResource, SnapshotterBlob, SnapshotterDelegate } from './snapshotter';
 | 
			
		||||
import type { SnapshotterResource as SnapshotterResource, SnapshotterBlob, SnapshotterDelegate } from '../../snapshot/snapshotter';
 | 
			
		||||
import * as trace from '../common/traceEvents';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import * as util from 'util';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import { createGuid, getFromENV, mkdirIfNeeded, monotonicTime } from '../../../utils/utils';
 | 
			
		||||
import { Page } from '../../page';
 | 
			
		||||
import { Snapshotter } from './snapshotter';
 | 
			
		||||
import { Snapshotter } from '../../snapshot/snapshotter';
 | 
			
		||||
import { helper, RegisteredListener } from '../../helper';
 | 
			
		||||
import { Dialog } from '../../dialog';
 | 
			
		||||
import { Frame, NavigationEvent } from '../../frames';
 | 
			
		||||
import { CallMetadata, InstrumentationListener, SdkObject } from '../../instrumentation';
 | 
			
		||||
import { FrameSnapshot } from '../../snapshot/snapshot';
 | 
			
		||||
 | 
			
		||||
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
 | 
			
		||||
const fsAppendFileAsync = util.promisify(fs.appendFile.bind(fs));
 | 
			
		||||
@ -133,7 +134,7 @@ class ContextTracer implements SnapshotterDelegate {
 | 
			
		||||
    this._appendTraceEvent(event);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onFrameSnapshot(frame: Frame, frameUrl: string, snapshot: trace.FrameSnapshot, snapshotId?: string): void {
 | 
			
		||||
  onFrameSnapshot(frame: Frame, frameUrl: string, snapshot: FrameSnapshot, snapshotId?: string): void {
 | 
			
		||||
    const event: trace.FrameSnapshotTraceEvent = {
 | 
			
		||||
      timestamp: monotonicTime(),
 | 
			
		||||
      type: 'snapshot',
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ import path from 'path';
 | 
			
		||||
import * as playwright from '../../../..';
 | 
			
		||||
import * as util from 'util';
 | 
			
		||||
import { ActionEntry, ContextEntry, TraceModel } from './traceModel';
 | 
			
		||||
import { SnapshotServer } from './snapshotServer';
 | 
			
		||||
import { SnapshotServer } from '../../snapshot/snapshotServer';
 | 
			
		||||
 | 
			
		||||
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
 | 
			
		||||
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
import { createGuid } from '../../../utils/utils';
 | 
			
		||||
import * as trace from '../common/traceEvents';
 | 
			
		||||
import { FrameSnapshot } from './frameSnapshot';
 | 
			
		||||
import { ContextResources, SnapshotRenderer } from '../../snapshot/snapshotRenderer';
 | 
			
		||||
export * as trace from '../common/traceEvents';
 | 
			
		||||
 | 
			
		||||
export class TraceModel {
 | 
			
		||||
@ -152,16 +152,16 @@ export class TraceModel {
 | 
			
		||||
    return { contextEntry, pageEntry };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  findSnapshotById(pageId: string, frameId: string, snapshotId: string): FrameSnapshot | undefined {
 | 
			
		||||
  findSnapshotById(pageId: string, frameId: string, snapshotId: string): SnapshotRenderer | undefined {
 | 
			
		||||
    const { pageEntry, contextEntry } = this.pageEntries.get(pageId)!;
 | 
			
		||||
    const frameSnapshots = pageEntry.snapshotsByFrameId[frameId];
 | 
			
		||||
    for (let index = 0; index < frameSnapshots.length; index++) {
 | 
			
		||||
      if (frameSnapshots[index].snapshotId === snapshotId)
 | 
			
		||||
        return new FrameSnapshot(frameId, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, index);
 | 
			
		||||
        return new SnapshotRenderer(frameId, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots.map(fs => fs.snapshot), index);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  findSnapshotByTime(pageId: string, frameId: string, timestamp: number): FrameSnapshot | undefined {
 | 
			
		||||
  findSnapshotByTime(pageId: string, frameId: string, timestamp: number): SnapshotRenderer | undefined {
 | 
			
		||||
    const { pageEntry, contextEntry } = this.pageEntries.get(pageId)!;
 | 
			
		||||
    const frameSnapshots = pageEntry.snapshotsByFrameId[frameId];
 | 
			
		||||
    let snapshotIndex = -1;
 | 
			
		||||
@ -170,7 +170,7 @@ export class TraceModel {
 | 
			
		||||
      if (timestamp && snapshot.timestamp <= timestamp)
 | 
			
		||||
        snapshotIndex = index;
 | 
			
		||||
    }
 | 
			
		||||
    return snapshotIndex >= 0 ? new FrameSnapshot(frameId, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots, snapshotIndex) : undefined;
 | 
			
		||||
    return snapshotIndex >= 0 ? new SnapshotRenderer(frameId, this.contextResources.get(contextEntry.created.contextId)!, frameSnapshots.map(fs => fs.snapshot), snapshotIndex) : undefined;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -183,8 +183,6 @@ export type ContextEntry = {
 | 
			
		||||
  pages: PageEntry[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ContextResources = Map<string, { resourceId: string, frameId: string }[]>;
 | 
			
		||||
 | 
			
		||||
export type InterestingPageEvent = trace.DialogOpenedEvent | trace.DialogClosedEvent | trace.NavigationEvent | trace.LoadEvent;
 | 
			
		||||
 | 
			
		||||
export type PageEntry = {
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,9 @@ import * as util from 'util';
 | 
			
		||||
import { ScreenshotGenerator } from './screenshotGenerator';
 | 
			
		||||
import { TraceModel } from './traceModel';
 | 
			
		||||
import { NetworkResourceTraceEvent, TraceEvent } from '../common/traceEvents';
 | 
			
		||||
import { SnapshotServer, SnapshotStorage } from './snapshotServer';
 | 
			
		||||
import { ServerRouteHandler, HttpServer } from '../../../utils/httpServer';
 | 
			
		||||
import { FrameSnapshot } from './frameSnapshot';
 | 
			
		||||
import { SnapshotServer, SnapshotStorage } from '../../snapshot/snapshotServer';
 | 
			
		||||
import { SnapshotRenderer } from '../../snapshot/snapshotRenderer';
 | 
			
		||||
 | 
			
		||||
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
 | 
			
		||||
 | 
			
		||||
@ -146,7 +146,7 @@ class TraceViewer implements SnapshotStorage {
 | 
			
		||||
    return traceModel.resourceById.get(resourceId)!;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  snapshotByName(snapshotName: string): FrameSnapshot | undefined {
 | 
			
		||||
  snapshotByName(snapshotName: string): SnapshotRenderer | undefined {
 | 
			
		||||
    const traceModel = this._document!.model;
 | 
			
		||||
    const parsed = parseSnapshotName(snapshotName);
 | 
			
		||||
    const snapshot = parsed.snapshotId ? traceModel.findSnapshotById(parsed.pageId, parsed.frameId, parsed.snapshotId) : traceModel.findSnapshotByTime(parsed.pageId, parsed.frameId, parsed.timestamp!);
 | 
			
		||||
 | 
			
		||||
@ -158,8 +158,9 @@ DEPS['src/server/supplements/recorder/recorderApp.ts'] = ['src/common/', 'src/ut
 | 
			
		||||
DEPS['src/utils/'] = ['src/common/'];
 | 
			
		||||
 | 
			
		||||
// Trace viewer
 | 
			
		||||
DEPS['src/server/trace/recorder/'] = ['src/server/trace/common/', ...DEPS['src/server/']];
 | 
			
		||||
DEPS['src/server/trace/viewer/'] = ['src/server/trace/common/', ...DEPS['src/server/']];
 | 
			
		||||
DEPS['src/server/trace/common/'] = ['src/server/snapshot/', ...DEPS['src/server/']];
 | 
			
		||||
DEPS['src/server/trace/recorder/'] = ['src/server/trace/common/', ...DEPS['src/server/trace/common/']];
 | 
			
		||||
DEPS['src/server/trace/viewer/'] = ['src/server/trace/common/', ...DEPS['src/server/trace/common/']];
 | 
			
		||||
 | 
			
		||||
checkDeps().catch(e => {
 | 
			
		||||
  console.error(e && e.stack ? e.stack : e);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user