@react-perfscope/core 0.7.1 → 1.0.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/dist/index.d.cts CHANGED
@@ -243,15 +243,6 @@ interface CreateSourceMapResolverOptions {
243
243
  /** Override the global fetch. Useful for tests and non-browser environments. */
244
244
  fetch?: typeof globalThis.fetch;
245
245
  }
246
- /**
247
- * Create a SourceMap resolver that fetches `.map` files from the live URL
248
- * referenced in each source file's `//# sourceMappingURL=` directive.
249
- * Caches the DECODED TraceMap per source URL — decoding the mappings is the
250
- * expensive step, so repeated resolves against the same file are O(log n)
251
- * lookups after the first.
252
- *
253
- * Returns the input frame on any failure (network error, missing map, etc.).
254
- */
255
246
  declare function createSourceMapResolver(opts?: CreateSourceMapResolverOptions): SourceMapResolver;
256
247
  declare function parseStack(raw: string | undefined): StackFrame[];
257
248
 
package/dist/index.d.ts CHANGED
@@ -243,15 +243,6 @@ interface CreateSourceMapResolverOptions {
243
243
  /** Override the global fetch. Useful for tests and non-browser environments. */
244
244
  fetch?: typeof globalThis.fetch;
245
245
  }
246
- /**
247
- * Create a SourceMap resolver that fetches `.map` files from the live URL
248
- * referenced in each source file's `//# sourceMappingURL=` directive.
249
- * Caches the DECODED TraceMap per source URL — decoding the mappings is the
250
- * expensive step, so repeated resolves against the same file are O(log n)
251
- * lookups after the first.
252
- *
253
- * Returns the input frame on any failure (network error, missing map, etc.).
254
- */
255
246
  declare function createSourceMapResolver(opts?: CreateSourceMapResolverOptions): SourceMapResolver;
256
247
  declare function parseStack(raw: string | undefined): StackFrame[];
257
248
 
package/dist/index.js CHANGED
@@ -78,8 +78,14 @@ import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping";
78
78
 
79
79
  // src/self-requests.ts
80
80
  var selfRequests = /* @__PURE__ */ new Set();
81
+ var MAX_SELF_REQUESTS = 2e3;
81
82
  function markSelfRequest(url) {
83
+ selfRequests.delete(url);
82
84
  selfRequests.add(url);
85
+ if (selfRequests.size > MAX_SELF_REQUESTS) {
86
+ const oldest = selfRequests.values().next().value;
87
+ if (oldest !== void 0) selfRequests.delete(oldest);
88
+ }
83
89
  }
84
90
  function isSelfRequest(url) {
85
91
  return selfRequests.has(url);
@@ -126,13 +132,25 @@ function attachLazyStack(target, raw, skipTopFrames = 0) {
126
132
  }
127
133
  });
128
134
  }
135
+ var MAX_CACHED_MAPS = 50;
136
+ function sourceCacheKey(url) {
137
+ const q = url.indexOf("?");
138
+ const h = url.indexOf("#");
139
+ const end = Math.min(q === -1 ? url.length : q, h === -1 ? url.length : h);
140
+ return url.slice(0, end);
141
+ }
129
142
  function createSourceMapResolver(opts = {}) {
130
143
  const f = opts.fetch ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : null);
131
144
  const cache = /* @__PURE__ */ new Map();
