Skip to content

Commit 3c5d40d

Browse files
committed
chore: update build scripts and enhance file handling
- Added a warning message to the build scripts in both root and scan package to remind developers to bump the version before building. - Refactored file handling in `tsup.config.ts` to use `fs/promises` for asynchronous file operations. - Enhanced the `flush` function in the network monitoring module to improve interaction handling and ensure proper session management. - Updated type definitions for `Interaction` and `Component` to allow for numeric interaction IDs. - Modified the `getSession` function to include the package version in the session data.
1 parent c62ecfc commit 3c5d40d

File tree

7 files changed

+65
-88
lines changed

7 files changed

+65
-88
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "root",
33
"private": true,
44
"scripts": {
5-
"build": "pnpm --parallel --filter=!extension build",
5+
"build": "pnpm --parallel --filter=!extension build && echo '\\n\\x1b[43m\\x1b[30m⚠️ WARNING: MAKE SURE TO BUMP VERSION BEFORE BUILDING OR REBUILD AFTER BUMPING VERSION IF PUBLISHING ⚠️\\x1b[0m\\n\\n'",
66
"dev": "pnpm --parallel --filter=!extension dev",
77
"pack": "pnpm --parallel --filter=!extension pack",
88
"pack:bump": "pnpm --filter scan pack:bump",

packages/scan/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
"auto.d.ts"
215215
],
216216
"scripts": {
217-
"build": "NODE_ENV=production tsup",
217+
"build": "NODE_ENV=production tsup && echo '\\n\\x1b[43m\\x1b[30m⚠️ WARNING: MAKE SURE TO BUMP VERSION BEFORE BUILDING OR REBUILD AFTER BUMPING VERSION ⚠️\\x1b[0m\\n\\n'",
218218
"postbuild": "pnpm copy-astro",
219219
"build:copy": "NODE_ENV=production tsup && cat dist/auto.global.js | pbcopy",
220220
"copy-astro": "cp -R src/core/monitor/params/astro dist/core/monitor/params",

packages/scan/src/core/monitor/network.ts

Lines changed: 47 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,25 @@ import {
88
import { getSession } from './utils';
99
import type { Interaction, IngestRequest, InternalInteraction, Component } from './types';
1010

11-
const getInteractionId = (interaction: InternalInteraction) =>
12-
`${interaction.performanceEntry.type}::<REPLACED_PATH>::${interaction.url}`; // We replace the path with <REPLACED_PATH> on ingest with the component path joined by `.`
13-
1411
const INTERACTION_TIME_TILL_COMPLETED = 4000;
1512

16-
const splitInteractions = (interactions: Array<InternalInteraction>) => {
13+
export const flush = async (): Promise<void> => {
14+
const monitor = Store.monitor.value;
15+
if (
16+
!monitor ||
17+
!navigator.onLine ||
18+
!monitor.url ||
19+
!monitor.interactions.length
20+
) {
21+
return;
22+
}
1723
const now = performance.now();
24+
// We might trigger flush before the interaction is completed,
25+
// so we need to split them into pending and completed by an arbitrary time.
1826
const pendingInteractions = new Array<InternalInteraction>();
1927
const completedInteractions = new Array<InternalInteraction>();
2028

29+
const interactions = monitor.interactions;
2130
for (let i = 0; i < interactions.length; i++) {
2231
const interaction = interactions[i];
2332
if (
@@ -30,84 +39,51 @@ const splitInteractions = (interactions: Array<InternalInteraction>) => {
3039
}
3140
}
3241

33-
return { pendingInteractions, completedInteractions };
34-
};
42+
// nothing to flush
43+
if (!completedInteractions.length) return;
3544

36-
const aggregateComponents = (interactions: Array<InternalInteraction>) => {
37-
const aggregatedComponents = new Array<Component>();
45+
// idempotent
46+
const session = await getSession({
47+
commit: monitor.commit,
48+
branch: monitor.branch,
49+
}).catch(() => null);
3850

39-
for (const interaction of interactions) {
40-
for (const [name, component] of Array.from(
41-
interaction.components.entries(),
42-
)) {
51+
if (!session) return;
52+
53+
const aggregatedComponents = new Array<Component>();
54+
const aggregatedInteractions = new Array<Interaction>();
55+
for (let i = 0; i < completedInteractions.length; i++) {
56+
const interaction = completedInteractions[i];
57+
58+
aggregatedInteractions.push({
59+
id: i,
60+
path: interaction.componentPath,
61+
name: interaction.componentName,
62+
time: interaction.performanceEntry.duration,
63+
timestamp: interaction.performanceEntry.timestamp,
64+
type: interaction.performanceEntry.type,
65+
url: interaction.url,
66+
route: interaction.route,
67+
commit: interaction.commit,
68+
branch: interaction.branch,
69+
uniqueInteractionId: interaction.uniqueInteractionId,
70+
});
71+
72+
const components = Array.from(interaction.components.entries());
73+
for (let j = 0; j < components.length; j++) {
74+
const [name, component] = components[j];
4375
aggregatedComponents.push({
4476
name,
4577
instances: component.fibers.size,
46-
interactionId: getInteractionId(interaction),
78+
interactionId: i,
4779
renders: component.renders,
4880
totalTime: component.totalTime,
4981
});
50-
51-
if (component.retiresAllowed === 0) {
52-
// otherwise there will be a memory leak if the user loses internet or our server goes down
53-
// we decide to skip the collection if this is the case
54-
interaction.components.delete(name);
55-
}
56-
57-
component.retiresAllowed -= 1;
5882
}
5983
}
60-
return aggregatedComponents;
61-
};
62-
63-
const toPayloadInteraction = (interactions: Array<InternalInteraction>) =>
64-
interactions.map(
65-
(interaction) =>
66-
({
67-
id: getInteractionId(interaction),
68-
path: interaction.componentPath,
69-
name: interaction.componentName,
70-
time: interaction.performanceEntry.duration,
71-
timestamp: interaction.performanceEntry.timestamp,
72-
type: interaction.performanceEntry.type,
73-
url: interaction.url,
74-
route: interaction.route,
75-
commit: interaction.commit,
76-
branch: interaction.branch,
77-
uniqueInteractionId: interaction.uniqueInteractionId,
78-
}) satisfies Interaction,
79-
);
80-
81-
export const flush = async (): Promise<void> => {
82-
const monitor = Store.monitor.value;
83-
if (
84-
!monitor ||
85-
!navigator.onLine ||
86-
!monitor.url ||
87-
!monitor.interactions.length
88-
) {
89-
return;
90-
}
91-
const { completedInteractions, pendingInteractions } = splitInteractions(
92-
monitor.interactions,
93-
);
94-
95-
// nothing to flush
96-
if (!completedInteractions.length) {
97-
return;
98-
}
99-
// idempotent
100-
const session = await getSession({
101-
commit: monitor.commit,
102-
branch: monitor.branch,
103-
}).catch(() => null);
104-
105-
if (!session) return;
106-
107-
const aggregatedComponents = aggregateComponents(monitor.interactions);
10884

10985
const payload: IngestRequest = {
110-
interactions: toPayloadInteraction(completedInteractions),
86+
interactions: aggregatedInteractions,
11187
components: aggregatedComponents,
11288
session: {
11389
...session,
@@ -117,14 +93,7 @@ export const flush = async (): Promise<void> => {
11793
};
11894

11995
monitor.pendingRequests++;
120-
// remove all completed interactions from batch
121-
monitor.interactions = monitor.interactions.filter((interaction) =>
122-
completedInteractions.some(
123-
(completedInteraction) =>
124-
completedInteraction.performanceEntry.id !==
125-
interaction.performanceEntry.id,
126-
),
127-
);
96+
monitor.interactions = pendingInteractions;
12897
try {
12998
transport(monitor.url, payload)
13099
.then(() => {

packages/scan/src/core/monitor/performance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ export function initPerformanceMonitoring(options?: Partial<PathFilters>) {
195195
performanceEntry: entry,
196196
components: new Map(),
197197
url: window.location.toString(),
198-
route: Store.monitor.value?.route ?? null,
198+
route:
199+
Store.monitor.value?.route ?? new URL(window.location.href).pathname,
199200
commit: Store.monitor.value?.commit ?? null,
200201
branch: Store.monitor.value?.branch ?? null,
201202
uniqueInteractionId: entry.id,

packages/scan/src/core/monitor/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ export interface Session {
2222
}
2323

2424
export interface Interaction {
25-
id: string; // a hashed unique id for interaction (groupable across sessions)
25+
id: string | number; // index of the interaction in the batch at ingest | server converts to a hashed string from route, type, name, path
2626
path: Array<string>; // the path of the interaction
27-
name: string; // name of interaction (i.e nav#top-menu.sc-601d0142-19.gHiJkL) or something useful
27+
name: string; // name of interaction
2828
type: string; // type of interaction i.e pointer
2929
time: number; // time of interaction in ms
3030
timestamp: number;
@@ -42,7 +42,7 @@ export interface Interaction {
4242
}
4343

4444
export interface Component {
45-
interactionId: string; // grouping components by interaction
45+
interactionId: string | number; // grouping components by interaction
4646
name: string;
4747
renders: number; // how many times it re-rendered / instances (normalized)
4848
instances: number; // instances which will be used to get number of total renders by * by renders

packages/scan/src/core/monitor/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export const getSession = async ({
117117
agent: navigator.userAgent,
118118
commit,
119119
branch,
120+
version: process.env.NPM_PACKAGE_VERSION,
120121
};
121122
cachedSession = session;
122123
return session;

packages/scan/tsup.config.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
import fs from 'node:fs/promises';
1+
import fsPromise from 'node:fs/promises';
2+
import * as fs from 'node:fs';
23
import path from 'node:path';
34
import { defineConfig } from 'tsup';
45

56
const DIST_PATH = './dist';
67

78
const addDirectivesToChunkFiles = async (readPath: string): Promise<void> => {
89
try {
9-
const files = await fs.readdir(readPath);
10+
const files = await fsPromise.readdir(readPath);
1011
for (const file of files) {
1112
if (file.endsWith('.mjs') || file.endsWith('.js')) {
1213
const filePath = path.join(readPath, file);
1314

14-
const data = await fs.readFile(filePath, 'utf8');
15+
const data = await fsPromise.readFile(filePath, 'utf8');
1516

1617
const updatedContent = `'use client';\n${data}`;
1718

18-
await fs.writeFile(filePath, updatedContent, 'utf8');
19+
await fsPromise.writeFile(filePath, updatedContent, 'utf8');
1920

2021
// eslint-disable-next-line no-console
2122
console.log(`Directive has been added to ${file}`);
@@ -84,6 +85,11 @@ export default defineConfig([
8485
minify: false,
8586
env: {
8687
NODE_ENV: process.env.NODE_ENV ?? 'development',
88+
NPM_PACKAGE_VERSION: JSON.parse(fs.readFileSync(
89+
path.join(__dirname, '../scan', 'package.json'),
90+
'utf8',
91+
),
92+
).version,
8793
},
8894
external: [
8995
'react',

0 commit comments

Comments
 (0)