Skip to content

Commit fad263f

Browse files
authored
perf: initialize trace view in the orchestrator once per worker (#10984)
1 parent f5eee72 commit fad263f

5 files changed

Lines changed: 63 additions & 7 deletions

File tree

packages/browser/src/client/orchestrator.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ export class IframeOrchestrator {
2727
constructor() {
2828
debug('init orchestrator', getBrowserState().sessionId)
2929

30+
if (getConfig().browser.traceView.enabled) {
31+
const domSnapshot = import('rrweb-snapshot')
32+
// a load failure surfaces in the tester that awaits this
33+
domSnapshot.catch(() => {})
34+
getBrowserState().browserTraceDomSnapshotPromise = domSnapshot
35+
}
36+
3037
const otelConfig = getBrowserState().config.experimental.openTelemetry
3138
this.traces = new Traces({
3239
enabled: !!(otelConfig?.enabled && otelConfig.browserSdkPath),

packages/browser/src/client/tester/runner.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
} from 'vitest/internal/browser'
3030
import { createStackString, parseStacktrace } from '../../../../utils/src/source-map'
3131
import { getTestName } from '../../../../vitest/src/utils/tasks'
32-
import { getBrowserState, getWorkerState, moduleRunner, now } from '../utils'
32+
import { getBrowserState, getOrchestratorState, getWorkerState, moduleRunner, now } from '../utils'
3333
import { rpc } from './rpc'
3434
import { VitestBrowserSnapshotEnvironment } from './snapshot'
3535
import { recordBrowserTraceEntry } from './trace'
@@ -92,7 +92,7 @@ function createBrowserRunner(
9292
return
9393
}
9494
if (shouldTraceView) {
95-
getBrowserState().browserTraceDomSnapshot = await import('rrweb-snapshot')
95+
getBrowserState().browserTraceDomSnapshot ??= await getOrchestratorState().browserTraceDomSnapshotPromise
9696
getBrowserState().browserTraceAttempts.set(test.id, { retry, repeats, startTime: now() })
9797
}
9898
else {

packages/browser/src/client/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ export interface BrowserRunnerState {
9898
browserTraceAttempts: Map<string, BrowserTraceAttempt>
9999
// lazily loaded only when traceView is enabled
100100
browserTraceDomSnapshot?: typeof import('rrweb-snapshot')
101+
// import started by the orchestrator so every tester reuses one module instance
102+
browserTraceDomSnapshotPromise?: Promise<typeof import('rrweb-snapshot')>
101103
selectorEngine: Ivya
102104
traces: Traces
103105
cleanups: Array<() => unknown>
@@ -117,6 +119,12 @@ export function getBrowserState(): BrowserRunnerState {
117119
return window.__vitest_browser_runner__
118120
}
119121

122+
/* @__NO_SIDE_EFFECTS__ */
123+
export function getOrchestratorState(): BrowserRunnerState {
124+
// @ts-expect-error not typed global
125+
return window.parent.__vitest_browser_runner__
126+
}
127+
120128
/* @__NO_SIDE_EFFECTS__ */
121129
export function getWorkerState(): WorkerGlobalState {
122130
// @ts-expect-error not typed global

patches/[email protected]

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,48 @@
11
diff --git a/dist/rrweb-snapshot.js b/dist/rrweb-snapshot.js
2+
index 1c0fc62d7ede018a7797d3e707c73fa803166d2d..eadcceb088ac1deef08655eb2ed1cdb95fdb515b 100644
23
--- a/dist/rrweb-snapshot.js
34
+++ b/dist/rrweb-snapshot.js
4-
@@ -1536,6 +1536,18 @@ const pseudoClassPlugin = {
5+
@@ -603,7 +603,7 @@ function genId() {
6+
return _id++;
7+
}
8+
function getValidTagName(element) {
9+
- if (element instanceof HTMLFormElement) {
10+
+ if (Object.prototype.toString.call(element) === "[object HTMLFormElement]") {
11+
return "form";
12+
}
13+
const processedTagName = toLowerCase(element.tagName);
14+
@@ -612,8 +612,16 @@ function getValidTagName(element) {
15+
}
16+
return processedTagName;
17+
}
18+
-let canvasService;
19+
-let canvasCtx;
20+
+const canvasServices = new WeakMap();
21+
+function getCanvasService(doc) {
22+
+ let service = canvasServices.get(doc);
23+
+ if (!service) {
24+
+ const canvas = doc.createElement("canvas");
25+
+ service = { canvas, context: canvas.getContext("2d") };
26+
+ canvasServices.set(doc, service);
27+
+ }
28+
+ return service;
29+
+}
30+
const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
31+
const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
32+
function getAbsoluteSrcsetString(doc, attributeValue) {
33+
@@ -1056,10 +1064,7 @@ function serializeElementNode(n, options) {
34+
}
35+
}
36+
if (tagName === "img" && inlineImages) {
37+
- if (!canvasService) {
38+
- canvasService = doc.createElement("canvas");
39+
- canvasCtx = canvasService.getContext("2d");
40+
- }
41+
+ const { canvas: canvasService, context: canvasCtx } = getCanvasService(doc);
42+
const image = n;
43+
const imageSrc = image.currentSrc || image.getAttribute("src") || "<unknown-src>";
44+
const priorCrossOrigin = image.crossOrigin;
45+
@@ -1536,6 +1541,18 @@ const pseudoClassPlugin = {
546
if (selector.includes(":hover")) {
647
rule2.selector += ",\n" + selector.replace(/:hover/g, ".\\:hover");
748
}

pnpm-lock.yaml

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)