132
145
  function fetchTracerFor(sourceUrl) {
133
146
  if (!f) return Promise.resolve(null);
134
- const existing = cache.get(sourceUrl);
135
- if (existing) return existing;
147
+ const key = sourceCacheKey(sourceUrl);
148
+ const existing = cache.get(key);
149
+ if (existing) {
150
+ cache.delete(key);
151
+ cache.set(key, existing);
152
+ return existing;
153
+ }
136
154
  const promise = (async () => {
137
155
  try {
138
156
  markSelfRequest(sourceUrl);
@@ -156,10 +174,15 @@ function createSourceMapResolver(opts = {}) {
156
174
  if (!mapRes || !mapRes.ok) return null;
157
175
  return new TraceMap(await mapRes.json());
158
176
  } catch {
177
+ cache.delete(key);
159
178
  return null;
160
179
  }
161
180
  })();
162
- cache.set(sourceUrl, promise);
181
+ cache.set(key, promise);
182
+ if (cache.size > MAX_CACHED_MAPS) {
183
+ const oldest = cache.keys().next().value;
184
+ if (oldest !== void 0) cache.delete(oldest);
185
+ }
163
186
  return promise;
164
187
  }
165
188
  return {
@@ -358,6 +381,7 @@ function createLongTasksCollector() {
358
381
  return {
359
382
  kind: "long-task",
360
383
  activate(emit) {
384
+ if (active) return;
361
385
  if (typeof PerformanceObserver === "undefined") {
362
386
  console.warn("[react-perfscope] PerformanceObserver not supported; long-tasks disabled");
363
387
  return;
@@ -409,6 +433,20 @@ function createLongTasksCollector() {
409
433
  };
410
434
  }
411
435
 
436
+ // src/self-measurement.ts
437
+ var depth = 0;
438
+ function withSelfMeasurement(fn) {
439
+ depth++;
440
+ try {
441
+ return fn();
442
+ } finally {
443
+ depth--;
444
+ }
445
+ }
446
+ function inSelfMeasurement() {
447
+ return depth > 0;
448
+ }
449
+
412
450
  // src/collectors/forced-reflow.ts
413
451
  var LAYOUT_GETTERS = [
414
452
  "offsetWidth",
@@ -471,7 +509,7 @@ function createForcedReflowCollector() {
471
509
  Object.defineProperty(proto, key, {
472
510
  configurable: true,
473
511
  get() {
474
- if (active) {
512
+ if (active && !inSelfMeasurement()) {
475
513
  if (!consumePendingMutations()) {
476
514
  return originalGet.call(this);
477
515
  }
@@ -496,7 +534,7 @@ function createForcedReflowCollector() {
496
534
  configurable: true,
497
535
  writable: true,
498
536
  value: function patchedLayoutMethod(...args) {
499
- if (active) {
537
+ if (active && !inSelfMeasurement()) {
500
538
  if (!consumePendingMutations()) {
501
539
  return original.apply(this, args);
502
540
  }
@@ -586,7 +624,7 @@ function collectPerfscopeRects() {
586
624
  function entryIsOnlyFromPerfscope(sources) {
587
625
  if (sources.length === 0) return false;
588
626
  if (typeof document === "undefined") return false;
589
- const hostRects = collectPerfscopeRects();
627
+ const hostRects = withSelfMeasurement(collectPerfscopeRects);
590
628
  if (hostRects.length === 0) return false;
591
629
  for (const src of sources) {
592
630
  let matched = false;
@@ -623,6 +661,7 @@ function createLayoutShiftCollector() {
623
661
  return {
624
662
  kind: "layout-shift",
625
663
  activate(emit) {
664
+ if (active) return;
626
665
  if (typeof PerformanceObserver === "undefined") {
627
666
  console.warn("[react-perfscope] PerformanceObserver not supported; layout-shift disabled");
628
667
  return;
@@ -681,6 +720,7 @@ function createNetworkCollector() {
681
720
  return {
682
721
  kind: "network",
683
722
  activate(emit) {
723
+ if (active) return;
684
724
  if (typeof PerformanceObserver === "undefined") {
685
725
  console.warn("[react-perfscope] PerformanceObserver not supported; network disabled");
686
726
  return;
@@ -830,6 +870,7 @@ function createHeapCollector() {
830
870
  return {
831
871
  kind: "heap",
832
872
  activate() {
873
+ if (timer != null) return;
833
874
  samples = [];
834
875
  if (!readMemory()) return;
835
876
  sample();
@@ -873,6 +914,7 @@ function createInteractionCollector() {
873
914
  return {
874
915
  kind: "interaction",
875
916
  activate() {
917
+ if (active) return;
876
918
  if (typeof PerformanceObserver === "undefined" || !supportsEventTiming()) return;
877
919
  active = true;
878
920
  entries = [];
@@ -1108,6 +1150,7 @@ function createSelfProfilingCollector() {
1108
1150
  return {
1109
1151
  kind: "long-task",
1110
1152
  activate() {
1153
+ if (profiler) return;
1111
1154
  tracePromise = null;
1112
1155
  const Ctor = globalThis.Profiler;
1113
1156
  if (typeof Ctor !== "function") return;
@@ -1125,6 +1168,8 @@ function createSelfProfilingCollector() {
1125
1168
  if (!profiler) return;
1126
1169
  try {
1127
1170
  tracePromise = profiler.stop();
1171
+ tracePromise.catch(() => {
1172
+ });
1128
1173
  } catch (err) {
1129
1174
  console.warn("[react-perfscope] self-profiling stop failed:", err);
1130
1175
  tracePromise = null;