Skip to content

Commit 652c2a5

Browse files
committed
Implement LUX.spaMode
1 parent 0627301 commit 652c2a5

29 files changed

+776
-171
lines changed

docs/debug-parser/events.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ export function getMessageForEvent(event: LogEventRecord, filters: string[]): st
154154

155155
return "POST beacon send failed.";
156156

157-
case LogEvent.PostBeaconAlreadySent:
158-
return "POST beacon cancelled (already sent).";
159-
160157
case LogEvent.PostBeaconCancelled:
161158
return "POST beacon cancelled.";
162159

@@ -272,6 +269,14 @@ function getEventName(event: LogEvent) {
272269
return "MarkLoadTimeCalled";
273270
case LogEvent.SendCancelledPageHidden:
274271
return "SendCancelledPageHidden";
272+
case LogEvent.TriggerSoftNavigationCalled:
273+
return "TriggerSoftNavigationCalled";
274+
case LogEvent.SendTriggeredBySoftNavigation:
275+
return "SendTriggeredBySoftNavigation";
276+
case LogEvent.SendCancelledSpaMode:
277+
return "SendCancelledSpaMode";
278+
case LogEvent.BfCacheRestore:
279+
return "BfCacheRestore";
275280
case LogEvent.SessionIsSampled:
276281
return "SessionIsSampled";
277282
case LogEvent.SessionIsNotSampled:
@@ -318,8 +323,6 @@ function getEventName(event: LogEvent) {
318323
return "PostBeaconTimeoutReached";
319324
case LogEvent.PostBeaconSent:
320325
return "PostBeaconSent";
321-
case LogEvent.PostBeaconAlreadySent:
322-
return "PostBeaconAlreadySent";
323326
case LogEvent.PostBeaconCancelled:
324327
return "PostBeaconCancelled";
325328
case LogEvent.PostBeaconStopRecording:
@@ -333,4 +336,6 @@ function getEventName(event: LogEvent) {
333336
case LogEvent.PostBeaconCollector:
334337
return "PostBeaconCollector";
335338
}
339+
340+
return "Unknown Event";
336341
}

docs/spa-mode.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPA Mode in lux.js
2+
3+
## Migrating from `LUX.auto = false`
4+
5+
- Remove `LUX.auto = false`.
6+
- Remove all `LUX.send()` calls. In SPA mode, the beacon is sent automatically. In some very rare cases you may want to send the beacon manually, which can be done by calling `LUX.send(true)` - **this is not recommended**.
7+
- Replace all `LUX.init()` calls with `LUX.startSoftNavigation()`.

src/beacon.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ConfigObject, UserConfig } from "./config";
22
import { wasPrerendered } from "./document";
3+
import * as Events from "./events";
34
import Flags, { addFlag } from "./flags";
45
import { addListener } from "./listeners";
56
import Logger, { LogEvent } from "./logger";
@@ -160,6 +161,10 @@ export class Beacon {
160161
}
161162

