From dd016d870a9637aeb6cc7bca6db3ea88433e2178 Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Tue, 14 May 2024 16:04:49 -0700 Subject: [PATCH 1/5] breaking out the style states into 2 fields and ensuring we dont reset in the middle of capturing subsequent pages --- lerna.json | 2 +- packages/clarity-decode/package.json | 2 +- packages/clarity-devtools/package.json | 2 +- packages/clarity-devtools/static/manifest.json | 4 ++-- packages/clarity-js/package.json | 2 +- packages/clarity-js/src/core/version.ts | 2 +- packages/clarity-js/src/insight/blank.ts | 2 ++ packages/clarity-js/src/insight/style.ts | 8 ++++---- packages/clarity-js/src/layout/encode.ts | 9 ++++----- packages/clarity-js/src/layout/style.ts | 13 +++++++------ packages/clarity-visualize/package.json | 2 +- 11 files changed, 25 insertions(+), 23 deletions(-) diff --git a/lerna.json b/lerna.json index 4101c39c..5f9363da 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.7.34", + "version": "0.7.35", "npmClient": "yarn", "useWorkspaces": true } diff --git a/packages/clarity-decode/package.json b/packages/clarity-decode/package.json index 70246019..b82ed02d 100644 --- a/packages/clarity-decode/package.json +++ b/packages/clarity-decode/package.json @@ -1,6 +1,6 @@ { "name": "clarity-decode", - "version": "0.7.34", + "version": "0.7.35", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", diff --git a/packages/clarity-devtools/package.json b/packages/clarity-devtools/package.json index 54181492..ff5a0bc4 100644 --- a/packages/clarity-devtools/package.json +++ b/packages/clarity-devtools/package.json @@ -1,6 +1,6 @@ { "name": "clarity-devtools", - "version": "0.7.34", + "version": "0.7.35", "private": true, "description": "Adds Clarity debugging support to browser devtools", "author": "Microsoft Corp.", diff --git a/packages/clarity-devtools/static/manifest.json b/packages/clarity-devtools/static/manifest.json index a780545c..ef240072 100644 --- a/packages/clarity-devtools/static/manifest.json +++ b/packages/clarity-devtools/static/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 2, "name": "Microsoft Clarity Developer Tools", "description": "Clarity helps you understand how users are interacting with your website.", - "version": "0.7.34", - "version_name": "0.7.34", + "version": "0.7.35", + "version_name": "0.7.35", "minimum_chrome_version": "50", "devtools_page": "devtools.html", "icons": { diff --git a/packages/clarity-js/package.json b/packages/clarity-js/package.json index 9f70765b..00df8db9 100644 --- a/packages/clarity-js/package.json +++ b/packages/clarity-js/package.json @@ -1,6 +1,6 @@ { "name": "clarity-js", - "version": "0.7.34", + "version": "0.7.35", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", diff --git a/packages/clarity-js/src/core/version.ts b/packages/clarity-js/src/core/version.ts index cbf00ad8..27eb0a1f 100644 --- a/packages/clarity-js/src/core/version.ts +++ b/packages/clarity-js/src/core/version.ts @@ -1,2 +1,2 @@ -let version = "0.7.34"; +let version = "0.7.35"; export default version; diff --git a/packages/clarity-js/src/insight/blank.ts b/packages/clarity-js/src/insight/blank.ts index 9f88a6c7..4ee308c4 100644 --- a/packages/clarity-js/src/insight/blank.ts +++ b/packages/clarity-js/src/insight/blank.ts @@ -1,4 +1,6 @@ export let state = []; +export let sheetAdoptionState = []; +export let sheetUpdateState = []; export let data = null; /* Intentionally blank module with empty code */ diff --git a/packages/clarity-js/src/insight/style.ts b/packages/clarity-js/src/insight/style.ts index 965c6ae7..aedc7940 100644 --- a/packages/clarity-js/src/insight/style.ts +++ b/packages/clarity-js/src/insight/style.ts @@ -3,13 +3,12 @@ import { StyleSheetState } from "@clarity-types/layout"; import * as core from "@src/core"; import * as metric from "@src/data/metric"; -export let state: StyleSheetState[] = []; +export let sheetAdoptionState: StyleSheetState[] = []; +export let sheetUpdateState: StyleSheetState[] = []; let replace: (text?: string) => Promise = null; let replaceSync: (text?: string) => void = null; export function start(): void { - reset(); - if (replace === null) { replace = CSSStyleSheet.prototype.replace; CSSStyleSheet.prototype.replace = function(): Promise { @@ -44,7 +43,8 @@ export function compute(): void { } export function reset(): void { - state = []; + sheetAdoptionState = []; + sheetUpdateState = []; } export function stop(): void { diff --git a/packages/clarity-js/src/layout/encode.ts b/packages/clarity-js/src/layout/encode.ts index 3400bf48..a0ddb294 100644 --- a/packages/clarity-js/src/layout/encode.ts +++ b/packages/clarity-js/src/layout/encode.ts @@ -38,17 +38,15 @@ export default async function (type: Event, timer: Timer = null, ts: number = nu region.reset(); break; case Event.StyleSheetAdoption: - for (let entry of style.state) { + case Event.StyleSheetUpdate: + for (let entry of style.sheetAdoptionState) { tokens = [entry.time, entry.event]; tokens.push(entry.data.id); tokens.push(entry.data.operation); tokens.push(entry.data.newIds); queue(tokens); } - style.reset(); - break; - case Event.StyleSheetUpdate: - for (let entry of style.state) { + for (let entry of style.sheetUpdateState) { tokens = [entry.time, entry.event]; tokens.push(entry.data.id); tokens.push(entry.data.operation); @@ -56,6 +54,7 @@ export default async function (type: Event, timer: Timer = null, ts: number = nu queue(tokens); } style.reset(); + break; case Event.Animation: for (let entry of animation.state) { tokens = [entry.time, entry.event]; diff --git a/packages/clarity-js/src/layout/style.ts b/packages/clarity-js/src/layout/style.ts index e7b9ca87..b6757416 100644 --- a/packages/clarity-js/src/layout/style.ts +++ b/packages/clarity-js/src/layout/style.ts @@ -7,8 +7,10 @@ import { getId, getNode } from "@src/layout/dom"; import * as core from "@src/core"; import { getCssRules } from "./node"; import * as metric from "@src/data/metric"; +import { schedule } from "@src/core/task"; -export let state: StyleSheetState[] = []; +export let sheetUpdateState: StyleSheetState[] = []; +export let sheetAdoptionState: StyleSheetState[] = []; let replace: (text?: string) => Promise = null; let replaceSync: (text?: string) => void = null; const styleSheetId = 'claritySheetId'; @@ -17,8 +19,6 @@ let styleSheetMap = {}; let styleTimeMap: {[key: string]: number} = {}; export function start(): void { - reset(); - if (replace === null) { replace = CSSStyleSheet.prototype.replace; CSSStyleSheet.prototype.replace = function(): Promise { @@ -96,7 +96,8 @@ export function compute(): void { } export function reset(): void { - state = []; + sheetAdoptionState = []; + sheetUpdateState = []; } export function stop(): void { @@ -106,7 +107,7 @@ export function stop(): void { } function trackStyleChange(time: number, id: string, operation: StyleSheetOperation, cssRules?: string): void { - state.push({ + sheetUpdateState.push({ time, event: Event.StyleSheetUpdate, data: { @@ -120,7 +121,7 @@ function trackStyleChange(time: number, id: string, operation: StyleSheetOperati } function trackStyleAdoption(time: number, id: number, operation: StyleSheetOperation, newIds: string[]): void { - state.push({ + sheetAdoptionState.push({ time, event: Event.StyleSheetAdoption, data: { diff --git a/packages/clarity-visualize/package.json b/packages/clarity-visualize/package.json index fdbc0060..688408fe 100644 --- a/packages/clarity-visualize/package.json +++ b/packages/clarity-visualize/package.json @@ -1,6 +1,6 @@ { "name": "clarity-visualize", - "version": "0.7.34", + "version": "0.7.35", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", From 52760a1891d4da02986083e8b81c0310b453d3da Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Wed, 15 May 2024 07:46:09 -0700 Subject: [PATCH 2/5] removing unused import --- packages/clarity-js/rollup.config.ts | 4 ++-- packages/clarity-js/src/layout/style.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/clarity-js/rollup.config.ts b/packages/clarity-js/rollup.config.ts index d07f0523..cc5e9ec0 100644 --- a/packages/clarity-js/rollup.config.ts +++ b/packages/clarity-js/rollup.config.ts @@ -15,7 +15,7 @@ export default [ plugins: [ alias({ entries: [ - { find: '@src/layout/style', replacement: '@src/insight/style' } + { find: '@src/layout/style', replacement: '@src/layout/style' } ] }), resolve(), @@ -37,7 +37,7 @@ export default [ plugins: [ alias({ entries: [ - { find: '@src/layout/style', replacement: '@src/insight/blank' } + { find: '@src/layout/style', replacement: '@src/layout/style' } ] }), resolve(), diff --git a/packages/clarity-js/src/layout/style.ts b/packages/clarity-js/src/layout/style.ts index b6757416..276f6026 100644 --- a/packages/clarity-js/src/layout/style.ts +++ b/packages/clarity-js/src/layout/style.ts @@ -7,7 +7,6 @@ import { getId, getNode } from "@src/layout/dom"; import * as core from "@src/core"; import { getCssRules } from "./node"; import * as metric from "@src/data/metric"; -import { schedule } from "@src/core/task"; export let sheetUpdateState: StyleSheetState[] = []; export let sheetAdoptionState: StyleSheetState[] = []; From 6acca304da51022581fae272b4ab2efc77d68c73 Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Wed, 15 May 2024 08:16:37 -0700 Subject: [PATCH 3/5] unintended rollup change --- packages/clarity-js/rollup.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/clarity-js/rollup.config.ts b/packages/clarity-js/rollup.config.ts index cc5e9ec0..d07f0523 100644 --- a/packages/clarity-js/rollup.config.ts +++ b/packages/clarity-js/rollup.config.ts @@ -15,7 +15,7 @@ export default [ plugins: [ alias({ entries: [ - { find: '@src/layout/style', replacement: '@src/layout/style' } + { find: '@src/layout/style', replacement: '@src/insight/style' } ] }), resolve(), @@ -37,7 +37,7 @@ export default [ plugins: [ alias({ entries: [ - { find: '@src/layout/style', replacement: '@src/layout/style' } + { find: '@src/layout/style', replacement: '@src/insight/blank' } ] }), resolve(), From 1a63174cd59bfc06643a0acb2c3a5f5e6ee45166 Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Wed, 15 May 2024 11:43:33 -0700 Subject: [PATCH 4/5] only creating stylesheets when documents reference them --- packages/clarity-js/src/layout/style.ts | 34 ++++++++++++------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/clarity-js/src/layout/style.ts b/packages/clarity-js/src/layout/style.ts index 276f6026..4fe4007a 100644 --- a/packages/clarity-js/src/layout/style.ts +++ b/packages/clarity-js/src/layout/style.ts @@ -23,8 +23,12 @@ export function start(): void { CSSStyleSheet.prototype.replace = function(): Promise { if (core.active()) { metric.max(Metric.ConstructedStyles, 1); - bootStrapStyleSheet(this); - trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.Replace, arguments[0]); + // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it + // and attached the sheet to a document. This way the timestamp of the style sheet creation will align + // to when it is used in the document rather than potentially being misaligned during the traverse process. + if (this[styleSheetPageNum] === metadataFields.pageNum) { + trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.Replace, arguments[0]); + } } return replace.apply(this, arguments); }; @@ -35,27 +39,18 @@ export function start(): void { CSSStyleSheet.prototype.replaceSync = function(): void { if (core.active()) { metric.max(Metric.ConstructedStyles, 1); - bootStrapStyleSheet(this); - trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.ReplaceSync, arguments[0]); + // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it + // and attached the sheet to a document. This way the timestamp of the style sheet creation will align + // to when it is used in the document rather than potentially being misaligned during the traverse process. + if (this[styleSheetPageNum] === metadataFields.pageNum) { + trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.ReplaceSync, arguments[0]); + } } return replaceSync.apply(this, arguments); }; } } -function bootStrapStyleSheet(styleSheet: CSSStyleSheet): void { - // If we haven't seen this style sheet on this page yet, we create a reference to it for the visualizer. - // For SPA or times in which Clarity restarts on a given page, our visualizer would lose context - // on the previously created style sheet for page N-1. - const pageNum = metadataFields.pageNum; - if (styleSheet[styleSheetPageNum] !== pageNum) { - styleSheet[styleSheetPageNum] = pageNum; - styleSheet[styleSheetId] = shortid(); - // need to pass a create style sheet event (don't add it to any nodes, but do create it) - trackStyleChange(time(), styleSheet[styleSheetId], StyleSheetOperation.Create); - } -} - export function checkDocumentStyles(documentNode: Document, timestamp: number): void { timestamp = timestamp || time(); if (!documentNode?.adoptedStyleSheets) { @@ -66,7 +61,10 @@ export function checkDocumentStyles(documentNode: Document, timestamp: number): let currentStyleSheets: string[] = []; for (var styleSheet of documentNode.adoptedStyleSheets) { const pageNum = metadataFields.pageNum; - // if we haven't seen this style sheet, create it and call replaceSync with its contents to bootstrap it + // If we haven't seen this style sheet on this page yet, we create a reference to it for the visualizer. + // For SPA or times in which Clarity restarts on a given page, our visualizer would lose context + // on the previously created style sheet for page N-1. + // Then we synthetically call replaceSync with its contents to bootstrap it if (styleSheet[styleSheetPageNum] !== pageNum) { styleSheet[styleSheetPageNum] = pageNum; styleSheet[styleSheetId] = shortid(); From d219f6d750fcb1e5cd149790ce94708c67a8127e Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Thu, 16 May 2024 10:21:57 -0700 Subject: [PATCH 5/5] ensuring we look at all documents for sytle changes --- packages/clarity-js/src/layout/style.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/clarity-js/src/layout/style.ts b/packages/clarity-js/src/layout/style.ts index 4fe4007a..e78b1f1b 100644 --- a/packages/clarity-js/src/layout/style.ts +++ b/packages/clarity-js/src/layout/style.ts @@ -3,7 +3,7 @@ import { StyleSheetOperation, StyleSheetState } from "@clarity-types/layout"; import { time } from "@src/core/time"; import { shortid, data as metadataFields } from "@src/data/metadata"; import encode from "@src/layout/encode"; -import { getId, getNode } from "@src/layout/dom"; +import { getId } from "@src/layout/dom"; import * as core from "@src/core"; import { getCssRules } from "./node"; import * as metric from "@src/data/metric"; @@ -16,6 +16,7 @@ const styleSheetId = 'claritySheetId'; const styleSheetPageNum = 'claritySheetNum'; let styleSheetMap = {}; let styleTimeMap: {[key: string]: number} = {}; +let documentNodes = []; export function start(): void { if (replace === null) { @@ -52,6 +53,9 @@ export function start(): void { } export function checkDocumentStyles(documentNode: Document, timestamp: number): void { + if (documentNodes.indexOf(documentNode) === -1) { + documentNodes.push(documentNode); + } timestamp = timestamp || time(); if (!documentNode?.adoptedStyleSheets) { // if we don't have adoptedStyledSheets on the Node passed to us, we can short circuit. @@ -87,9 +91,11 @@ export function checkDocumentStyles(documentNode: Document, timestamp: number): } export function compute(): void { - let ts = -1 in styleTimeMap ? styleTimeMap[-1] : null; - checkDocumentStyles(document, ts); - Object.keys(styleSheetMap).forEach((x) => checkDocumentStyles(getNode(parseInt(x, 10)) as Document, styleTimeMap[x])); + for (var documentNode of documentNodes) { + var docId = documentNode == document ? -1 : getId(documentNode); + let ts = docId in styleTimeMap ? styleTimeMap[docId] : null; + checkDocumentStyles(document, ts); + } } export function reset(): void { @@ -100,6 +106,7 @@ export function reset(): void { export function stop(): void { styleSheetMap = {}; styleTimeMap = {}; + documentNodes = []; reset(); }