@memlab/lens 1.0.0 → 1.0.1

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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/config.d.ts +22 -0
  3. package/dist/core/dom-observer.d.ts +10 -0
  4. package/dist/core/event-listener-tracker.d.ts +33 -0
  5. package/dist/core/react-fiber-analysis.d.ts +4 -0
  6. package/dist/core/react-memory-scan.d.ts +36 -0
  7. package/{src/core/types.ts → dist/core/types.d.ts} +56 -80
  8. package/{src/index.ts → dist/core/valid-component-name.d.ts} +2 -7
  9. package/dist/extensions/basic-extension.d.ts +30 -0
  10. package/dist/extensions/dom-visualization-extension.d.ts +17 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/memlens.lib.bundle.js +1695 -0
  13. package/dist/memlens.lib.bundle.min.js +1 -0
  14. package/dist/memlens.lib.d.ts +12 -0
  15. package/dist/memlens.run.bundle.js +2673 -0
  16. package/dist/memlens.run.bundle.min.js +1 -0
  17. package/dist/memlens.run.d.ts +1 -0
  18. package/dist/tests/bundle/lib.bundle.test.d.ts +1 -0
  19. package/dist/tests/bundle/run.bundle.start.head.test.d.ts +1 -0
  20. package/dist/tests/bundle/run.bundle.start.test.d.ts +1 -0
  21. package/dist/tests/bundle/run.bundle.test.d.ts +1 -0
  22. package/dist/tests/fiber/dev.fiber.complex.dev.test.d.ts +1 -0
  23. package/dist/tests/fiber/dev.fiber.complex.list.dev.test.d.ts +1 -0
  24. package/dist/tests/fiber/dev.fiber.complex.prod.test.d.ts +1 -0
  25. package/dist/tests/fiber/dev.fiber.name.dev.test.d.ts +1 -0
  26. package/dist/tests/fiber/dev.fiber.name.prod.test.d.ts +1 -0
  27. package/dist/tests/utils/test-utils.d.ts +11 -0
  28. package/dist/utils/intersection-observer.d.ts +18 -0
  29. package/dist/utils/react-fiber-utils.d.ts +56 -0
  30. package/dist/utils/utils.d.ts +26 -0
  31. package/dist/utils/weak-ref-utils.d.ts +67 -0
  32. package/dist/visual/components/component-stack-panel.d.ts +11 -0
  33. package/dist/visual/components/control-widget.d.ts +13 -0
  34. package/dist/visual/components/overlay-rectangle.d.ts +11 -0
  35. package/dist/visual/components/status-text.d.ts +2 -0
  36. package/dist/visual/components/toggle-button.d.ts +3 -0
  37. package/dist/visual/components/visual-overlay.d.ts +1 -0
  38. package/dist/visual/dom-element-visualizer-interactive.d.ts +26 -0
  39. package/{src/core/valid-component-name.ts → dist/visual/dom-element-visualizer.d.ts} +5 -7
  40. package/dist/visual/visual-utils.d.ts +16 -0
  41. package/package.json +5 -1
  42. package/explainer.md +0 -54
  43. package/playwright.config.ts +0 -21
  44. package/src/config/config.ts +0 -32
  45. package/src/core/dom-observer.ts +0 -189
  46. package/src/core/event-listener-tracker.ts +0 -171
  47. package/src/core/react-fiber-analysis.ts +0 -123
  48. package/src/core/react-memory-scan.ts +0 -366
  49. package/src/extensions/basic-extension.ts +0 -41
  50. package/src/extensions/dom-visualization-extension.ts +0 -42
  51. package/src/memlens.lib.js.flow +0 -75
  52. package/src/memlens.lib.ts +0 -22
  53. package/src/memlens.run.ts +0 -21
  54. package/src/tests/bundle/lib.bundle.test.ts +0 -31
  55. package/src/tests/bundle/run.bundle.start.head.test.ts +0 -48
  56. package/src/tests/bundle/run.bundle.start.test.ts +0 -48
  57. package/src/tests/bundle/run.bundle.test.ts +0 -51
  58. package/src/tests/fiber/dev.fiber.complex.dev.test.ts +0 -92
  59. package/src/tests/fiber/dev.fiber.complex.list.dev.test.ts +0 -118
  60. package/src/tests/fiber/dev.fiber.complex.prod.test.ts +0 -92
  61. package/src/tests/fiber/dev.fiber.name.dev.test.ts +0 -77
  62. package/src/tests/fiber/dev.fiber.name.prod.test.ts +0 -79
  63. package/src/tests/lib/babel.prod.js +0 -4
  64. package/src/tests/lib/react-dom-v18.dev.js +0 -29926
  65. package/src/tests/lib/react-dom-v18.prod.js +0 -269
  66. package/src/tests/lib/react-v18.dev.js +0 -3345
  67. package/src/tests/lib/react-v18.prod.js +0 -33
  68. package/src/tests/manual/playwright-open-manual.js +0 -40
  69. package/src/tests/manual/todo-list/todo-with-run.bundle.html +0 -80
  70. package/src/tests/utils/test-utils.ts +0 -28
  71. package/src/utils/intersection-observer.ts +0 -65
  72. package/src/utils/react-fiber-utils.ts +0 -212
  73. package/src/utils/utils.ts +0 -201
  74. package/src/utils/weak-ref-utils.ts +0 -308
  75. package/src/visual/components/component-stack-panel.ts +0 -85
  76. package/src/visual/components/control-widget.ts +0 -96
  77. package/src/visual/components/overlay-rectangle.ts +0 -167
  78. package/src/visual/components/status-text.ts +0 -53
  79. package/src/visual/components/toggle-button.ts +0 -57
  80. package/src/visual/components/visual-overlay.ts +0 -19
  81. package/src/visual/dom-element-visualizer-interactive.ts +0 -358
  82. package/src/visual/dom-element-visualizer.ts +0 -130
  83. package/src/visual/visual-utils.ts +0 -89
  84. package/tsconfig.json +0 -18
  85. package/webpack.config.js +0 -105
