@atlaskit/react-ufo 3.14.6 → 3.14.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/cjs/create-experimental-interaction-metrics-payload/index.js +14 -12
- package/dist/cjs/create-payload/utils/get-vc-metrics.js +17 -13
- package/dist/cjs/interaction-metrics/index.js +35 -15
- package/dist/cjs/interaction-metrics-init/index.js +5 -3
- package/dist/cjs/vc/index.js +46 -6
- package/dist/cjs/vc/vc-observer/index.js +10 -2
- package/dist/cjs/vc/vc-observer/observers/index.js +12 -7
- package/dist/cjs/vc/vc-observer/observers/ssr-placeholders/index.js +76 -40
- package/dist/cjs/vc/vc-observer-new/index.js +84 -0
- package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +214 -71
- package/dist/cjs/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +97 -59
- package/dist/es2019/create-experimental-interaction-metrics-payload/index.js +4 -2
- package/dist/es2019/create-payload/utils/get-vc-metrics.js +10 -4
- package/dist/es2019/interaction-metrics/index.js +36 -16
- package/dist/es2019/interaction-metrics-init/index.js +5 -3
- package/dist/es2019/vc/index.js +42 -5
- package/dist/es2019/vc/vc-observer/index.js +8 -2
- package/dist/es2019/vc/vc-observer/observers/index.js +11 -5
- package/dist/es2019/vc/vc-observer/observers/ssr-placeholders/index.js +57 -26
- package/dist/es2019/vc/vc-observer-new/index.js +67 -1
- package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +87 -22
- package/dist/es2019/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +50 -34
- package/dist/esm/create-experimental-interaction-metrics-payload/index.js +14 -12
- package/dist/esm/create-payload/utils/get-vc-metrics.js +17 -13
- package/dist/esm/interaction-metrics/index.js +36 -16
- package/dist/esm/interaction-metrics-init/index.js +5 -3
- package/dist/esm/vc/index.js +45 -6
- package/dist/esm/vc/vc-observer/index.js +10 -2
- package/dist/esm/vc/vc-observer/observers/index.js +12 -7
- package/dist/esm/vc/vc-observer/observers/ssr-placeholders/index.js +76 -40
- package/dist/esm/vc/vc-observer-new/index.js +84 -0
- package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +214 -71
- package/dist/esm/vc/vc-observer-new/viewport-observer/mutation-observer/index.js +97 -59
- package/dist/types/common/common/types.d.ts +4 -1
- package/dist/types/vc/index.d.ts +3 -0
- package/dist/types/vc/types.d.ts +2 -0
- package/dist/types/vc/vc-observer/index.d.ts +1 -0
- package/dist/types/vc/vc-observer/observers/index.d.ts +2 -0
- package/dist/types/vc/vc-observer/observers/ssr-placeholders/index.d.ts +6 -0
- package/dist/types/vc/vc-observer-new/index.d.ts +30 -0
- package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types/vc/vc-observer-new/viewport-observer/index.d.ts +5 -1
- package/dist/types/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
- package/dist/types-ts4.5/common/common/types.d.ts +4 -1
- package/dist/types-ts4.5/vc/index.d.ts +3 -0
- package/dist/types-ts4.5/vc/types.d.ts +2 -0
- package/dist/types-ts4.5/vc/vc-observer/index.d.ts +1 -0
- package/dist/types-ts4.5/vc/vc-observer/observers/index.d.ts +2 -0
- package/dist/types-ts4.5/vc/vc-observer/observers/ssr-placeholders/index.d.ts +6 -0
- package/dist/types-ts4.5/vc/vc-observer-new/index.d.ts +30 -0
- package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +1 -1
- package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/index.d.ts +5 -1
- package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/mutation-observer/index.d.ts +2 -0
- package/package.json +11 -6
|
@@ -4,10 +4,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
8
7
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
9
8
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
10
9
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
10
|
+
// Batched mutation data for performance optimization
|
|
11
|
+
|
|
11
12
|
function createMutationObserver(_ref) {
|
|
12
13
|
var onAttributeMutation = _ref.onAttributeMutation,
|
|
13
14
|
onChildListMutation = _ref.onChildListMutation,
|
|
@@ -16,82 +17,119 @@ function createMutationObserver(_ref) {
|
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
18
19
|
var mutationObserverCallback = function mutationObserverCallback(mutations) {
|
|
19
|
-
var addedNodes = [];
|
|
20
|
-
var removedNodes = [];
|
|
21
|
-
var attributeMutations = [];
|
|
22
20
|
var targets = [];
|
|
21
|
+
// Use nested Maps for O(1) batching performance
|
|
22
|
+
// Short-lived Maps are safe since they're discarded after each callback
|
|
23
|
+
var batchedMutations = new Map();
|
|
23
24
|
var _iterator = _createForOfIteratorHelper(mutations),
|
|
24
25
|
_step;
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if ((0, _platformFeatureFlags.fg)('platform_vc_ignore_no_ls_mutation_marker')) {
|
|
27
|
+
var _loop = function _loop() {
|
|
28
|
+
var mut = _step.value;
|
|
29
|
+
if (!(mut.target instanceof HTMLElement)) {
|
|
30
|
+
return 0; // continue
|
|
31
|
+
}
|
|
32
|
+
if (mut.type === 'attributes') {
|
|
33
|
+
var _mut$oldValue;
|
|
34
|
+
/*
|
|
35
|
+
"MutationObserver was explicitly designed to work that way, but I can't now recall the reasoning.
|
|
36
|
+
I think it might have been something along the lines that for consistency every setAttribute call should create a record.
|
|
37
|
+
Conceptually there is after all a mutation: there is an old value replaced with a new one,
|
|
38
|
+
and whether or not they are the same doesn't really matter.
|
|
39
|
+
And Custom elements should work the same way as MutationObserver."
|
|
40
|
+
https://github.com/whatwg/dom/issues/520#issuecomment-336574796
|
|
41
|
+
*/
|
|
42
|
+
var oldValue = (_mut$oldValue = mut.oldValue) !== null && _mut$oldValue !== void 0 ? _mut$oldValue : undefined;
|
|
43
|
+
var newValue = mut.attributeName ? mut.target.getAttribute(mut.attributeName) : undefined;
|
|
44
|
+
if (oldValue !== newValue) {
|
|
45
45
|
var _mut$attributeName;
|
|
46
|
-
attributeMutations.push({
|
|
47
|
-
target: new WeakRef(_mut.target),
|
|
48
|
-
attributeName: (_mut$attributeName = _mut.attributeName) !== null && _mut$attributeName !== void 0 ? _mut$attributeName : 'unknown',
|
|
49
|
-
oldValue: oldValue,
|
|
50
|
-
newValue: newValue
|
|
51
|
-
});
|
|
52
|
-
} else {
|
|
53
|
-
var _mut$attributeName2;
|
|
54
46
|
onAttributeMutation({
|
|
55
|
-
target:
|
|
56
|
-
attributeName: (_mut$
|
|
47
|
+
target: mut.target,
|
|
48
|
+
attributeName: (_mut$attributeName = mut.attributeName) !== null && _mut$attributeName !== void 0 ? _mut$attributeName : 'unknown',
|
|
57
49
|
oldValue: oldValue,
|
|
58
50
|
newValue: newValue
|
|
59
51
|
});
|
|
60
52
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
53
|
+
return 0; // continue
|
|
54
|
+
} else if (mut.type === 'childList') {
|
|
55
|
+
var _mut$addedNodes, _mut$removedNodes;
|
|
56
|
+
// In chromium browser MutationRecord has timestamp field, which we should use.
|
|
57
|
+
var timestamp = Math.round(mut.timestamp || performance.now());
|
|
58
|
+
|
|
59
|
+
// Get or create timestamp bucket
|
|
60
|
+
var timestampBucket = batchedMutations.get(timestamp);
|
|
61
|
+
if (!timestampBucket) {
|
|
62
|
+
timestampBucket = new Map();
|
|
63
|
+
batchedMutations.set(timestamp, timestampBucket);
|
|
68
64
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
|
|
66
|
+
// Get or create target batch within timestamp bucket
|
|
67
|
+
var batch = timestampBucket.get(mut.target);
|
|
68
|
+
if (!batch) {
|
|
69
|
+
batch = {
|
|
70
|
+
target: new WeakRef(mut.target),
|
|
71
|
+
addedNodes: [],
|
|
72
|
+
removedNodes: [],
|
|
73
|
+
timestamp: timestamp
|
|
74
|
+
};
|
|
75
|
+
timestampBucket.set(mut.target, batch);
|
|
73
76
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
|
|
78
|
+
// Accumulate added nodes
|
|
79
|
+
((_mut$addedNodes = mut.addedNodes) !== null && _mut$addedNodes !== void 0 ? _mut$addedNodes : []).forEach(function (node) {
|
|
80
|
+
if (node instanceof HTMLElement) {
|
|
81
|
+
batch.addedNodes.push(new WeakRef(node));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Accumulate removed nodes
|
|
86
|
+
((_mut$removedNodes = mut.removedNodes) !== null && _mut$removedNodes !== void 0 ? _mut$removedNodes : []).forEach(function (node) {
|
|
87
|
+
if (node instanceof HTMLElement) {
|
|
88
|
+
batch.removedNodes.push(new WeakRef(node));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
targets.push(mut.target);
|
|
93
|
+
},
|
|
94
|
+
_ret;
|
|
95
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
96
|
+
_ret = _loop();
|
|
97
|
+
if (_ret === 0) continue;
|
|
77
98
|
}
|
|
99
|
+
|
|
100
|
+
// Process all batched childList mutations
|
|
78
101
|
} catch (err) {
|
|
79
102
|
_iterator.e(err);
|
|
80
103
|
} finally {
|
|
81
104
|
_iterator.f();
|
|
82
105
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
var _iterator2 = _createForOfIteratorHelper(batchedMutations.values()),
|
|
107
|
+
_step2;
|
|
108
|
+
try {
|
|
109
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
110
|
+
var timestampBucket = _step2.value;
|
|
111
|
+
var _iterator3 = _createForOfIteratorHelper(timestampBucket.values()),
|
|
112
|
+
_step3;
|
|
113
|
+
try {
|
|
114
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
115
|
+
var batch = _step3.value;
|
|
116
|
+
onChildListMutation({
|
|
117
|
+
target: batch.target,
|
|
118
|
+
addedNodes: batch.addedNodes,
|
|
119
|
+
removedNodes: batch.removedNodes,
|
|
120
|
+
timestamp: batch.timestamp
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
_iterator3.e(err);
|
|
125
|
+
} finally {
|
|
126
|
+
_iterator3.f();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch (err) {
|
|
130
|
+
_iterator2.e(err);
|
|
131
|
+
} finally {
|
|
132
|
+
_iterator2.f();
|
|
95
133
|
}
|
|
96
134
|
onMutationFinished === null || onMutationFinished === void 0 || onMutationFinished({
|
|
97
135
|
targets: targets
|
|
@@ -58,10 +58,12 @@ export class ExperimentalVCMetrics {
|
|
|
58
58
|
}
|
|
59
59
|
export const experimentalVC = new ExperimentalVCMetrics();
|
|
60
60
|
export async function getExperimentalVCMetrics(interaction) {
|
|
61
|
-
if
|
|
61
|
+
// Use per-interaction VC observer if available, otherwise fall back to global experimentalVC
|
|
62
|
+
const vcObserver = interaction.experimentalVCObserver || experimentalVC.vcObserver;
|
|
63
|
+
if (vcObserver) {
|
|
62
64
|
var _interaction$apdex, _interaction$apdex$;
|
|
63
65
|
const prefix = 'ufo-experimental';
|
|
64
|
-
const result = await
|
|
66
|
+
const result = await vcObserver.getVCResult({
|
|
65
67
|
start: interaction.start,
|
|
66
68
|
stop: interaction.end,
|
|
67
69
|
tti: (_interaction$apdex = interaction.apdex) === null || _interaction$apdex === void 0 ? void 0 : (_interaction$apdex$ = _interaction$apdex[0]) === null || _interaction$apdex$ === void 0 ? void 0 : _interaction$apdex$.stopTime,
|
|
@@ -11,7 +11,7 @@ async function getVCMetrics(interaction) {
|
|
|
11
11
|
if (!(config !== null && config !== void 0 && (_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled)) {
|
|
12
12
|
return {};
|
|
13
13
|
}
|
|
14
|
-
if (fg('
|
|
14
|
+
if (fg('platform_ufo_enable_vc_press_interactions')) {
|
|
15
15
|
if (interaction.type !== 'page_load' && interaction.type !== 'transition' && interaction.type !== 'press') {
|
|
16
16
|
return {};
|
|
17
17
|
}
|
|
@@ -23,8 +23,11 @@ async function getVCMetrics(interaction) {
|
|
|
23
23
|
const interactionStatus = getInteractionStatus(interaction);
|
|
24
24
|
const pageVisibilityUpToTTAI = getPageVisibilityUpToTTAI(interaction);
|
|
25
25
|
const shouldReportVCMetrics = interactionStatus.originalInteractionStatus === 'SUCCEEDED' && pageVisibilityUpToTTAI === 'visible';
|
|
26
|
+
|
|
27
|
+
// Use per-interaction VC observer if available, otherwise fall back to global
|
|
28
|
+
const observer = interaction.vcObserver || getVCObserver();
|
|
26
29
|
if (!shouldReportVCMetrics && fg('platform_ufo_no_vc_on_aborted')) {
|
|
27
|
-
|
|
30
|
+
observer.stop(interaction.ufoName);
|
|
28
31
|
return {};
|
|
29
32
|
}
|
|
30
33
|
const isSSREnabled = interaction.type === 'page_load' && ((config === null || config === void 0 ? void 0 : config.ssr) || (config === null || config === void 0 ? void 0 : (_config$vc$ssrWhiteli = config.vc.ssrWhitelist) === null || _config$vc$ssrWhiteli === void 0 ? void 0 : _config$vc$ssrWhiteli.includes(interaction.ufoName)));
|
|
@@ -34,7 +37,7 @@ async function getVCMetrics(interaction) {
|
|
|
34
37
|
postInteractionLog.setVCObserverSSRConfig(ssr);
|
|
35
38
|
const tti = (_interaction$apdex = interaction.apdex) === null || _interaction$apdex === void 0 ? void 0 : (_interaction$apdex$ = _interaction$apdex[0]) === null || _interaction$apdex$ === void 0 ? void 0 : _interaction$apdex$.stopTime;
|
|
36
39
|
const prefix = 'ufo';
|
|
37
|
-
const result = await
|
|
40
|
+
const result = await observer.getVCResult({
|
|
38
41
|
start: interaction.start,
|
|
39
42
|
stop: interaction.end,
|
|
40
43
|
tti,
|
|
@@ -47,8 +50,11 @@ async function getVCMetrics(interaction) {
|
|
|
47
50
|
includeSSRRatio: (_config$vc3 = config.vc) === null || _config$vc3 === void 0 ? void 0 : _config$vc3.includeSSRRatio,
|
|
48
51
|
...ssr
|
|
49
52
|
});
|
|
53
|
+
if (fg('platform_ufo_enable_vc_observer_per_interaction')) {
|
|
54
|
+
observer.stop(interaction.ufoName);
|
|
55
|
+
}
|
|
50
56
|
if ((_config$experimentalI = config.experimentalInteractionMetrics) !== null && _config$experimentalI !== void 0 && _config$experimentalI.enabled) {
|
|
51
|
-
|
|
57
|
+
observer.stop(interaction.ufoName);
|
|
52
58
|
}
|
|
53
59
|
postInteractionLog.setLastInteractionFinishVCResult(result);
|
|
54
60
|
const mostRecentVCRevision = getMostRecentVCRevision(interaction.ufoName);
|
|
@@ -6,7 +6,7 @@ import { experimentalVC, getExperimentalVCMetrics, onExperimentalInteractionComp
|
|
|
6
6
|
import { clearActiveTrace } from '../experience-trace-id-context';
|
|
7
7
|
import { allFeatureFlagsAccessed, currentFeatureFlagsAccessed } from '../feature-flags-accessed';
|
|
8
8
|
import { getInteractionId } from '../interaction-id-context';
|
|
9
|
-
import { getVCObserver } from '../vc';
|
|
9
|
+
import { getVCObserver, newVCObserver } from '../vc';
|
|
10
10
|
import { interactions } from './common/constants';
|
|
11
11
|
import PostInteractionLog from './post-interaction-log';
|
|
12
12
|
const PreviousInteractionLog = {
|
|
@@ -487,7 +487,9 @@ function finishInteraction(id, data, endTime = performance.now()) {
|
|
|
487
487
|
clearActiveTrace();
|
|
488
488
|
callCleanUpCallbacks(data);
|
|
489
489
|
if ((_getConfig4 = getConfig()) !== null && _getConfig4 !== void 0 && (_getConfig4$vc = _getConfig4.vc) !== null && _getConfig4$vc !== void 0 && _getConfig4$vc.stopVCAtInteractionFinish) {
|
|
490
|
-
|
|
490
|
+
// Use per-interaction VC observer if available, otherwise fall back to global
|
|
491
|
+
const observer = data.vcObserver || getVCObserver();
|
|
492
|
+
data.vc = observer.getVCRawData();
|
|
491
493
|
}
|
|
492
494
|
if (!((_getConfig5 = getConfig()) !== null && _getConfig5 !== void 0 && (_getConfig5$experimen = _getConfig5.experimentalInteractionMetrics) !== null && _getConfig5$experimen !== void 0 && _getConfig5$experimen.enabled)) {
|
|
493
495
|
remove(id);
|
|
@@ -656,6 +658,7 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
|
|
|
656
658
|
if ((_getConfig11 = getConfig()) !== null && _getConfig11 !== void 0 && (_getConfig11$postInte = _getConfig11.postInteractionLog) !== null && _getConfig11$postInte !== void 0 && _getConfig11$postInte.enabled) {
|
|
657
659
|
postInteractionLog.reset();
|
|
658
660
|
}
|
|
661
|
+
let vcObserver;
|
|
659
662
|
let previousTime = startTime;
|
|
660
663
|
let timeoutTime = fg('platform_ufo_enable_timeout_config') ? getInteractionTimeout(ufoName) : CLEANUP_TIMEOUT;
|
|
661
664
|
const timerID = setTimeout(() => {
|
|
@@ -678,6 +681,21 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
|
|
|
678
681
|
this.timerID = newTimerID;
|
|
679
682
|
}
|
|
680
683
|
const addFeatureFlagsToInteraction = coinflip(getCapabilityRate('feature_flag_access'));
|
|
684
|
+
const config = getConfig();
|
|
685
|
+
if (config && config.vc) {
|
|
686
|
+
const vcOptions = {
|
|
687
|
+
heatmapSize: config.vc.heatmapSize,
|
|
688
|
+
oldDomUpdates: config.vc.oldDomUpdates,
|
|
689
|
+
devToolsEnabled: config.vc.devToolsEnabled,
|
|
690
|
+
selectorConfig: config.vc.selectorConfig,
|
|
691
|
+
ssrEnablePageLayoutPlaceholder: config.vc.ssrEnablePageLayoutPlaceholder,
|
|
692
|
+
disableSizeAndPositionCheck: config.vc.disableSizeAndPositionCheck
|
|
693
|
+
};
|
|
694
|
+
vcObserver = fg('platform_ufo_enable_vc_observer_per_interaction') ? newVCObserver(vcOptions) : undefined;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Create per-interaction VC observer when feature flag is enabled
|
|
698
|
+
|
|
681
699
|
const metrics = {
|
|
682
700
|
id: interactionId,
|
|
683
701
|
start: startTime,
|
|
@@ -718,7 +736,8 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
|
|
|
718
736
|
redirects: [],
|
|
719
737
|
timerID,
|
|
720
738
|
changeTimeout,
|
|
721
|
-
trace
|
|
739
|
+
trace,
|
|
740
|
+
vcObserver
|
|
722
741
|
};
|
|
723
742
|
if (addFeatureFlagsToInteraction) {
|
|
724
743
|
currentFeatureFlagsAccessed.clear();
|
|
@@ -737,13 +756,21 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
|
|
|
737
756
|
metrics.cleanupCallbacks.push(() => {
|
|
738
757
|
clearTimeout(metrics.timerID);
|
|
739
758
|
});
|
|
759
|
+
// Add cleanup for per-interaction VC observer
|
|
760
|
+
if (vcObserver) {
|
|
761
|
+
metrics.cleanupCallbacks.push(() => {
|
|
762
|
+
vcObserver.stop(ufoName);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
740
765
|
const awaitBM3TTIList = getAwaitBM3TTIList();
|
|
741
766
|
if (awaitBM3TTIList.includes(ufoName)) {
|
|
742
767
|
addHoldByID(interactionId, [], ufoName, ufoName, true);
|
|
743
768
|
}
|
|
744
|
-
if (type === 'transition') {
|
|
769
|
+
if (type === 'transition' || type === 'page_load') {
|
|
745
770
|
var _getConfig12, _getConfig12$experime;
|
|
746
|
-
|
|
771
|
+
// Use per-interaction VC observer if available, otherwise fall back to global
|
|
772
|
+
const observer = vcObserver || getVCObserver();
|
|
773
|
+
observer.start({
|
|
747
774
|
startTime,
|
|
748
775
|
experienceKey: ufoName
|
|
749
776
|
});
|
|
@@ -756,20 +783,13 @@ export function addNewInteraction(interactionId, ufoName, type, startTime, rate,
|
|
|
756
783
|
});
|
|
757
784
|
}
|
|
758
785
|
}
|
|
759
|
-
if (type === 'press' &&
|
|
760
|
-
|
|
761
|
-
getVCObserver()
|
|
786
|
+
if (type === 'press' && fg('platform_ufo_enable_vc_press_interactions')) {
|
|
787
|
+
// Use per-interaction VC observer if available, otherwise fall back to global
|
|
788
|
+
const observer = vcObserver || getVCObserver();
|
|
789
|
+
observer.start({
|
|
762
790
|
startTime,
|
|
763
791
|
experienceKey: ufoName
|
|
764
792
|
});
|
|
765
|
-
postInteractionLog.startVCObserver({
|
|
766
|
-
startTime
|
|
767
|
-
});
|
|
768
|
-
if ((_getConfig13 = getConfig()) !== null && _getConfig13 !== void 0 && (_getConfig13$experime = _getConfig13.experimentalInteractionMetrics) !== null && _getConfig13$experime !== void 0 && _getConfig13$experime.enabled) {
|
|
769
|
-
experimentalVC.start({
|
|
770
|
-
startTime
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
793
|
}
|
|
774
794
|
}
|
|
775
795
|
export function addBrowserMetricEvent(event) {
|
|
@@ -91,9 +91,11 @@ export function init(analyticsWebClientAsync, config) {
|
|
|
91
91
|
ssrEnablePageLayoutPlaceholder: config.vc.ssrEnablePageLayoutPlaceholder,
|
|
92
92
|
disableSizeAndPositionCheck: config.vc.disableSizeAndPositionCheck
|
|
93
93
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
if (!fg('platform_ufo_enable_vc_observer_per_interaction')) {
|
|
95
|
+
getVCObserver(vcOptions).start({
|
|
96
|
+
startTime: 0
|
|
97
|
+
});
|
|
98
|
+
}
|
|
97
99
|
postInteractionLog.initializeVCObserver(vcOptions);
|
|
98
100
|
postInteractionLog.startVCObserver({
|
|
99
101
|
startTime: 0
|
package/dist/es2019/vc/index.js
CHANGED
|
@@ -4,17 +4,41 @@ import { VCObserverNOOP } from './no-op-vc-observer';
|
|
|
4
4
|
import { VCObserver } from './vc-observer';
|
|
5
5
|
import VCObserverNew from './vc-observer-new';
|
|
6
6
|
import { RLLPlaceholderHandlers } from './vc-observer/observers/rll-placeholders';
|
|
7
|
+
import { SSRPlaceholderHandlers } from './vc-observer/observers/ssr-placeholders';
|
|
7
8
|
export class VCObserverWrapper {
|
|
8
9
|
constructor(opts = {}) {
|
|
10
|
+
var _opts$ssrEnablePageLa, _opts$disableSizeAndP;
|
|
9
11
|
this.newVCObserver = null;
|
|
10
12
|
this.oldVCObserver = null;
|
|
13
|
+
|
|
14
|
+
// Initialize SSR placeholder handler once
|
|
15
|
+
this.ssrPlaceholderHandler = new SSRPlaceholderHandlers({
|
|
16
|
+
enablePageLayoutPlaceholder: (_opts$ssrEnablePageLa = opts.ssrEnablePageLayoutPlaceholder) !== null && _opts$ssrEnablePageLa !== void 0 ? _opts$ssrEnablePageLa : false,
|
|
17
|
+
disableSizeAndPositionCheck: (_opts$disableSizeAndP = opts.disableSizeAndPositionCheck) !== null && _opts$disableSizeAndP !== void 0 ? _opts$disableSizeAndP : {
|
|
18
|
+
v: false,
|
|
19
|
+
h: false
|
|
20
|
+
}
|
|
21
|
+
});
|
|
11
22
|
if (isVCRevisionEnabled('fy25.03')) {
|
|
23
|
+
var _opts$ssrEnablePageLa2, _opts$disableSizeAndP2;
|
|
12
24
|
this.newVCObserver = new VCObserverNew({
|
|
13
|
-
selectorConfig: opts.selectorConfig
|
|
25
|
+
selectorConfig: opts.selectorConfig,
|
|
26
|
+
isPostInteraction: opts.isPostInteraction,
|
|
27
|
+
SSRConfig: {
|
|
28
|
+
enablePageLayoutPlaceholder: (_opts$ssrEnablePageLa2 = opts.ssrEnablePageLayoutPlaceholder) !== null && _opts$ssrEnablePageLa2 !== void 0 ? _opts$ssrEnablePageLa2 : false,
|
|
29
|
+
disableSizeAndPositionCheck: (_opts$disableSizeAndP2 = opts.disableSizeAndPositionCheck) !== null && _opts$disableSizeAndP2 !== void 0 ? _opts$disableSizeAndP2 : {
|
|
30
|
+
v: false,
|
|
31
|
+
h: false
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
ssrPlaceholderHandler: this.ssrPlaceholderHandler
|
|
14
35
|
});
|
|
15
36
|
}
|
|
16
37
|
if (isVCRevisionEnabled('fy25.01') || isVCRevisionEnabled('fy25.02')) {
|
|
17
|
-
this.oldVCObserver = new VCObserver(
|
|
38
|
+
this.oldVCObserver = new VCObserver({
|
|
39
|
+
...opts,
|
|
40
|
+
ssrPlaceholderHandler: this.ssrPlaceholderHandler
|
|
41
|
+
});
|
|
18
42
|
}
|
|
19
43
|
}
|
|
20
44
|
|
|
@@ -68,6 +92,8 @@ export class VCObserverWrapper {
|
|
|
68
92
|
(_this$newVCObserver2 = this.newVCObserver) === null || _this$newVCObserver2 === void 0 ? void 0 : _this$newVCObserver2.stop();
|
|
69
93
|
}
|
|
70
94
|
RLLPlaceholderHandlers.getInstance().reset();
|
|
95
|
+
// Clear shared SSR placeholder handler
|
|
96
|
+
this.ssrPlaceholderHandler.clear();
|
|
71
97
|
}
|
|
72
98
|
getVCRawData() {
|
|
73
99
|
var _this$oldVCObserver$g, _this$oldVCObserver3;
|
|
@@ -94,16 +120,22 @@ export class VCObserverWrapper {
|
|
|
94
120
|
};
|
|
95
121
|
}
|
|
96
122
|
setSSRElement(element) {
|
|
97
|
-
var _this$oldVCObserver5;
|
|
123
|
+
var _this$oldVCObserver5, _this$newVCObserver4;
|
|
98
124
|
(_this$oldVCObserver5 = this.oldVCObserver) === null || _this$oldVCObserver5 === void 0 ? void 0 : _this$oldVCObserver5.setSSRElement(element);
|
|
125
|
+
(_this$newVCObserver4 = this.newVCObserver) === null || _this$newVCObserver4 === void 0 ? void 0 : _this$newVCObserver4.setReactRootElement(element);
|
|
99
126
|
}
|
|
100
127
|
setReactRootRenderStart(startTime) {
|
|
101
|
-
var _this$oldVCObserver6;
|
|
128
|
+
var _this$oldVCObserver6, _this$newVCObserver5;
|
|
102
129
|
(_this$oldVCObserver6 = this.oldVCObserver) === null || _this$oldVCObserver6 === void 0 ? void 0 : _this$oldVCObserver6.setReactRootRenderStart(startTime || performance.now());
|
|
130
|
+
(_this$newVCObserver5 = this.newVCObserver) === null || _this$newVCObserver5 === void 0 ? void 0 : _this$newVCObserver5.setReactRootRenderStart(startTime || performance.now());
|
|
103
131
|
}
|
|
104
132
|
setReactRootRenderStop(stopTime) {
|
|
105
|
-
var _this$oldVCObserver7;
|
|
133
|
+
var _this$oldVCObserver7, _this$newVCObserver6;
|
|
106
134
|
(_this$oldVCObserver7 = this.oldVCObserver) === null || _this$oldVCObserver7 === void 0 ? void 0 : _this$oldVCObserver7.setReactRootRenderStop(stopTime || performance.now());
|
|
135
|
+
(_this$newVCObserver6 = this.newVCObserver) === null || _this$newVCObserver6 === void 0 ? void 0 : _this$newVCObserver6.setReactRootRenderStop(stopTime || performance.now());
|
|
136
|
+
}
|
|
137
|
+
collectSSRPlaceholders() {
|
|
138
|
+
this.ssrPlaceholderHandler.collectExistingPlaceholders();
|
|
107
139
|
}
|
|
108
140
|
}
|
|
109
141
|
|
|
@@ -133,4 +165,9 @@ export function getVCObserver(opts = {}) {
|
|
|
133
165
|
globalThis.__vcObserver = shouldMockVCObserver ? new VCObserverNOOP() : new VCObserverWrapper(opts);
|
|
134
166
|
}
|
|
135
167
|
return globalThis.__vcObserver;
|
|
168
|
+
}
|
|
169
|
+
export function newVCObserver(opts = {}) {
|
|
170
|
+
const shouldMockVCObserver = !isEnvironmentSupported();
|
|
171
|
+
const observer = shouldMockVCObserver ? new VCObserverNOOP() : new VCObserverWrapper(opts);
|
|
172
|
+
return observer;
|
|
136
173
|
}
|
|
@@ -495,7 +495,8 @@ export class VCObserver {
|
|
|
495
495
|
this.oldDomUpdatesEnabled = options.oldDomUpdates || false;
|
|
496
496
|
const {
|
|
497
497
|
ssrEnablePageLayoutPlaceholder,
|
|
498
|
-
disableSizeAndPositionCheck
|
|
498
|
+
disableSizeAndPositionCheck,
|
|
499
|
+
ssrPlaceholderHandler
|
|
499
500
|
} = options;
|
|
500
501
|
this.observers = new Observers({
|
|
501
502
|
selectorConfig: options.selectorConfig || {
|
|
@@ -508,7 +509,8 @@ export class VCObserver {
|
|
|
508
509
|
SSRConfig: {
|
|
509
510
|
enablePageLayoutPlaceholder: ssrEnablePageLayoutPlaceholder || false,
|
|
510
511
|
disableSizeAndPositionCheck: disableSizeAndPositionCheck
|
|
511
|
-
}
|
|
512
|
+
},
|
|
513
|
+
ssrPlaceholderHandler: ssrPlaceholderHandler
|
|
512
514
|
});
|
|
513
515
|
this.heatmap = !isVCRevisionEnabled('fy25.01') ? [] : this.getCleanHeatmap();
|
|
514
516
|
this.heatmapNext = this.getCleanHeatmap();
|
|
@@ -654,6 +656,10 @@ export class VCObserver {
|
|
|
654
656
|
setReactRootRenderStop(stopTime = performance.now()) {
|
|
655
657
|
this.observers.setReactRootRenderStop(stopTime);
|
|
656
658
|
}
|
|
659
|
+
collectSSRPlaceholders() {
|
|
660
|
+
// This is handled by the shared SSRPlaceholderHandlers in VCObserverWrapper
|
|
661
|
+
// Individual observers don't need to implement this
|
|
662
|
+
}
|
|
657
663
|
setAbortReason(abort, timestamp, info = '') {
|
|
658
664
|
if (this.abortReason.reason === null || this.abortReason.blocking === false) {
|
|
659
665
|
this.abortReason.reason = abort;
|
|
@@ -21,7 +21,6 @@ function isElementVisible(target) {
|
|
|
21
21
|
}
|
|
22
22
|
export class Observers {
|
|
23
23
|
constructor(opts) {
|
|
24
|
-
var _opts$SSRConfig, _opts$SSRConfig2;
|
|
25
24
|
_defineProperty(this, "observedMutations", new WeakMap());
|
|
26
25
|
_defineProperty(this, "elementsInView", new Set());
|
|
27
26
|
_defineProperty(this, "callbacks", new Set());
|
|
@@ -61,10 +60,17 @@ export class Observers {
|
|
|
61
60
|
};
|
|
62
61
|
this.intersectionObserver = this.getIntersectionObserver();
|
|
63
62
|
this.mutationObserver = this.getMutationObserver();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
|
|
64
|
+
// Use shared SSR placeholder handler if provided, otherwise create new one
|
|
65
|
+
if (opts.ssrPlaceholderHandler) {
|
|
66
|
+
this.ssrPlaceholderHandler = opts.ssrPlaceholderHandler;
|
|
67
|
+
} else {
|
|
68
|
+
var _opts$SSRConfig, _opts$SSRConfig2;
|
|
69
|
+
this.ssrPlaceholderHandler = new SSRPlaceholderHandlers({
|
|
70
|
+
enablePageLayoutPlaceholder: (_opts$SSRConfig = opts.SSRConfig) === null || _opts$SSRConfig === void 0 ? void 0 : _opts$SSRConfig.enablePageLayoutPlaceholder,
|
|
71
|
+
disableSizeAndPositionCheck: (_opts$SSRConfig2 = opts.SSRConfig) === null || _opts$SSRConfig2 === void 0 ? void 0 : _opts$SSRConfig2.disableSizeAndPositionCheck
|
|
72
|
+
});
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
isBrowserSupported() {
|
|
70
76
|
return typeof window.IntersectionObserver === 'function' && typeof window.MutationObserver === 'function';
|
|
@@ -96,32 +96,8 @@ export class SSRPlaceholderHandlers {
|
|
|
96
96
|
this.disableSizeAndPositionCheck = disableSizeAndPositionCheck;
|
|
97
97
|
if (window.document) {
|
|
98
98
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
existingElements.forEach(el => {
|
|
102
|
-
const placeholderId = el instanceof HTMLElement && this.getPlaceholderId(el);
|
|
103
|
-
if (placeholderId) {
|
|
104
|
-
var _window$__SSR_PLACEHO, _this$intersectionObs2;
|
|
105
|
-
let width = -1;
|
|
106
|
-
let height = -1;
|
|
107
|
-
let x = -1;
|
|
108
|
-
let y = -1;
|
|
109
|
-
const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[placeholderId];
|
|
110
|
-
if (boundingClientRect) {
|
|
111
|
-
width = boundingClientRect.width;
|
|
112
|
-
height = boundingClientRect.height;
|
|
113
|
-
x = boundingClientRect.x;
|
|
114
|
-
y = boundingClientRect.y;
|
|
115
|
-
}
|
|
116
|
-
this.staticPlaceholders.set(placeholderId, {
|
|
117
|
-
width,
|
|
118
|
-
height,
|
|
119
|
-
x,
|
|
120
|
-
y
|
|
121
|
-
});
|
|
122
|
-
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.observe(el);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
99
|
+
// Collect initial placeholders using SSR dimensions
|
|
100
|
+
this.collectPlaceholdersInternal();
|
|
125
101
|
} catch (e) {} finally {
|
|
126
102
|
delete window.__SSR_PLACEHOLDERS_DIMENSIONS__;
|
|
127
103
|
}
|
|
@@ -133,6 +109,61 @@ export class SSRPlaceholderHandlers {
|
|
|
133
109
|
this.getSizeCallbacks = new Map();
|
|
134
110
|
this.reactValidateCallbacks = new Map();
|
|
135
111
|
}
|
|
112
|
+
collectPlaceholdersInternal() {
|
|
113
|
+
const selector = this.enablePageLayoutPlaceholder ? '[data-ssr-placeholder],[data-testid="page-layout.root"]' : '[data-ssr-placeholder]';
|
|
114
|
+
const existingElements = document.querySelectorAll(selector);
|
|
115
|
+
existingElements.forEach(el => {
|
|
116
|
+
const placeholderId = el instanceof HTMLElement && this.getPlaceholderId(el);
|
|
117
|
+
if (placeholderId && !this.staticPlaceholders.has(placeholderId)) {
|
|
118
|
+
var _window$__SSR_PLACEHO, _this$intersectionObs2;
|
|
119
|
+
let width = -1;
|
|
120
|
+
let height = -1;
|
|
121
|
+
let x = -1;
|
|
122
|
+
let y = -1;
|
|
123
|
+
|
|
124
|
+
// Use SSR dimensions from window global if available
|
|
125
|
+
const boundingClientRect = (_window$__SSR_PLACEHO = window.__SSR_PLACEHOLDERS_DIMENSIONS__) === null || _window$__SSR_PLACEHO === void 0 ? void 0 : _window$__SSR_PLACEHO[placeholderId];
|
|
126
|
+
if (boundingClientRect) {
|
|
127
|
+
width = boundingClientRect.width;
|
|
128
|
+
height = boundingClientRect.height;
|
|
129
|
+
x = boundingClientRect.x;
|
|
130
|
+
y = boundingClientRect.y;
|
|
131
|
+
} else {
|
|
132
|
+
// Fallback to current bounding rect if SSR dimensions not available
|
|
133
|
+
const rect = el.getBoundingClientRect();
|
|
134
|
+
width = rect.width;
|
|
135
|
+
height = rect.height;
|
|
136
|
+
x = rect.x;
|
|
137
|
+
y = rect.y;
|
|
138
|
+
}
|
|
139
|
+
this.staticPlaceholders.set(placeholderId, {
|
|
140
|
+
width,
|
|
141
|
+
height,
|
|
142
|
+
x,
|
|
143
|
+
y
|
|
144
|
+
});
|
|
145
|
+
(_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.observe(el);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Added this method to be utilised for testing purposes.
|
|
152
|
+
* In production it collection placeholder should only happens on constructor
|
|
153
|
+
*/
|
|
154
|
+
collectExistingPlaceholders() {
|
|
155
|
+
if (!window.document) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
// Collect placeholders using SSR dimensions or fallback to live dimensions
|
|
160
|
+
this.collectPlaceholdersInternal();
|
|
161
|
+
} catch (e) {
|
|
162
|
+
// Silently fail if there are any issues
|
|
163
|
+
} finally {
|
|
164
|
+
delete window.__SSR_PLACEHOLDERS_DIMENSIONS__;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
136
167
|
isPlaceholder(element) {
|
|
137
168
|
return Boolean(this.getPlaceholderId(element));
|
|
138
169
|
}
|