162163
send() {
164+
if (this.isSent) {
165+
return;
166+
}
167+
163168
this.logger.logEvent(LogEvent.PostBeaconSendCalled);
164169

165170
for (const cb of this.onBeforeSendCbs) {
@@ -187,11 +192,6 @@ export class Beacon {
187192
return;
188193
}
189194

190-
if (this.isSent) {
191-
this.logger.logEvent(LogEvent.PostBeaconAlreadySent);
192-
return;
193-
}
194-
195195
// Only clear the max measure timeout if there's data to send.
196196
clearTimeout(this.maxMeasureTimeout);
197197

@@ -215,6 +215,7 @@ export class Beacon {
215215
if (sendBeacon(beaconUrl, JSON.stringify(payload))) {
216216
this.isSent = true;
217217
this.logger.logEvent(LogEvent.PostBeaconSent, [beaconUrl, payload]);
218+
Events.emit("beacon", payload);
218219
}
219220
} catch (e) {
220221
// Intentionally empty; handled below

src/config.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { LuxGlobal } from "./global";
22
import { ServerTimingConfig } from "./server-timing";
33
import { UrlPatternMapping } from "./url-matcher";
44

5+
/**
6+
* ConfigObject holds the parsed and normalised lux.js configuration. It is initialised once based
7+
* on the `LUX` global.
8+
*/
59
export interface ConfigObject {
610
allowEmptyPostBeacon: boolean;
711
auto: boolean;
@@ -28,6 +32,7 @@ export interface ConfigObject {
2832
sendBeaconOnPageHidden: boolean;
2933
serverTiming?: ServerTimingConfig;
3034
snippetVersion?: LuxGlobal["snippetVersion"];
35+
spaMode: boolean;
3136
trackErrors: boolean;
3237
trackHiddenPages: boolean;
3338
}
@@ -37,7 +42,8 @@ export type UserConfig = Partial<ConfigObject>;
3742
const luxOrigin = "https://lux.speedcurve.com";
3843

3944
export function fromObject(obj: UserConfig): ConfigObject {
40-
const autoMode = getProperty(obj, "auto", true);
45+
const spaMode = getProperty(obj, "spaMode", false);
46+
const autoMode = spaMode ? false : getProperty(obj, "auto", true);
4147

4248
return {
4349
allowEmptyPostBeacon: getProperty(obj, "allowEmptyPostBeacon", false),
@@ -57,13 +63,14 @@ export function fromObject(obj: UserConfig): ConfigObject {
5763
maxBeaconUTEntries: getProperty(obj, "maxBeaconUTEntries", 20),
5864
maxErrors: getProperty(obj, "maxErrors", 5),
5965
maxMeasureTime: getProperty(obj, "maxMeasureTime", 60_000),
60-
measureUntil: getProperty(obj, "measureUntil", "onload"),
66+
measureUntil: getProperty(obj, "measureUntil", spaMode ? "pagehidden" : "onload"),
6167
minMeasureTime: getProperty(obj, "minMeasureTime", 0),
6268
newBeaconOnPageShow: getProperty(obj, "newBeaconOnPageShow", false),
6369
pagegroups: getProperty(obj, "pagegroups"),
6470
samplerate: getProperty(obj, "samplerate", 100),
65-
sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
71+
sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", spaMode || autoMode),
6672
serverTiming: getProperty(obj, "serverTiming"),
73+
spaMode,
6774
trackErrors: getProperty(obj, "trackErrors", true),
6875
trackHiddenPages: getProperty(obj, "trackHiddenPages", false),
6976
};

src/global.ts renamed to src/global.d.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,43 @@ import type { Event } from "./events";
33
import type { LogEventRecord } from "./logger";
44

55
export type Command = [CommandFunction, ...CommandArg[]];
6-
type CommandFunction = "addData" | "init" | "mark" | "markLoadTime" | "measure" | "on" | "send";
7-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8-
type CommandArg = any;
6+
type CommandFunction =
7+
| "addData"
8+
| "init"
9+
| "mark"
10+
| "markLoadTime"
11+
| "measure"
12+
| "on"
13+
| "send"
14+
| "startSoftNavigation";
15+
16+
type CommandArg = unknown;
917
type PerfMarkFn = typeof performance.mark;
1018
type PerfMeasureFn = typeof performance.measure;
1119

20+
/**
21+
* LuxGlobal is the global `LUX` object. It is defined and modified by the snippet, lux.js and by
22+
* the implementor.
23+
*/
1224
export interface LuxGlobal extends UserConfig {
1325
/** Command queue used to store actions that were initiated before the full script loads */
1426
ac?: Command[];
15-
addData: (name: string, value: unknown) => void;
27+
addData: (name: string, value?: unknown) => void;
1628
cmd: (cmd: Command) => void;
1729
/** @deprecated */
1830
doUpdate?: () => void;
1931
forceSample?: () => void;
20-
getDebug?: () => LogEventRecord[];
32+
getDebug: () => LogEventRecord[];
2133
getSessionId?: () => void;
22-
init: () => void;
34+
init: (time?: number) => void;
2335
mark: (...args: Parameters<PerfMarkFn>) => ReturnType<PerfMarkFn> | void;
24-
markLoadTime?: (time?: number) => void;
36+
markLoadTime: (time?: number) => void;
2537
measure: (...args: Parameters<PerfMeasureFn>) => ReturnType<PerfMeasureFn> | void;
2638
on: (event: Event, callback: (data?: unknown) => void) => void;
2739
/** Timestamp representing when the LUX snippet was evaluated */
2840
ns?: number;
29-
send: () => void;
41+
send: (force?: boolean) => void;
3042
snippetVersion?: string;
43+
startSoftNavigation: (time?: number) => void;
3144
version?: string;
3245
}

src/logger.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export const enum LogEvent {
1515
OnloadHandlerTriggered = 11,
1616
MarkLoadTimeCalled = 12,
1717
SendCancelledPageHidden = 13,
18+
TriggerSoftNavigationCalled = 14,
19+
SendTriggeredBySoftNavigation = 15,
20+
SendCancelledSpaMode = 16,
21+
BfCacheRestore = 17,
22+
InitCallIgnored = 18,
1823

1924
// Data collection events
2025
SessionIsSampled = 21,
@@ -48,7 +53,6 @@ export const enum LogEvent {
4853
PostBeaconSendCalled = 81,
4954
PostBeaconTimeoutReached = 82,
5055
PostBeaconSent = 83,
51-
PostBeaconAlreadySent = 84,
5256
PostBeaconCancelled = 85,
5357
PostBeaconStopRecording = 86,
5458
PostBeaconMetricRejected = 87,

0 commit comments

Comments
 (0)