@@ -1,366 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import type {Fiber} from 'react-reconciler';
11
- import type {
12
- AnalysisResult,
13
- AnalysisResultCallback,
14
- BoundingRect,
15
- CreateOptions,
16
- DOMElementInfo,
17
- Optional,
18
- ScanResult,
19
- AnyValue,
20
- EventListenerLeak,
21
- Nullable,
22
- } from './types';
23
- import type {BasicExtension} from '../extensions/basic-extension';
24
-
25
- import * as utils from '../utils/utils';
26
- import ReactFiberAnalyzer from './react-fiber-analysis';
27
- import {
28
- getFiberNodeFromElement,
29
- getReactComponentStack,
30
- } from '../utils/react-fiber-utils';
31
- import {DOMObserver} from './dom-observer';
32
- import {config} from '../config/config';
33
- import {EventListenerTracker} from './event-listener-tracker';
34
-
35
- export default class ReactMemoryScan {
36
- static nextElementId = 0;
37
- #elementWeakRefs: Array<WeakRef<Element>>;
38
- #isActivated: boolean;
39
- #intervalId: NodeJS.Timeout;
40
- #elementToBoundingRects: WeakMap<Element, BoundingRect>;
41
- #elementToComponentStack: WeakMap<Element, string[]>;
42
- #knownFiberNodes: Array<WeakRef<Fiber>>;
43
- #fiberAnalyzer: ReactFiberAnalyzer;
44
- #isDevMode: boolean;
45
- #subscribers: Array<AnalysisResultCallback>;
46
- #extensions: Array<BasicExtension>;
47
- #scanIntervalMs: number;
48
- #domObserver: Optional<DOMObserver>;
49
- #eventListenerTracker: Nullable<EventListenerTracker>;
50
-
51
- constructor(options: CreateOptions = {}) {
52
- this.#elementWeakRefs = [];
53
- this.#isActivated = false;
54
- this.#elementToBoundingRects = new WeakMap();
55
- this.#elementToComponentStack = new WeakMap();
56
- this.#knownFiberNodes = [];
57
- this.#eventListenerTracker = options.trackEventListenerLeaks
58
- ? EventListenerTracker.getInstance()
59
- : null;
60
-
61
- this.#fiberAnalyzer = new ReactFiberAnalyzer();
62
- this.#intervalId = 0 as unknown as NodeJS.Timeout;
63
- this.#isDevMode = options.isDevMode ?? false;
64
- this.#subscribers = options.subscribers ?? [];
65
- this.#extensions = options.extensions ?? [];
66
- this.#scanIntervalMs =
67
- options.scanIntervalMs ?? config.performance.scanIntervalMs;
68
- }
69
-
70
- #log(...args: AnyValue[]): void {
71
- if (this.#isDevMode && config.features.enableConsoleLogs) {
72
- utils.consoleLog(...args);
73
- }
74
- }
75
-
76
- subscribe(callback: AnalysisResultCallback): () => void {
77
- this.#subscribers.push(callback);
78
- return () => this.unsubscribe(callback);
79
- }
80
-
81
- unsubscribe(callback: AnalysisResultCallback): void {
82
- this.#subscribers = this.#subscribers.filter(cb => cb !== callback);
83
- }
84
-
85
- #notifySubscribers(result: AnalysisResult): void {
86
- for (const subscriber of this.#subscribers) {
87
- subscriber(result);
88
- }
89
- const duration = result.end - result.start;
90
- this.#log('duration: ', `${duration} ms`);
91
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
92
- const {scanner, leakedFibers, fiberNodes, ...rest} = result;
93
- this.#log(rest);
94
- }
95
-
96
- registerExtension(extension: BasicExtension): () => void {
97
- this.#extensions.push(extension);
98
- return () => this.unregisterExtension(extension);
99
- }
100
-
101
- unregisterExtension(extension: BasicExtension): void {
102
- this.#extensions = this.#extensions.filter(e => e !== extension);
103
- }
104
-
105
- #notifyExtensionsBeforeScan(): void {
106
- for (const extension of this.#extensions) {
107
- extension?.beforeScan();
108
- }
109
- }
110
-
111
- #notifyExtensionsAfterScan(result: AnalysisResult): void {
112
- for (const extension of this.#extensions) {
113
- extension?.afterScan(result);
114
- }
115
- }
116
-
117
- start() {
118
- this.#isActivated = true;
119
- this.#intervalId = setInterval(
120
- this.#scanCycle.bind(this),
121
- this.#scanIntervalMs,
122
- );
123
- if (config.features.enableMutationObserver) {
124
- if (this.#domObserver == null) {
125
- this.#domObserver = new DOMObserver();
126
- // NOTE: do not update the fiber or component information here
127
- // with this.#domObserver.register as those elements in the delta
128
- // list may be unmounted or just attached and their shape and
129
- // component info is not correct or not set yet
130
- }
131
- this.#domObserver.startMonitoring();
132
- }
133
- console.log('[Memory] Tracking React and DOM memory...');
134
- }
135
-
136
- #scanCycle() {
137
- if (!this.#isActivated) {
138
- return;
139
- }
140
- this.#notifyExtensionsBeforeScan();
141
- const start = performance.now();
142
- const stats = this.scan();
143
- const end = performance.now();
144
-
145
- // inform subscribers and extensions
146
- const analysiResult = {
147
- ...stats,
148
- start,
149
- end,
150
- scanner: this,
151
- };
152
- this.#notifySubscribers(analysiResult);
153
- this.#notifyExtensionsAfterScan(analysiResult);
154
- }
155
-
156
- pause() {
157
- this.#isActivated = false;
158
- }
159
-
160
- stop() {
161
- this.#isActivated = false;
162
- clearInterval(this.#intervalId);
163
- this.#elementWeakRefs = [];
164
- this.#domObserver?.stopMonitoring();
165
- }
166
-
167
- recordBoundingRectangles(elementRefs: Array<WeakRef<Element>>) {
168
- for (const elemRef of elementRefs) {
169
- const element = elemRef.deref();
170
- if (element == null || this.#elementToBoundingRects.has(element)) {
171
- continue;
172
- }
173
- const rect = utils.getBoundingClientRect(element);
174
- if (rect != null) {
175
- this.#elementToBoundingRects.set(element, rect);
176
- }
177
- }
178
- }
179
-
180
- getDetachedDOMInfo(): Array<DOMElementInfo> {
181
- const detachedDOMElements = [];
182
- for (const weakRef of this.#elementWeakRefs) {
183
- const element = weakRef.deref();
184
- if (element == null || element.isConnected) {
185
- continue;
186
- }
187
- // add a unique id to that detach dom element
188
- const elem = element as AnyValue;
189
- if (elem.detachedElementId == null) {
190
- const elementId = ReactMemoryScan.nextElementId++;
191
- elem.detachedElementIdStr = `memory-id-${elementId}@`;
192
- elem.detachedElementId = elementId;
193
- }
194
- const componentStack = this.#elementToComponentStack.get(element) ?? [];
195
- detachedDOMElements.push({
196
- element: weakRef,
197
- boundingRect: this.#elementToBoundingRects.get(element),
198
- componentStack,
199
- });
200
- }
201
- return detachedDOMElements;
202
- }
203
-
204
- isDevMode(): boolean {
205
- return this.#isDevMode;
206
- }
207
-
208
- #updateElementToComponentInfo(elements: Array<WeakRef<Element>>): void {
209
- for (const elemRef of elements) {
210
- const element = elemRef.deref();
211
- if (element == null || this.#elementToComponentStack.has(element)) {
212
- continue;
213
- }
214
- const fiberNode = getFiberNodeFromElement(element);
215
- if (fiberNode == null) {
216
- continue;
217
- }
218
- this.#elementToComponentStack.set(
219
- element,
220
- getReactComponentStack(fiberNode),
221
- );
222
- }
223
- }
224
-
225
- getCachedComponentName(elementRef: WeakRef<Element>): string {
226
- const FALLBACK_NAME = '<Unknown>';
227
- const element = elementRef.deref();
228
- if (element == null) {
229
- return FALLBACK_NAME;
230
- }
231
- const componentStack = this.#elementToComponentStack.get(element);
232
- if (componentStack == null) {
233
- return FALLBACK_NAME;
234
- }
235
- return componentStack[0] ?? FALLBACK_NAME;
236
- }
237
-
238
- updateFiberNodes(fiberNodes: Array<WeakRef<Fiber>>): Array<WeakRef<Fiber>> {
239
- const knownFiberSet = new WeakSet<Fiber>();
240
- for (const fiberNode of this.#knownFiberNodes) {
241
- const fiber = fiberNode.deref();
242
- if (fiber != null) {
243
- knownFiberSet.add(fiber);
244
- }
245
- }
246
- const newFiberSet = new WeakSet<Fiber>();
247
- for (const fiberNode of fiberNodes) {
248
- const fiber = fiberNode.deref();
249
- if (fiber != null) {
250
- newFiberSet.add(fiber);
251
- }
252
- }
253
- const leakedFibers: Array<WeakRef<Fiber>> = [];
254
- const newExistingFibers: Array<WeakRef<Fiber>> = [];
255
- // clean up and compact the existing fiber node lists
256
- for (const fiberRef of this.#knownFiberNodes) {
257
- const fiber = fiberRef.deref();
258
- if (fiber == null) {
259
- continue;
260
- }
261
- if (!newFiberSet.has(fiber)) {
262
- leakedFibers.push(fiberRef);
263
- } else {
264
- newExistingFibers.push(fiberRef);
265
- if (fiber.return == null) {
266
- leakedFibers.push(fiberRef);
267
- }
268
- }
269
- }
270
- // add new fibers to the existing list
271
- for (const fiberRef of fiberNodes) {
272
- const fiber = fiberRef.deref();
273
- if (fiber == null) {
274
- continue;
275
- }
276
- if (!knownFiberSet.has(fiber)) {
277
- newExistingFibers.push(fiberRef);
278
- }
279
- }
280
- this.#knownFiberNodes = newExistingFibers;
281
- this.#log('known fibers: ', this.#knownFiberNodes.length);
282
- this.#log('leaked fibers: ', leakedFibers.length);
283
- return leakedFibers;
284
- }
285
-
286
- packLeakedFibers(leakedFibers: Array<WeakRef<Fiber>>): Array<LeakedFiber> {
287
- const ret = [];
288
- for (const leakedFiber of leakedFibers) {
289
- ret.push(new LeakedFiber(leakedFiber));
290
- }
291
- return ret;
292
- }
293
-
294
- #getTrackedDOMRefs(): Array<WeakRef<Element>> {
295
- if (this.#domObserver == null) {
296
- return utils.getDOMElements();
297
- }
298
- return [...utils.getDOMElements(), ...this.#domObserver.getDOMElements()];
299
- }
300
-
301
- #runGC(): void {
302
- if ((window as AnyValue)?.gc != null) {
303
- (window as AnyValue).gc();
304
- }
305
- }
306
-
307
- #scanEventListenerLeaks(): EventListenerLeak[] {
308
- if (this.#eventListenerTracker == null) {
309
- return [];
310
- }
311
- // Scan for event listener leaks
312
- const detachedListeners = this.#eventListenerTracker.scan(
313
- this.getCachedComponentName.bind(this),
314
- );
315
- const eventListenerLeaks: EventListenerLeak[] = [];
316
- for (const [componentName, listeners] of detachedListeners.entries()) {
317
- const typeCount = new Map<string, number>();
318
- for (const listener of listeners) {
319
- const count = typeCount.get(listener.type) ?? 0;
320
- typeCount.set(listener.type, count + 1);
321
- }
322
- for (const [type, count] of typeCount.entries()) {
323
- eventListenerLeaks.push({
324
- type,
325
- componentName,
326
- count,
327
- });
328
- }
329
- }
330
- return eventListenerLeaks;
331
- }
332
-
333
- scan(): ScanResult {
334
- const start = Date.now();
335
- this.#runGC();
336
- const weakRefList = this.#elementWeakRefs;
337
- // TODO: associate elements with URL and other metadata
338
- const allElements = this.#getTrackedDOMRefs();
339
- this.#updateElementToComponentInfo(allElements);
340
- this.recordBoundingRectangles(allElements);
341
- utils.updateWeakRefList(weakRefList, allElements);
342
- const scanResult = this.#fiberAnalyzer.scan(
343
- weakRefList,
344
- this.#elementToComponentStack,
345
- );
346
- const leakedFibers = this.updateFiberNodes(scanResult.fiberNodes);
347
- scanResult.leakedFibers = leakedFibers;
348
-
349
- // scan for event listener leaks
350
- // TODO: show the results in the UI widget
351
- scanResult.eventListenerLeaks = this.#scanEventListenerLeaks();
352
-
353
- (window as AnyValue).leakedFibers = this.packLeakedFibers(leakedFibers);
354
- const end = Date.now();
355
- this.#log(`scan took ${end - start}ms`);
356
- return scanResult;
357
- }
358
- }
359
-
360
- class LeakedFiber {
361
- leakedFiber: WeakRef<Fiber>;
362
-
363
- constructor(fiber: WeakRef<Fiber>) {
364
- this.leakedFiber = fiber;
365
- }
366
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import type ReactMemoryScan from '../core/react-memory-scan';
11
- import type {AnalysisResult} from '../core/types';
12
-
13
- /**
14
- * Base class for React Memory Scanner extensions.
15
- * Extensions can hook into the scanning process before and after analysis.
16
- */
17
- export abstract class BasicExtension {
18
- protected readonly scanner: ReactMemoryScan;
19
-
20
- constructor(scanner: ReactMemoryScan) {
21
- this.scanner = scanner;
22
- }
23
-
24
- /**
25
- * Hook that runs before the memory scan starts.
26
- * Override this method to perform any setup or pre-scan operations.
27
- */
28
- beforeScan(): void {
29
- // to be overridden
30
- }
31
-
32
- /**
33
- * Hook that runs after the memory scan completes.
34
- * Override this method to process or modify the analysis results.
35
- * @param analysisResult - The results from the memory scan
36
- */
37
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
38
- afterScan(_analysisResult: AnalysisResult): void {
39
- // to be overridden
40
- }
41
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import type ReactMemoryScan from '../core/react-memory-scan';
11
- import type {AnalysisResult} from '../core/types';
12
-
13
- import DOMElementVisualizer from '../visual/dom-element-visualizer';
14
- import DOMElementVisualizerInteractive from '../visual/dom-element-visualizer-interactive';
15
- import {BasicExtension} from './basic-extension';
16
-
17
- const USE_INTERACTIVE_VISUALIZER = true;
18
-
19
- export class DOMVisualizationExtension extends BasicExtension {
20
- #domVirtualizer: DOMElementVisualizer;
21
-
22
- constructor(scanner: ReactMemoryScan) {
23
- super(scanner);
24
- if (USE_INTERACTIVE_VISUALIZER) {
25
- this.#domVirtualizer = new DOMElementVisualizerInteractive();
26
- } else {
27
- this.#domVirtualizer = new DOMElementVisualizer();
28
- }
29
- }
30
-
31
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
32
- afterScan(_analysisResult: AnalysisResult): void {
33
- // const start = Date.now();
34
- const scanner = this.scanner;
35
- if (scanner.isDevMode()) {
36
- const detachedDOMInfo = scanner.getDetachedDOMInfo();
37
- this.#domVirtualizer.repaint(detachedDOMInfo);
38
- }
39
- // const end = Date.now();
40
- // console.log(`repaint took ${end - start}ms`);
41
- }
42
- }
@@ -1,75 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow strict-local
8
- * @format
9
- * @oncall memory_lab
10
- */
11
- // Core types
12
- export type BoundingRect = {
13
- bottom: number,
14
- height: number,
15
- left: number,
16
- right: number,
17
- top: number,
18
- width: number,
19
- x: number,
20
- y: number,
21
- };
22
-
23
- export type DOMElementInfo = {
24
- boundingRect: BoundingRect,
25
- };
26
-
27
- export type Nullable<T> = T | null;
28
-
29
- // [lib-index.ts]
30
- export type ReactMemoryScan = {
31
- constructor: (options: CreateOptions) => void,
32
- start: () => void,
33
- stop: () => void,
34
- scan: () => void,
35
- visualize: () => void,
36
- subscribe: (callback: AnalysisResultCallback) => () => void,
37
- unsubscribe: (callback: AnalysisResultCallback) => void,
38
- isDevMode: () => boolean,
39
- };
40
-
41
- declare export function createReactMemoryScan(
42
- options: CreateOptions,
43
- ): ReactMemoryScan;
44
-
45
- export type BasicExtension = {
46
- beforeScan: () => void,
47
- afterScan: (result: AnalysisResult) => void,
48
- };
49
-
50
- export type CreateOptions = {
51
- isDevMode?: boolean,
52
- subscribers?: Array<AnalysisResultCallback>,
53
- extensions?: Array<BasicExtension>,
54
- scanIntervalMs?: number,
55
- };
56
-
57
- export type ScanResult = {
58
- components: Set<string>,
59
- componentToFiberNodeCount: Map<string, number>,
60
- totalElements: number,
61
- totalDetachedElements: number,
62
- detachedComponentToFiberNodeCount: Map<string, number>,
63
- fiberNodes: Array<WeakRef<Fiber>>,
64
- leakedFibers: Array<WeakRef<Fiber>>,
65
- };
66
-
67
- export type AnalysisResult = {
68
- ...ScanResult,
69
- start: number,
70
- end: number,
71
- };
72
-
73
- export type AnalysisResultCallback = (result: AnalysisResult) => void;
74
-
75
- export type DOMObserveCallback = (list: Array<WeakRef<Element>>) => void;
@@ -1,22 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import ReactMemoryScan from './core/react-memory-scan';
11
- import {CreateOptions} from './core/types';
12
- // import { DOMVisualizationExtension } from './extensions/dom-visualization-extension';
13
-
14
- export function createReactMemoryScan(
15
- options: CreateOptions = {},
16
- ): ReactMemoryScan {
17
- return new ReactMemoryScan(options);
18
- // const memoryScan = new ReactMemoryScan(options);
19
- // const domVisualizer = new DOMVisualizationExtension(memoryScan);
20
- // memoryScan.registerExtension(domVisualizer);
21
- // return memoryScan;
22
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import ReactMemoryScan from './core/react-memory-scan';
11
- import {DOMVisualizationExtension} from './extensions/dom-visualization-extension';
12
- import {hasRunInSession, setRunInSession} from './utils/utils';
13
-
14
- if (!hasRunInSession()) {
15
- const memoryScan = new ReactMemoryScan({isDevMode: true});
16
- const domVisualizer = new DOMVisualizationExtension(memoryScan);
17
- memoryScan.registerExtension(domVisualizer);
18
-
19
- memoryScan.start();
20
- setRunInSession();
21
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import type {AnyValue} from '../../core/types';
11
- import {test, expect} from '@playwright/test';
12
- import {libBundleFilePath} from '../utils/test-utils';
13
-
14
- test('test library in browser via addScriptTag', async ({page}) => {
15
- // Navigate to an empty page (or a test page)
16
- await page.goto('about:blank');
17
-
18
- // Inject the lib bundle file (UMD bundle of the library) into the page
19
- await page.addScriptTag({path: libBundleFilePath});
20
-
21
- // Now the global `MemLens` should be available in the page
22
- const libraryLoaded = await page.evaluate(() => {
23
- const createReactMemoryScan = (window as AnyValue).MemLens
24
- .createReactMemoryScan;
25
- const instance = createReactMemoryScan();
26
- const analysisResult = instance.scan();
27
- return typeof analysisResult.totalElements === 'number';
28
- });
29
-
30
- expect(libraryLoaded).toBe(true);
31
- });
@@ -1,48 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import {test, expect} from '@playwright/test';
11
- import fs from 'fs';
12
- import {wait} from '../utils/test-utils';
13
- import {runBundleFilePath} from '../utils/test-utils';
14
-
15
- test.describe('run.bundle.js functionality', () => {
16
- test('should load and execute correctly', async ({page}) => {
17
- const bundleCode = fs.readFileSync(runBundleFilePath, 'utf8');
18
-
19
- let bundleLoaded = false;
20
- // Listen for console messages
21
- page.on('console', message => {
22
- // add console.log(message) if you would like to debug
23
- const msgText = message.text();
24
- if (msgText.includes('Tracking React and DOM memory')) {
25
- bundleLoaded = true;
26
- }
27
- });
28
-
29
- await page.setContent(`
30
- <!DOCTYPE html>
31
- <html>
32
- <head>
33
- <script>
34
- ${bundleCode}
35
- </script>
36
- </head>
37
- <body>
38
- <div id="test-container"></div>
39
- </body>
40
- </html>
41
- `);
42
-
43
- await wait(2000);
44
-
45
- // check if the bundle loaded successfully
46
- expect(bundleLoaded).toBe(true);
47
- });
48
- });
@@ -1,48 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @oncall memory_lab
9
- */
10
- import {test, expect} from '@playwright/test';
11
- import fs from 'fs';
12
- import {wait} from '../utils/test-utils';
13
- import {runBundleFilePath} from '../utils/test-utils';
14
-
15
- test.describe('run.bundle.js functionality', () => {
16
- test('should load and execute correctly', async ({page}) => {
17
- const bundleCode = fs.readFileSync(runBundleFilePath, 'utf8');
18
-
19
- let bundleLoaded = false;
20
- // Listen for console messages
21
- page.on('console', message => {
22
- // add console.log(message) if you would like to debug
23
- const msgText = message.text();
24
- if (msgText.includes('Tracking React and DOM memory')) {
25
- bundleLoaded = true;
26
- }
27
- });
28
-
29
- await page.setContent(`
30
- <!DOCTYPE html>
31
- <html>
32
- <head>
33
- </head>
34
- <body>
35
- <div id="test-container"></div>
36
- <script>
37
- ${bundleCode}
38
- </script>
39
- </body>
40
- </html>
41
- `);
42
-
43
- await wait(1000);
44
-
45
- // check if the bundle loaded successfully
46
- expect(bundleLoaded).toBe(true);
47
- });
48
- });