@atlaskit/insm 1.2.11 → 1.3.0
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 +18 -0
- package/api/package.json +7 -0
- package/dist/cjs/api.js +77 -0
- package/dist/cjs/dom-element-count.js +16 -0
- package/dist/cjs/editor-dom-registry.js +65 -0
- package/dist/cjs/index.js +11 -60
- package/dist/cjs/insm-session.js +6 -2
- package/dist/cjs/insm.js +51 -0
- package/dist/es2019/api.js +70 -0
- package/dist/es2019/dom-element-count.js +10 -0
- package/dist/es2019/editor-dom-registry.js +45 -0
- package/dist/es2019/index.js +5 -60
- package/dist/es2019/insm-session.js +6 -0
- package/dist/es2019/insm.js +45 -0
- package/dist/esm/api.js +70 -0
- package/dist/esm/dom-element-count.js +10 -0
- package/dist/esm/editor-dom-registry.js +58 -0
- package/dist/esm/index.js +5 -60
- package/dist/esm/insm-session.js +6 -2
- package/dist/esm/insm.js +51 -0
- package/dist/types/api.d.ts +13 -0
- package/dist/types/dom-element-count.d.ts +8 -0
- package/dist/types/editor-dom-registry.d.ts +33 -0
- package/dist/types/index.d.ts +1 -13
- package/dist/types/insm.d.ts +33 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @atlaskit/insm
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`60bbe3aea8c6e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/60bbe3aea8c6e) -
|
|
8
|
+
Add editorDomSize (the page editor's DOM element count) to the insm measured event, and new
|
|
9
|
+
registerEditorDom / unregisterEditorDom apis for the editor to provide the element to measure.
|
|
10
|
+
Behind the platform_editor_insm_dom_node_count experiment.
|
|
11
|
+
|
|
12
|
+
The insm api is now also available from the `@atlaskit/insm/api` entry point, so consumers do not
|
|
13
|
+
have to import it from the package barrel. The barrel export is unchanged.
|
|
14
|
+
|
|
15
|
+
## 1.2.12
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
|
|
3
21
|
## 1.2.11
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/api/package.json
ADDED
package/dist/cjs/api.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.init = init;
|
|
7
|
+
exports.insm = void 0;
|
|
8
|
+
var _insm = require("./insm");
|
|
9
|
+
var initialisedInsm;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
13
|
+
*/
|
|
14
|
+
function init(options) {
|
|
15
|
+
initialisedInsm = new _insm.INSM(options);
|
|
16
|
+
}
|
|
17
|
+
function insmInitialised() {
|
|
18
|
+
if (!initialisedInsm) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* **In**teractivity **s**ession **m**onitoring
|
|
26
|
+
*/
|
|
27
|
+
var insm = exports.insm = {
|
|
28
|
+
startHeavyTask: function startHeavyTask(heavyTaskName) {
|
|
29
|
+
if (insmInitialised()) {
|
|
30
|
+
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
endHeavyTask: function endHeavyTask(heavyTaskName) {
|
|
34
|
+
if (insmInitialised()) {
|
|
35
|
+
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
registerEditorDom: function registerEditorDom(editorDom) {
|
|
39
|
+
if (insmInitialised()) {
|
|
40
|
+
initialisedInsm.registerEditorDom(editorDom);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
unregisterEditorDom: function unregisterEditorDom(editorDom) {
|
|
44
|
+
if (insmInitialised()) {
|
|
45
|
+
initialisedInsm.unregisterEditorDom(editorDom);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
start: function start(experienceKey, experienceProperties) {
|
|
49
|
+
if (insmInitialised()) {
|
|
50
|
+
initialisedInsm.start(experienceKey, experienceProperties);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
overrideExperienceKey: function overrideExperienceKey(experienceKey) {
|
|
54
|
+
if (insmInitialised()) {
|
|
55
|
+
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
stopEarly: function stopEarly(reasonKey, description) {
|
|
59
|
+
if (insmInitialised()) {
|
|
60
|
+
initialisedInsm.stopEarly(reasonKey, description);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
// We only expose details and feature start/stop to consumers
|
|
64
|
+
// as the other properties are internals for the insm and InsmPeriod
|
|
65
|
+
// to interact with the running session.
|
|
66
|
+
get session() {
|
|
67
|
+
if (insmInitialised()) {
|
|
68
|
+
return initialisedInsm.runningSession;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
// @ts-expect-error Private method for testing purposes
|
|
72
|
+
__setAnalyticsWebClient: function __setAnalyticsWebClient(analyticsWebClient) {
|
|
73
|
+
if (initialisedInsm) {
|
|
74
|
+
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.countDomElements = countDomElements;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the total number of DOM elements inside the given element.
|
|
9
|
+
*
|
|
10
|
+
* Uses the native `getElementsByTagName('*')`, which counts descendants iteratively in the
|
|
11
|
+
* browser engine -- intentionally not a recursive JS walk, so it can't overflow the stack on
|
|
12
|
+
* very large documents.
|
|
13
|
+
*/
|
|
14
|
+
function countDomElements(element) {
|
|
15
|
+
return element.getElementsByTagName('*').length;
|
|
16
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.EditorDomRegistry = void 0;
|
|
8
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
|
+
/**
|
|
11
|
+
* Holds the page editor's content DOM.
|
|
12
|
+
*
|
|
13
|
+
* insm holds no reference to the editor, so the element is registered from the outside — it is
|
|
14
|
+
* the same `editorView.dom` element the editor measures for the `editorDomSize` attribute on
|
|
15
|
+
* its INP event.
|
|
16
|
+
*
|
|
17
|
+
* Only the page editor registers itself: an insm session measures a page, and secondary
|
|
18
|
+
* editors on the page (inline comments, nested legacy content extensions) would make the
|
|
19
|
+
* registration ambiguous.
|
|
20
|
+
*
|
|
21
|
+
* The element is held via a `WeakRef` so a destroyed editor's DOM can be collected even if
|
|
22
|
+
* `unregister` is never reached.
|
|
23
|
+
*/
|
|
24
|
+
var EditorDomRegistry = exports.EditorDomRegistry = /*#__PURE__*/function () {
|
|
25
|
+
function EditorDomRegistry() {
|
|
26
|
+
(0, _classCallCheck2.default)(this, EditorDomRegistry);
|
|
27
|
+
}
|
|
28
|
+
return (0, _createClass2.default)(EditorDomRegistry, [{
|
|
29
|
+
key: "register",
|
|
30
|
+
value:
|
|
31
|
+
/**
|
|
32
|
+
* Registers the page editor's content DOM element (`editorView.dom`).
|
|
33
|
+
*/
|
|
34
|
+
function register(editorDom) {
|
|
35
|
+
this.registered = new WeakRef(editorDom);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Unregisters an editor's content DOM element. Expected to be called when the editor is
|
|
40
|
+
* destroyed. Ignored when a different editor is currently registered, so an editor being
|
|
41
|
+
* torn down after its replacement registered does not clear the newer one.
|
|
42
|
+
*/
|
|
43
|
+
}, {
|
|
44
|
+
key: "unregister",
|
|
45
|
+
value: function unregister(editorDom) {
|
|
46
|
+
var _this$registered;
|
|
47
|
+
if (((_this$registered = this.registered) === null || _this$registered === void 0 ? void 0 : _this$registered.deref()) === editorDom) {
|
|
48
|
+
this.registered = undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The registered editor's content DOM, or undefined when no editor is registered or the
|
|
54
|
+
* registered one is no longer in the document -- ie. an experience without a page editor,
|
|
55
|
+
* or a session which outlived the editor.
|
|
56
|
+
*/
|
|
57
|
+
}, {
|
|
58
|
+
key: "editorDom",
|
|
59
|
+
get: function get() {
|
|
60
|
+
var _this$registered2;
|
|
61
|
+
var editorDom = (_this$registered2 = this.registered) === null || _this$registered2 === void 0 ? void 0 : _this$registered2.deref();
|
|
62
|
+
return editorDom !== null && editorDom !== void 0 && editorDom.isConnected ? editorDom : undefined;
|
|
63
|
+
}
|
|
64
|
+
}]);
|
|
65
|
+
}();
|
package/dist/cjs/index.js
CHANGED
|
@@ -3,65 +3,16 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
13
|
-
*/
|
|
14
|
-
function init(options) {
|
|
15
|
-
initialisedInsm = new _insm.INSM(options);
|
|
16
|
-
}
|
|
17
|
-
function insmInitialised() {
|
|
18
|
-
if (!initialisedInsm) {
|
|
19
|
-
return false;
|
|
6
|
+
Object.defineProperty(exports, "init", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _api.init;
|
|
20
10
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*/
|
|
27
|
-
var insm = exports.insm = {
|
|
28
|
-
startHeavyTask: function startHeavyTask(heavyTaskName) {
|
|
29
|
-
if (insmInitialised()) {
|
|
30
|
-
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
endHeavyTask: function endHeavyTask(heavyTaskName) {
|
|
34
|
-
if (insmInitialised()) {
|
|
35
|
-
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
start: function start(experienceKey, experienceProperties) {
|
|
39
|
-
if (insmInitialised()) {
|
|
40
|
-
initialisedInsm.start(experienceKey, experienceProperties);
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
overrideExperienceKey: function overrideExperienceKey(experienceKey) {
|
|
44
|
-
if (insmInitialised()) {
|
|
45
|
-
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
stopEarly: function stopEarly(reasonKey, description) {
|
|
49
|
-
if (insmInitialised()) {
|
|
50
|
-
initialisedInsm.stopEarly(reasonKey, description);
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
// We only expose details and feature start/stop to consumers
|
|
54
|
-
// as the other properties are internals for the insm and InsmPeriod
|
|
55
|
-
// to interact with the running session.
|
|
56
|
-
get session() {
|
|
57
|
-
if (insmInitialised()) {
|
|
58
|
-
return initialisedInsm.runningSession;
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
// @ts-expect-error Private method for testing purposes
|
|
62
|
-
__setAnalyticsWebClient: function __setAnalyticsWebClient(analyticsWebClient) {
|
|
63
|
-
if (initialisedInsm) {
|
|
64
|
-
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
65
|
-
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "insm", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _api.insm;
|
|
66
16
|
}
|
|
67
|
-
};
|
|
17
|
+
});
|
|
18
|
+
var _api = require("./api");
|
package/dist/cjs/insm-session.js
CHANGED
|
@@ -9,6 +9,7 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/cl
|
|
|
9
9
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
var _bowserUltralight = _interopRequireDefault(require("bowser-ultralight"));
|
|
12
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
12
13
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
13
14
|
var _insmPeriod = require("./insm-period");
|
|
14
15
|
var _LongAnimationFrameMeasurer = require("./session-measurers/LongAnimationFrameMeasurer");
|
|
@@ -204,11 +205,14 @@ var INSMSession = exports.INSMSession = /*#__PURE__*/function () {
|
|
|
204
205
|
var operationalEvent = {
|
|
205
206
|
actionSubject: 'insm',
|
|
206
207
|
action: 'measured',
|
|
207
|
-
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, this.staticProperties), evaluatedAddedProperties), {}, {
|
|
208
|
+
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, this.staticProperties), evaluatedAddedProperties), {}, {
|
|
208
209
|
'event:population': this.insm.options.population,
|
|
209
210
|
experienceKey: this.experienceKey,
|
|
210
211
|
initial: this.experienceProperties.initial,
|
|
211
|
-
contentId: this.experienceProperties.contentId
|
|
212
|
+
contentId: this.experienceProperties.contentId
|
|
213
|
+
}, (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_insm_dom_node_count') ? {
|
|
214
|
+
editorDomSize: this.insm.getEditorDomSize()
|
|
215
|
+
} : {}), {}, {
|
|
212
216
|
timing: {
|
|
213
217
|
startedAt: this.startedAt,
|
|
214
218
|
// Note: this will not match up with the periods sum of durations, as it includes
|
package/dist/cjs/insm.js
CHANGED
|
@@ -8,6 +8,8 @@ exports.INSM = void 0;
|
|
|
8
8
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
9
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _domElementCount = require("./dom-element-count");
|
|
12
|
+
var _editorDomRegistry = require("./editor-dom-registry");
|
|
11
13
|
var _insmSession = require("./insm-session");
|
|
12
14
|
var _afps = require("./period-measurers/afps");
|
|
13
15
|
var _inp = require("./inp-measurers/inp");
|
|
@@ -22,6 +24,11 @@ var INSM = exports.INSM = /*#__PURE__*/function () {
|
|
|
22
24
|
* page session.
|
|
23
25
|
*/
|
|
24
26
|
(0, _defineProperty2.default)(this, "runningHeavyTasks", new Set());
|
|
27
|
+
/**
|
|
28
|
+
* The editor is tracked at the insm layer (rather than per session) as it can
|
|
29
|
+
* outlive, or be mounted after, the session it is measured by.
|
|
30
|
+
*/
|
|
31
|
+
(0, _defineProperty2.default)(this, "editorDomRegistry", new _editorDomRegistry.EditorDomRegistry());
|
|
25
32
|
this.periodMeasurers = [(0, _expValEquals.expValEquals)('platform_editor_disable_afps', 'isEnabled', true) ? undefined : new _afps.AnimationFPSIM(), new _inp.INPTracker()];
|
|
26
33
|
this.options = options;
|
|
27
34
|
|
|
@@ -89,6 +96,50 @@ var INSM = exports.INSM = /*#__PURE__*/function () {
|
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Registers the page editor's content DOM element (`editorView.dom`) with insm.
|
|
101
|
+
*
|
|
102
|
+
* insm does not locate the editor itself - the element is provided by the editor so
|
|
103
|
+
* that session events can report its DOM element count (`editorDomSize`).
|
|
104
|
+
*
|
|
105
|
+
* A session measures a page, so only the page's own editor should register. Secondary
|
|
106
|
+
* editors (inline comments, nested legacy content extensions) must not, as the
|
|
107
|
+
* reported size would then depend on which editor registered last.
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* insm.registerEditorDom(editorView.dom);
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
}, {
|
|
114
|
+
key: "registerEditorDom",
|
|
115
|
+
value: function registerEditorDom(editorDom) {
|
|
116
|
+
this.editorDomRegistry.register(editorDom);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Unregisters the editor's content DOM element. This is expected to be called when
|
|
121
|
+
* the editor is destroyed.
|
|
122
|
+
*/
|
|
123
|
+
}, {
|
|
124
|
+
key: "unregisterEditorDom",
|
|
125
|
+
value: function unregisterEditorDom(editorDom) {
|
|
126
|
+
this.editorDomRegistry.unregister(editorDom);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The number of DOM elements inside the registered editor, used as a proxy for
|
|
131
|
+
* document complexity in performance events.
|
|
132
|
+
*
|
|
133
|
+
* Undefined when no editor is registered, or the registered one is no longer in
|
|
134
|
+
* the document.
|
|
135
|
+
*/
|
|
136
|
+
}, {
|
|
137
|
+
key: "getEditorDomSize",
|
|
138
|
+
value: function getEditorDomSize() {
|
|
139
|
+
var editorDom = this.editorDomRegistry.editorDom;
|
|
140
|
+
return editorDom ? (0, _domElementCount.countDomElements)(editorDom) : undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
92
143
|
/**
|
|
93
144
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
94
145
|
* routing solution.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { INSM } from './insm';
|
|
2
|
+
let initialisedInsm;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
6
|
+
*/
|
|
7
|
+
export function init(options) {
|
|
8
|
+
initialisedInsm = new INSM(options);
|
|
9
|
+
}
|
|
10
|
+
function insmInitialised() {
|
|
11
|
+
if (!initialisedInsm) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* **In**teractivity **s**ession **m**onitoring
|
|
19
|
+
*/
|
|
20
|
+
export const insm = {
|
|
21
|
+
startHeavyTask(heavyTaskName) {
|
|
22
|
+
if (insmInitialised()) {
|
|
23
|
+
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
endHeavyTask(heavyTaskName) {
|
|
27
|
+
if (insmInitialised()) {
|
|
28
|
+
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
registerEditorDom(editorDom) {
|
|
32
|
+
if (insmInitialised()) {
|
|
33
|
+
initialisedInsm.registerEditorDom(editorDom);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
unregisterEditorDom(editorDom) {
|
|
37
|
+
if (insmInitialised()) {
|
|
38
|
+
initialisedInsm.unregisterEditorDom(editorDom);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
start(experienceKey, experienceProperties) {
|
|
42
|
+
if (insmInitialised()) {
|
|
43
|
+
initialisedInsm.start(experienceKey, experienceProperties);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
overrideExperienceKey(experienceKey) {
|
|
47
|
+
if (insmInitialised()) {
|
|
48
|
+
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
stopEarly(reasonKey, description) {
|
|
52
|
+
if (insmInitialised()) {
|
|
53
|
+
initialisedInsm.stopEarly(reasonKey, description);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
// We only expose details and feature start/stop to consumers
|
|
57
|
+
// as the other properties are internals for the insm and InsmPeriod
|
|
58
|
+
// to interact with the running session.
|
|
59
|
+
get session() {
|
|
60
|
+
if (insmInitialised()) {
|
|
61
|
+
return initialisedInsm.runningSession;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
// @ts-expect-error Private method for testing purposes
|
|
65
|
+
__setAnalyticsWebClient(analyticsWebClient) {
|
|
66
|
+
if (initialisedInsm) {
|
|
67
|
+
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the total number of DOM elements inside the given element.
|
|
3
|
+
*
|
|
4
|
+
* Uses the native `getElementsByTagName('*')`, which counts descendants iteratively in the
|
|
5
|
+
* browser engine -- intentionally not a recursive JS walk, so it can't overflow the stack on
|
|
6
|
+
* very large documents.
|
|
7
|
+
*/
|
|
8
|
+
export function countDomElements(element) {
|
|
9
|
+
return element.getElementsByTagName('*').length;
|
|
10
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds the page editor's content DOM.
|
|
3
|
+
*
|
|
4
|
+
* insm holds no reference to the editor, so the element is registered from the outside — it is
|
|
5
|
+
* the same `editorView.dom` element the editor measures for the `editorDomSize` attribute on
|
|
6
|
+
* its INP event.
|
|
7
|
+
*
|
|
8
|
+
* Only the page editor registers itself: an insm session measures a page, and secondary
|
|
9
|
+
* editors on the page (inline comments, nested legacy content extensions) would make the
|
|
10
|
+
* registration ambiguous.
|
|
11
|
+
*
|
|
12
|
+
* The element is held via a `WeakRef` so a destroyed editor's DOM can be collected even if
|
|
13
|
+
* `unregister` is never reached.
|
|
14
|
+
*/
|
|
15
|
+
export class EditorDomRegistry {
|
|
16
|
+
/**
|
|
17
|
+
* Registers the page editor's content DOM element (`editorView.dom`).
|
|
18
|
+
*/
|
|
19
|
+
register(editorDom) {
|
|
20
|
+
this.registered = new WeakRef(editorDom);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Unregisters an editor's content DOM element. Expected to be called when the editor is
|
|
25
|
+
* destroyed. Ignored when a different editor is currently registered, so an editor being
|
|
26
|
+
* torn down after its replacement registered does not clear the newer one.
|
|
27
|
+
*/
|
|
28
|
+
unregister(editorDom) {
|
|
29
|
+
var _this$registered;
|
|
30
|
+
if (((_this$registered = this.registered) === null || _this$registered === void 0 ? void 0 : _this$registered.deref()) === editorDom) {
|
|
31
|
+
this.registered = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The registered editor's content DOM, or undefined when no editor is registered or the
|
|
37
|
+
* registered one is no longer in the document -- ie. an experience without a page editor,
|
|
38
|
+
* or a session which outlived the editor.
|
|
39
|
+
*/
|
|
40
|
+
get editorDom() {
|
|
41
|
+
var _this$registered2;
|
|
42
|
+
const editorDom = (_this$registered2 = this.registered) === null || _this$registered2 === void 0 ? void 0 : _this$registered2.deref();
|
|
43
|
+
return editorDom !== null && editorDom !== void 0 && editorDom.isConnected ? editorDom : undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/es2019/index.js
CHANGED
|
@@ -1,60 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
export function init(options) {
|
|
8
|
-
initialisedInsm = new INSM(options);
|
|
9
|
-
}
|
|
10
|
-
function insmInitialised() {
|
|
11
|
-
if (!initialisedInsm) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* **In**teractivity **s**ession **m**onitoring
|
|
19
|
-
*/
|
|
20
|
-
export const insm = {
|
|
21
|
-
startHeavyTask(heavyTaskName) {
|
|
22
|
-
if (insmInitialised()) {
|
|
23
|
-
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
endHeavyTask(heavyTaskName) {
|
|
27
|
-
if (insmInitialised()) {
|
|
28
|
-
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
start(experienceKey, experienceProperties) {
|
|
32
|
-
if (insmInitialised()) {
|
|
33
|
-
initialisedInsm.start(experienceKey, experienceProperties);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
overrideExperienceKey(experienceKey) {
|
|
37
|
-
if (insmInitialised()) {
|
|
38
|
-
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
stopEarly(reasonKey, description) {
|
|
42
|
-
if (insmInitialised()) {
|
|
43
|
-
initialisedInsm.stopEarly(reasonKey, description);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
// We only expose details and feature start/stop to consumers
|
|
47
|
-
// as the other properties are internals for the insm and InsmPeriod
|
|
48
|
-
// to interact with the running session.
|
|
49
|
-
get session() {
|
|
50
|
-
if (insmInitialised()) {
|
|
51
|
-
return initialisedInsm.runningSession;
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
// @ts-expect-error Private method for testing purposes
|
|
55
|
-
__setAnalyticsWebClient(analyticsWebClient) {
|
|
56
|
-
if (initialisedInsm) {
|
|
57
|
-
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
};
|
|
1
|
+
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
+
// Entry file in package.json
|
|
3
|
+
// Barrel kept for existing consumers -- new call sites should import from the
|
|
4
|
+
// `@atlaskit/insm/api` entry point instead.
|
|
5
|
+
export { init, insm } from './api';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import Bowser from 'bowser-ultralight';
|
|
3
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
3
4
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
4
5
|
import { PeriodTracking } from './insm-period';
|
|
5
6
|
import { LongAnimationFrameMeasurer } from './session-measurers/LongAnimationFrameMeasurer';
|
|
@@ -171,6 +172,11 @@ export class INSMSession {
|
|
|
171
172
|
experienceKey: this.experienceKey,
|
|
172
173
|
initial: this.experienceProperties.initial,
|
|
173
174
|
contentId: this.experienceProperties.contentId,
|
|
175
|
+
// The same measurement as the `editorDomSize` attribute on the editor's INP
|
|
176
|
+
// event, sampled from the registered editor when the session ends.
|
|
177
|
+
...(isExperimentEnabled('platform_editor_insm_dom_node_count') ? {
|
|
178
|
+
editorDomSize: this.insm.getEditorDomSize()
|
|
179
|
+
} : {}),
|
|
174
180
|
timing: {
|
|
175
181
|
startedAt: this.startedAt,
|
|
176
182
|
// Note: this will not match up with the periods sum of durations, as it includes
|
package/dist/es2019/insm.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import { countDomElements } from './dom-element-count';
|
|
3
|
+
import { EditorDomRegistry } from './editor-dom-registry';
|
|
2
4
|
import { INSMSession } from './insm-session';
|
|
3
5
|
import { AnimationFPSIM } from './period-measurers/afps';
|
|
4
6
|
import { INPTracker } from './inp-measurers/inp';
|
|
@@ -11,6 +13,11 @@ export class INSM {
|
|
|
11
13
|
* page session.
|
|
12
14
|
*/
|
|
13
15
|
_defineProperty(this, "runningHeavyTasks", new Set());
|
|
16
|
+
/**
|
|
17
|
+
* The editor is tracked at the insm layer (rather than per session) as it can
|
|
18
|
+
* outlive, or be mounted after, the session it is measured by.
|
|
19
|
+
*/
|
|
20
|
+
_defineProperty(this, "editorDomRegistry", new EditorDomRegistry());
|
|
14
21
|
this.periodMeasurers = [expValEquals('platform_editor_disable_afps', 'isEnabled', true) ? undefined : new AnimationFPSIM(), new INPTracker()];
|
|
15
22
|
this.options = options;
|
|
16
23
|
|
|
@@ -72,6 +79,44 @@ export class INSM {
|
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Registers the page editor's content DOM element (`editorView.dom`) with insm.
|
|
84
|
+
*
|
|
85
|
+
* insm does not locate the editor itself - the element is provided by the editor so
|
|
86
|
+
* that session events can report its DOM element count (`editorDomSize`).
|
|
87
|
+
*
|
|
88
|
+
* A session measures a page, so only the page's own editor should register. Secondary
|
|
89
|
+
* editors (inline comments, nested legacy content extensions) must not, as the
|
|
90
|
+
* reported size would then depend on which editor registered last.
|
|
91
|
+
*
|
|
92
|
+
* ```ts
|
|
93
|
+
* insm.registerEditorDom(editorView.dom);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
registerEditorDom(editorDom) {
|
|
97
|
+
this.editorDomRegistry.register(editorDom);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Unregisters the editor's content DOM element. This is expected to be called when
|
|
102
|
+
* the editor is destroyed.
|
|
103
|
+
*/
|
|
104
|
+
unregisterEditorDom(editorDom) {
|
|
105
|
+
this.editorDomRegistry.unregister(editorDom);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The number of DOM elements inside the registered editor, used as a proxy for
|
|
110
|
+
* document complexity in performance events.
|
|
111
|
+
*
|
|
112
|
+
* Undefined when no editor is registered, or the registered one is no longer in
|
|
113
|
+
* the document.
|
|
114
|
+
*/
|
|
115
|
+
getEditorDomSize() {
|
|
116
|
+
const editorDom = this.editorDomRegistry.editorDom;
|
|
117
|
+
return editorDom ? countDomElements(editorDom) : undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
75
120
|
/**
|
|
76
121
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
77
122
|
* routing solution.
|
package/dist/esm/api.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { INSM } from './insm';
|
|
2
|
+
var initialisedInsm;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
6
|
+
*/
|
|
7
|
+
export function init(options) {
|
|
8
|
+
initialisedInsm = new INSM(options);
|
|
9
|
+
}
|
|
10
|
+
function insmInitialised() {
|
|
11
|
+
if (!initialisedInsm) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* **In**teractivity **s**ession **m**onitoring
|
|
19
|
+
*/
|
|
20
|
+
export var insm = {
|
|
21
|
+
startHeavyTask: function startHeavyTask(heavyTaskName) {
|
|
22
|
+
if (insmInitialised()) {
|
|
23
|
+
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
endHeavyTask: function endHeavyTask(heavyTaskName) {
|
|
27
|
+
if (insmInitialised()) {
|
|
28
|
+
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
registerEditorDom: function registerEditorDom(editorDom) {
|
|
32
|
+
if (insmInitialised()) {
|
|
33
|
+
initialisedInsm.registerEditorDom(editorDom);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
unregisterEditorDom: function unregisterEditorDom(editorDom) {
|
|
37
|
+
if (insmInitialised()) {
|
|
38
|
+
initialisedInsm.unregisterEditorDom(editorDom);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
start: function start(experienceKey, experienceProperties) {
|
|
42
|
+
if (insmInitialised()) {
|
|
43
|
+
initialisedInsm.start(experienceKey, experienceProperties);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
overrideExperienceKey: function overrideExperienceKey(experienceKey) {
|
|
47
|
+
if (insmInitialised()) {
|
|
48
|
+
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
stopEarly: function stopEarly(reasonKey, description) {
|
|
52
|
+
if (insmInitialised()) {
|
|
53
|
+
initialisedInsm.stopEarly(reasonKey, description);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
// We only expose details and feature start/stop to consumers
|
|
57
|
+
// as the other properties are internals for the insm and InsmPeriod
|
|
58
|
+
// to interact with the running session.
|
|
59
|
+
get session() {
|
|
60
|
+
if (insmInitialised()) {
|
|
61
|
+
return initialisedInsm.runningSession;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
// @ts-expect-error Private method for testing purposes
|
|
65
|
+
__setAnalyticsWebClient: function __setAnalyticsWebClient(analyticsWebClient) {
|
|
66
|
+
if (initialisedInsm) {
|
|
67
|
+
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the total number of DOM elements inside the given element.
|
|
3
|
+
*
|
|
4
|
+
* Uses the native `getElementsByTagName('*')`, which counts descendants iteratively in the
|
|
5
|
+
* browser engine -- intentionally not a recursive JS walk, so it can't overflow the stack on
|
|
6
|
+
* very large documents.
|
|
7
|
+
*/
|
|
8
|
+
export function countDomElements(element) {
|
|
9
|
+
return element.getElementsByTagName('*').length;
|
|
10
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
/**
|
|
4
|
+
* Holds the page editor's content DOM.
|
|
5
|
+
*
|
|
6
|
+
* insm holds no reference to the editor, so the element is registered from the outside — it is
|
|
7
|
+
* the same `editorView.dom` element the editor measures for the `editorDomSize` attribute on
|
|
8
|
+
* its INP event.
|
|
9
|
+
*
|
|
10
|
+
* Only the page editor registers itself: an insm session measures a page, and secondary
|
|
11
|
+
* editors on the page (inline comments, nested legacy content extensions) would make the
|
|
12
|
+
* registration ambiguous.
|
|
13
|
+
*
|
|
14
|
+
* The element is held via a `WeakRef` so a destroyed editor's DOM can be collected even if
|
|
15
|
+
* `unregister` is never reached.
|
|
16
|
+
*/
|
|
17
|
+
export var EditorDomRegistry = /*#__PURE__*/function () {
|
|
18
|
+
function EditorDomRegistry() {
|
|
19
|
+
_classCallCheck(this, EditorDomRegistry);
|
|
20
|
+
}
|
|
21
|
+
return _createClass(EditorDomRegistry, [{
|
|
22
|
+
key: "register",
|
|
23
|
+
value:
|
|
24
|
+
/**
|
|
25
|
+
* Registers the page editor's content DOM element (`editorView.dom`).
|
|
26
|
+
*/
|
|
27
|
+
function register(editorDom) {
|
|
28
|
+
this.registered = new WeakRef(editorDom);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Unregisters an editor's content DOM element. Expected to be called when the editor is
|
|
33
|
+
* destroyed. Ignored when a different editor is currently registered, so an editor being
|
|
34
|
+
* torn down after its replacement registered does not clear the newer one.
|
|
35
|
+
*/
|
|
36
|
+
}, {
|
|
37
|
+
key: "unregister",
|
|
38
|
+
value: function unregister(editorDom) {
|
|
39
|
+
var _this$registered;
|
|
40
|
+
if (((_this$registered = this.registered) === null || _this$registered === void 0 ? void 0 : _this$registered.deref()) === editorDom) {
|
|
41
|
+
this.registered = undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The registered editor's content DOM, or undefined when no editor is registered or the
|
|
47
|
+
* registered one is no longer in the document -- ie. an experience without a page editor,
|
|
48
|
+
* or a session which outlived the editor.
|
|
49
|
+
*/
|
|
50
|
+
}, {
|
|
51
|
+
key: "editorDom",
|
|
52
|
+
get: function get() {
|
|
53
|
+
var _this$registered2;
|
|
54
|
+
var editorDom = (_this$registered2 = this.registered) === null || _this$registered2 === void 0 ? void 0 : _this$registered2.deref();
|
|
55
|
+
return editorDom !== null && editorDom !== void 0 && editorDom.isConnected ? editorDom : undefined;
|
|
56
|
+
}
|
|
57
|
+
}]);
|
|
58
|
+
}();
|
package/dist/esm/index.js
CHANGED
|
@@ -1,60 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
export function init(options) {
|
|
8
|
-
initialisedInsm = new INSM(options);
|
|
9
|
-
}
|
|
10
|
-
function insmInitialised() {
|
|
11
|
-
if (!initialisedInsm) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* **In**teractivity **s**ession **m**onitoring
|
|
19
|
-
*/
|
|
20
|
-
export var insm = {
|
|
21
|
-
startHeavyTask: function startHeavyTask(heavyTaskName) {
|
|
22
|
-
if (insmInitialised()) {
|
|
23
|
-
initialisedInsm.startHeavyTask(heavyTaskName);
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
endHeavyTask: function endHeavyTask(heavyTaskName) {
|
|
27
|
-
if (insmInitialised()) {
|
|
28
|
-
initialisedInsm.endHeavyTask(heavyTaskName);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
start: function start(experienceKey, experienceProperties) {
|
|
32
|
-
if (insmInitialised()) {
|
|
33
|
-
initialisedInsm.start(experienceKey, experienceProperties);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
overrideExperienceKey: function overrideExperienceKey(experienceKey) {
|
|
37
|
-
if (insmInitialised()) {
|
|
38
|
-
initialisedInsm.overrideExperienceKey(experienceKey);
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
stopEarly: function stopEarly(reasonKey, description) {
|
|
42
|
-
if (insmInitialised()) {
|
|
43
|
-
initialisedInsm.stopEarly(reasonKey, description);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
// We only expose details and feature start/stop to consumers
|
|
47
|
-
// as the other properties are internals for the insm and InsmPeriod
|
|
48
|
-
// to interact with the running session.
|
|
49
|
-
get session() {
|
|
50
|
-
if (insmInitialised()) {
|
|
51
|
-
return initialisedInsm.runningSession;
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
// @ts-expect-error Private method for testing purposes
|
|
55
|
-
__setAnalyticsWebClient: function __setAnalyticsWebClient(analyticsWebClient) {
|
|
56
|
-
if (initialisedInsm) {
|
|
57
|
-
initialisedInsm.analyticsWebClient = analyticsWebClient;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
};
|
|
1
|
+
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
+
// Entry file in package.json
|
|
3
|
+
// Barrel kept for existing consumers -- new call sites should import from the
|
|
4
|
+
// `@atlaskit/insm/api` entry point instead.
|
|
5
|
+
export { init, insm } from './api';
|
package/dist/esm/insm-session.js
CHANGED
|
@@ -7,6 +7,7 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
|
|
|
7
7
|
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; } }
|
|
8
8
|
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; }
|
|
9
9
|
import Bowser from 'bowser-ultralight';
|
|
10
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
10
11
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
11
12
|
import { PeriodTracking } from './insm-period';
|
|
12
13
|
import { LongAnimationFrameMeasurer } from './session-measurers/LongAnimationFrameMeasurer';
|
|
@@ -198,11 +199,14 @@ export var INSMSession = /*#__PURE__*/function () {
|
|
|
198
199
|
var operationalEvent = {
|
|
199
200
|
actionSubject: 'insm',
|
|
200
201
|
action: 'measured',
|
|
201
|
-
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, this.staticProperties), evaluatedAddedProperties), {}, {
|
|
202
|
+
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, this.staticProperties), evaluatedAddedProperties), {}, {
|
|
202
203
|
'event:population': this.insm.options.population,
|
|
203
204
|
experienceKey: this.experienceKey,
|
|
204
205
|
initial: this.experienceProperties.initial,
|
|
205
|
-
contentId: this.experienceProperties.contentId
|
|
206
|
+
contentId: this.experienceProperties.contentId
|
|
207
|
+
}, isExperimentEnabled('platform_editor_insm_dom_node_count') ? {
|
|
208
|
+
editorDomSize: this.insm.getEditorDomSize()
|
|
209
|
+
} : {}), {}, {
|
|
206
210
|
timing: {
|
|
207
211
|
startedAt: this.startedAt,
|
|
208
212
|
// Note: this will not match up with the periods sum of durations, as it includes
|
package/dist/esm/insm.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
import { countDomElements } from './dom-element-count';
|
|
5
|
+
import { EditorDomRegistry } from './editor-dom-registry';
|
|
4
6
|
import { INSMSession } from './insm-session';
|
|
5
7
|
import { AnimationFPSIM } from './period-measurers/afps';
|
|
6
8
|
import { INPTracker } from './inp-measurers/inp';
|
|
@@ -15,6 +17,11 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
15
17
|
* page session.
|
|
16
18
|
*/
|
|
17
19
|
_defineProperty(this, "runningHeavyTasks", new Set());
|
|
20
|
+
/**
|
|
21
|
+
* The editor is tracked at the insm layer (rather than per session) as it can
|
|
22
|
+
* outlive, or be mounted after, the session it is measured by.
|
|
23
|
+
*/
|
|
24
|
+
_defineProperty(this, "editorDomRegistry", new EditorDomRegistry());
|
|
18
25
|
this.periodMeasurers = [expValEquals('platform_editor_disable_afps', 'isEnabled', true) ? undefined : new AnimationFPSIM(), new INPTracker()];
|
|
19
26
|
this.options = options;
|
|
20
27
|
|
|
@@ -82,6 +89,50 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Registers the page editor's content DOM element (`editorView.dom`) with insm.
|
|
94
|
+
*
|
|
95
|
+
* insm does not locate the editor itself - the element is provided by the editor so
|
|
96
|
+
* that session events can report its DOM element count (`editorDomSize`).
|
|
97
|
+
*
|
|
98
|
+
* A session measures a page, so only the page's own editor should register. Secondary
|
|
99
|
+
* editors (inline comments, nested legacy content extensions) must not, as the
|
|
100
|
+
* reported size would then depend on which editor registered last.
|
|
101
|
+
*
|
|
102
|
+
* ```ts
|
|
103
|
+
* insm.registerEditorDom(editorView.dom);
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
}, {
|
|
107
|
+
key: "registerEditorDom",
|
|
108
|
+
value: function registerEditorDom(editorDom) {
|
|
109
|
+
this.editorDomRegistry.register(editorDom);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Unregisters the editor's content DOM element. This is expected to be called when
|
|
114
|
+
* the editor is destroyed.
|
|
115
|
+
*/
|
|
116
|
+
}, {
|
|
117
|
+
key: "unregisterEditorDom",
|
|
118
|
+
value: function unregisterEditorDom(editorDom) {
|
|
119
|
+
this.editorDomRegistry.unregister(editorDom);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The number of DOM elements inside the registered editor, used as a proxy for
|
|
124
|
+
* document complexity in performance events.
|
|
125
|
+
*
|
|
126
|
+
* Undefined when no editor is registered, or the registered one is no longer in
|
|
127
|
+
* the document.
|
|
128
|
+
*/
|
|
129
|
+
}, {
|
|
130
|
+
key: "getEditorDomSize",
|
|
131
|
+
value: function getEditorDomSize() {
|
|
132
|
+
var editorDom = this.editorDomRegistry.editorDom;
|
|
133
|
+
return editorDom ? countDomElements(editorDom) : undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
85
136
|
/**
|
|
86
137
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
87
138
|
* routing solution.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { INSMOptions } from './types';
|
|
2
|
+
import type { INSMSession } from './insm-session';
|
|
3
|
+
import { INSM } from './insm';
|
|
4
|
+
/**
|
|
5
|
+
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
6
|
+
*/
|
|
7
|
+
export declare function init(options: INSMOptions): void;
|
|
8
|
+
/**
|
|
9
|
+
* **In**teractivity **s**ession **m**onitoring
|
|
10
|
+
*/
|
|
11
|
+
export declare const insm: Pick<INSM, 'start' | 'stopEarly' | 'startHeavyTask' | 'endHeavyTask' | 'overrideExperienceKey' | 'registerEditorDom' | 'unregisterEditorDom'> & {
|
|
12
|
+
session: Pick<INSMSession, 'details' | 'startFeature' | 'endFeature' | 'addProperties' | 'setProperty'> | undefined;
|
|
13
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the total number of DOM elements inside the given element.
|
|
3
|
+
*
|
|
4
|
+
* Uses the native `getElementsByTagName('*')`, which counts descendants iteratively in the
|
|
5
|
+
* browser engine -- intentionally not a recursive JS walk, so it can't overflow the stack on
|
|
6
|
+
* very large documents.
|
|
7
|
+
*/
|
|
8
|
+
export declare function countDomElements(element: Element): number;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds the page editor's content DOM.
|
|
3
|
+
*
|
|
4
|
+
* insm holds no reference to the editor, so the element is registered from the outside — it is
|
|
5
|
+
* the same `editorView.dom` element the editor measures for the `editorDomSize` attribute on
|
|
6
|
+
* its INP event.
|
|
7
|
+
*
|
|
8
|
+
* Only the page editor registers itself: an insm session measures a page, and secondary
|
|
9
|
+
* editors on the page (inline comments, nested legacy content extensions) would make the
|
|
10
|
+
* registration ambiguous.
|
|
11
|
+
*
|
|
12
|
+
* The element is held via a `WeakRef` so a destroyed editor's DOM can be collected even if
|
|
13
|
+
* `unregister` is never reached.
|
|
14
|
+
*/
|
|
15
|
+
export declare class EditorDomRegistry {
|
|
16
|
+
private registered;
|
|
17
|
+
/**
|
|
18
|
+
* Registers the page editor's content DOM element (`editorView.dom`).
|
|
19
|
+
*/
|
|
20
|
+
register(editorDom: HTMLElement): void;
|
|
21
|
+
/**
|
|
22
|
+
* Unregisters an editor's content DOM element. Expected to be called when the editor is
|
|
23
|
+
* destroyed. Ignored when a different editor is currently registered, so an editor being
|
|
24
|
+
* torn down after its replacement registered does not clear the newer one.
|
|
25
|
+
*/
|
|
26
|
+
unregister(editorDom: HTMLElement): void;
|
|
27
|
+
/**
|
|
28
|
+
* The registered editor's content DOM, or undefined when no editor is registered or the
|
|
29
|
+
* registered one is no longer in the document -- ie. an experience without a page editor,
|
|
30
|
+
* or a session which outlived the editor.
|
|
31
|
+
*/
|
|
32
|
+
get editorDom(): HTMLElement | undefined;
|
|
33
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { INSMSession } from './insm-session';
|
|
3
|
-
import { INSM } from './insm';
|
|
4
|
-
/**
|
|
5
|
-
* Initializes the INSM (Interactivity Session Measurement) tooling
|
|
6
|
-
*/
|
|
7
|
-
export declare function init(options: INSMOptions): void;
|
|
8
|
-
/**
|
|
9
|
-
* **In**teractivity **s**ession **m**onitoring
|
|
10
|
-
*/
|
|
11
|
-
export declare const insm: Pick<INSM, 'start' | 'stopEarly' | 'startHeavyTask' | 'endHeavyTask' | 'overrideExperienceKey'> & {
|
|
12
|
-
session: Pick<INSMSession, 'details' | 'startFeature' | 'endFeature' | 'addProperties' | 'setProperty'> | undefined;
|
|
13
|
-
};
|
|
1
|
+
export { init, insm } from './api';
|
package/dist/types/insm.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export declare class INSM {
|
|
|
14
14
|
* page session.
|
|
15
15
|
*/
|
|
16
16
|
runningHeavyTasks: Set<string>;
|
|
17
|
+
/**
|
|
18
|
+
* The editor is tracked at the insm layer (rather than per session) as it can
|
|
19
|
+
* outlive, or be mounted after, the session it is measured by.
|
|
20
|
+
*/
|
|
21
|
+
private editorDomRegistry;
|
|
17
22
|
constructor(options: INSMOptions);
|
|
18
23
|
/**
|
|
19
24
|
* Starts a heavy task in the currently running session.
|
|
@@ -28,6 +33,34 @@ export declare class INSM {
|
|
|
28
33
|
* Ends a heavy task in the currently running session
|
|
29
34
|
*/
|
|
30
35
|
endHeavyTask(heavyTaskName: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Registers the page editor's content DOM element (`editorView.dom`) with insm.
|
|
38
|
+
*
|
|
39
|
+
* insm does not locate the editor itself - the element is provided by the editor so
|
|
40
|
+
* that session events can report its DOM element count (`editorDomSize`).
|
|
41
|
+
*
|
|
42
|
+
* A session measures a page, so only the page's own editor should register. Secondary
|
|
43
|
+
* editors (inline comments, nested legacy content extensions) must not, as the
|
|
44
|
+
* reported size would then depend on which editor registered last.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* insm.registerEditorDom(editorView.dom);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
registerEditorDom(editorDom: HTMLElement): void;
|
|
51
|
+
/**
|
|
52
|
+
* Unregisters the editor's content DOM element. This is expected to be called when
|
|
53
|
+
* the editor is destroyed.
|
|
54
|
+
*/
|
|
55
|
+
unregisterEditorDom(editorDom: HTMLElement): void;
|
|
56
|
+
/**
|
|
57
|
+
* The number of DOM elements inside the registered editor, used as a proxy for
|
|
58
|
+
* document complexity in performance events.
|
|
59
|
+
*
|
|
60
|
+
* Undefined when no editor is registered, or the registered one is no longer in
|
|
61
|
+
* the document.
|
|
62
|
+
*/
|
|
63
|
+
getEditorDomSize(): number | undefined;
|
|
31
64
|
/**
|
|
32
65
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
33
66
|
* routing solution.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/insm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "INSM tooling measures user-perceived interactivity of a page",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"atlaskit:src": "src/index.ts",
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@atlaskit/analytics-listeners": "^11.1.0",
|
|
21
|
-
"@atlaskit/
|
|
21
|
+
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
22
|
+
"@atlaskit/tmp-editor-statsig": "^147.0.0",
|
|
22
23
|
"@babel/runtime": "^7.0.0",
|
|
23
24
|
"bowser-ultralight": "^1.0.6"
|
|
24
25
|
},
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
"react": "^18.2.0 || ^19.2.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
30
|
+
"@atlassian/experiment-test-utils": "^0.2.0",
|
|
29
31
|
"@atlassian/structured-docs-types": "workspace:^",
|
|
30
32
|
"react": "^19.2.0"
|
|
31
33
|
}
|