Skip to content

Commit db2c5bd

Browse files
⚡️ [RUM-6813] Lazy load session replay (#3152)
1 parent c83326b commit db2c5bd

30 files changed

+467
-193
lines changed

.gitlab-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ script-tests:
308308
interruptible: true
309309
script:
310310
- yarn
311+
- yarn build:bundle
311312
- yarn test:script
312313
########################################################################################################################
313314
# Deploy

packages/core/src/browser/runOnReadyState.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ export function runOnReadyState(
1414
const eventName = expectedReadyState === 'complete' ? DOM_EVENT.LOAD : DOM_EVENT.DOM_CONTENT_LOADED
1515
return addEventListener(configuration, window, eventName, callback, { once: true })
1616
}
17+
18+
export function asyncRunOnReadyState(
19+
configuration: Configuration,
20+
expectedReadyState: 'complete' | 'interactive'
21+
): Promise<void> {
22+
return new Promise((resolve) => {
23+
runOnReadyState(configuration, expectedReadyState, resolve)
24+
})
25+
}

packages/core/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export {
4747
addTelemetryUsage,
4848
drainPreStartTelemetry,
4949
} from './domain/telemetry'
50-
export { monitored, monitor, callMonitored, setDebugMode } from './tools/monitor'
50+
export { monitored, monitor, callMonitored, setDebugMode, monitorError } from './tools/monitor'
5151
export { Observable, Subscription } from './tools/observable'
5252
export {
5353
startSessionManager,
@@ -82,7 +82,7 @@ export { AbstractLifeCycle } from './tools/abstractLifeCycle'
8282
export * from './domain/eventRateLimiter/createEventRateLimiter'
8383
export * from './tools/utils/browserDetection'
8484
export { sendToExtension } from './tools/sendToExtension'
85-
export { runOnReadyState } from './browser/runOnReadyState'
85+
export { runOnReadyState, asyncRunOnReadyState } from './browser/runOnReadyState'
8686
export { getZoneJsOriginalValue } from './tools/getZoneJsOriginalValue'
8787
export { instrumentMethod, instrumentSetter, InstrumentedMethodCall } from './tools/instrumentMethod'
8888
export {

packages/core/src/tools/monitor.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,17 @@ export function callMonitored<T extends (...args: any[]) => any>(
5050
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
5151
return fn.apply(context, args)
5252
} catch (e) {
53-
displayIfDebugEnabled(e)
54-
if (onMonitorErrorCollected) {
55-
try {
56-
onMonitorErrorCollected(e)
57-
} catch (e) {
58-
displayIfDebugEnabled(e)
59-
}
53+
monitorError(e)
54+
}
55+
}
56+
57+
export function monitorError(e: unknown) {
58+
displayIfDebugEnabled(e)
59+
if (onMonitorErrorCollected) {
60+
try {
61+
onMonitorErrorCollected(e)
62+
} catch (e) {
63+
displayIfDebugEnabled(e)
6064
}
6165
}
6266
}

packages/core/tsconfig.esm.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"compilerOptions": {
44
"baseUrl": ".",
55
"declaration": true,
6-
"module": "es6",
76
"rootDir": "./src/",
87
"outDir": "./esm/"
98
},

packages/rum-core/tsconfig.esm.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"compilerOptions": {
44
"baseUrl": ".",
55
"declaration": true,
6-
"module": "es6",
76
"rootDir": "./src/",
87
"outDir": "./esm/"
98
},

packages/rum-react/tsconfig.esm.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"compilerOptions": {
44
"baseUrl": ".",
55
"declaration": true,
6-
"module": "es6",
76
"rootDir": "./src/",
87
"outDir": "./esm/"
98
},

packages/rum-slim/tsconfig.esm.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"compilerOptions": {
44
"baseUrl": ".",
55
"declaration": true,
6-
"module": "es6",
76
"rootDir": "./src/",
87
"outDir": "./esm/"
98
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function lazyLoadRecorder() {
2+
return import(/* webpackChunkName: "recorder" */ './startRecording').then((module) => module.startRecording)
3+
}

packages/rum/src/boot/postStartStrategy.ts

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77
RumSession,
88
} from '@datadog/browser-rum-core'
99
import { LifeCycleEventType, SessionReplayState } from '@datadog/browser-rum-core'
10-
import { PageExitReason, runOnReadyState, type DeflateEncoder } from '@datadog/browser-core'
10+
import { asyncRunOnReadyState, monitorError, PageExitReason, type DeflateEncoder } from '@datadog/browser-core'
1111
import { getSessionReplayLink } from '../domain/getSessionReplayLink'
1212
import type { startRecording } from './startRecording'
1313

@@ -37,10 +37,11 @@ export function createPostStartStrategy(
3737
lifeCycle: LifeCycle,
3838
sessionManager: RumSessionManager,
3939
viewHistory: ViewHistory,
40-
startRecordingImpl: StartRecording,
40+
loadRecorder: () => Promise<StartRecording>,
4141
getOrCreateDeflateEncoder: () => DeflateEncoder | undefined
4242
): Strategy {
4343
let status = RecorderStatus.Stopped
44+
let stopRecording: () => void
4445

4546
lifeCycle.subscribe(LifeCycleEventType.SESSION_EXPIRED, () => {
4647
if (status === RecorderStatus.Starting || status === RecorderStatus.Started) {
@@ -62,6 +63,30 @@ export function createPostStartStrategy(
6263
}
6364
})
6465

66+
const doStart = async () => {
67+
const [startRecordingImpl] = await Promise.all([loadRecorder(), asyncRunOnReadyState(configuration, 'interactive')])
68+
69+
if (status !== RecorderStatus.Starting) {
70+
return
71+
}
72+
73+
const deflateEncoder = getOrCreateDeflateEncoder()
74+
if (!deflateEncoder) {
75+
status = RecorderStatus.Stopped
76+
return
77+
}
78+
79+
;({ stop: stopRecording } = startRecordingImpl(
80+
lifeCycle,
81+
configuration,
82+
sessionManager,
83+
viewHistory,
84+
deflateEncoder
85+
))
86+
87+
status = RecorderStatus.Started
88+
}
89+
6590
function start(options?: StartRecordingOptions) {
6691
const session = sessionManager.findTrackedSession()
6792
if (canStartRecording(session, options)) {
@@ -75,42 +100,22 @@ export function createPostStartStrategy(
75100

76101
status = RecorderStatus.Starting
77102

78-
runOnReadyState(configuration, 'interactive', () => {
79-
if (status !== RecorderStatus.Starting) {
80-
return
81-
}
82-
83-
const deflateEncoder = getOrCreateDeflateEncoder()
84-
if (!deflateEncoder) {
85-
status = RecorderStatus.Stopped
86-
return
87-
}
88-
89-
;({ stop: stopRecording } = startRecordingImpl(
90-
lifeCycle,
91-
configuration,
92-
sessionManager,
93-
viewHistory,
94-
deflateEncoder
95-
))
96-
97-
status = RecorderStatus.Started
98-
})
103+
// Intentionally not awaiting doStart() to keep it asynchronous
104+
doStart().catch(monitorError)
99105

100106
if (shouldForceReplay(session!, options)) {
101107
sessionManager.setForcedReplay()
102108
}
103109
}
104110

105111
function stop() {
106-
if (status !== RecorderStatus.Stopped && status === RecorderStatus.Started) {
112+
if (status === RecorderStatus.Started) {
107113
stopRecording?.()
108114
}
109115

110116
status = RecorderStatus.Stopped
111117
}
112118

113-
let stopRecording: () => void
114119
return {
115120
start,
116121
stop,

0 commit comments

Comments
 (0)