rerender-lens 0.5.0 → 0.7.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +23 -4
  3. package/dist/{budget-CRswn-nC.d.cts → budget-CA1MS7lB.d.cts} +1 -1
  4. package/dist/{budget-BnJlYwrV.d.ts → budget-ok1VDJ4t.d.ts} +1 -1
  5. package/dist/cli.cjs +78 -26
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/cli.js +78 -26
  8. package/dist/cli.js.map +1 -1
  9. package/dist/{devtools-BYWat7nQ.d.ts → devtools-Cl5n_52v.d.ts} +11 -2
  10. package/dist/{devtools-DJi_6AfJ.d.cts → devtools-UwQx2VYS.d.cts} +11 -2
  11. package/dist/index.cjs +99 -9
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +13 -7
  14. package/dist/index.d.ts +13 -7
  15. package/dist/index.js +99 -10
  16. package/dist/index.js.map +1 -1
  17. package/dist/jest-setup.cjs +20 -3
  18. package/dist/jest-setup.cjs.map +1 -1
  19. package/dist/jest-setup.d.cts +4 -4
  20. package/dist/jest-setup.d.ts +4 -4
  21. package/dist/jest-setup.js +20 -3
  22. package/dist/jest-setup.js.map +1 -1
  23. package/dist/jest.cjs +20 -3
  24. package/dist/jest.cjs.map +1 -1
  25. package/dist/jest.d.cts +4 -4
  26. package/dist/jest.d.ts +4 -4
  27. package/dist/jest.js +20 -3
  28. package/dist/jest.js.map +1 -1
  29. package/dist/{notifiers-DwKlvv4H.d.cts → notifiers-B5poAEvE.d.cts} +2 -2
  30. package/dist/{notifiers-FNzKHs0a.d.ts → notifiers-CqQW0Eum.d.ts} +2 -2
  31. package/dist/playwright.d.cts +4 -4
  32. package/dist/playwright.d.ts +4 -4
  33. package/dist/relay.cjs +65 -21
  34. package/dist/relay.cjs.map +1 -1
  35. package/dist/relay.d.cts +25 -3
  36. package/dist/relay.d.ts +25 -3
  37. package/dist/relay.js +65 -21
  38. package/dist/relay.js.map +1 -1
  39. package/dist/rerender-lens.iife.js +105 -12
  40. package/dist/{runner-report-CW8X5RwK.d.ts → runner-report-Bvqoe89M.d.ts} +2 -2
  41. package/dist/{runner-report-B8Sc3FZO.d.cts → runner-report-CvpDg2zt.d.cts} +2 -2
  42. package/dist/setup.cjs +98 -9
  43. package/dist/setup.cjs.map +1 -1
  44. package/dist/setup.js +98 -9
  45. package/dist/setup.js.map +1 -1
  46. package/dist/{types-DW5-N2XH.d.cts → types-DwNN5cWe.d.cts} +28 -1
  47. package/dist/{types-DW5-N2XH.d.ts → types-DwNN5cWe.d.ts} +28 -1
  48. package/dist/vite.d.cts +1 -1
  49. package/dist/vite.d.ts +1 -1
  50. package/dist/vitest-setup.cjs +20 -3
  51. package/dist/vitest-setup.cjs.map +1 -1
  52. package/dist/vitest-setup.d.cts +4 -4
  53. package/dist/vitest-setup.d.ts +4 -4
  54. package/dist/vitest-setup.js +20 -3
  55. package/dist/vitest-setup.js.map +1 -1
  56. package/dist/vitest.cjs +20 -3
  57. package/dist/vitest.cjs.map +1 -1
  58. package/dist/vitest.d.cts +5 -5
  59. package/dist/vitest.d.ts +5 -5
  60. package/dist/vitest.js +20 -3
  61. package/dist/vitest.js.map +1 -1
  62. package/package.json +3 -2
  63. package/panel/panel.css +48 -0
  64. package/panel/panel.js +348 -20
package/dist/index.cjs CHANGED
@@ -403,16 +403,27 @@ function printReport(report, options) {
403
403
  }
404
404
 
405
405
  // src/state.ts
406
+ var MAX_SEEN_COMPONENTS = 500;
406
407
  var KEY = /* @__PURE__ */ Symbol.for("rerender-lens.state");
407
408
  function getState() {
408
409
  const g = globalThis;
409
410
  let s = g[KEY];
410
411
  if (!s) {
411
- s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0 };
412
+ s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0, seen: /* @__PURE__ */ new Set(), seenTracked: /* @__PURE__ */ new Set(), seenOverflow: false };
412
413
  g[KEY] = s;
413
414
  }
414
415
  return s;
415
416
  }
417
+ function noteRendered(s, name, tracked) {
418
+ if (!s.seen.has(name)) {
419
+ if (s.seen.size >= MAX_SEEN_COMPONENTS) {
420
+ s.seenOverflow = true;
421
+ return;
422
+ }
423
+ s.seen.add(name);
424
+ }
425
+ if (tracked) s.seenTracked.add(name);
426
+ }
416
427
  function warnOnce(key, message) {
417
428
  const s = getState();
418
429
  if (s.warnedOnce.has(key)) return;
@@ -1139,8 +1150,11 @@ function onCommit(root, commitPriority) {
1139
1150
  const alt = fiber.alternate;
1140
1151
  if (alt && isComponentTag(fiber.tag) && didRender(fiber)) {
1141
1152
  if (isHotSwapped(fiber, alt)) hot = true;
1142
- renderedNames.add(fiberName(fiber));
1143
- if (shouldTrack(fiberType(fiber), o)) rendered.push(fiber);
1153
+ const name = fiberName(fiber);
1154
+ renderedNames.add(name);
1155
+ const tracked = shouldTrack(fiberType(fiber), o);
1156
+ noteRendered(s, name, tracked);
1157
+ if (tracked) rendered.push(fiber);
1144
1158
  }
1145
1159
  if (fiber.tag === SuspenseComponent && alt && alt.memoizedState !== null && fiber.memoizedState === null) (resolvedBoundaries ?? (resolvedBoundaries = [])).push(fiber);
1146
1160
  if (!alt || fiber.child !== alt.child) {
@@ -1265,10 +1279,53 @@ function shouldTrack(type, o) {
1265
1279
  if (o.trackAllMemoized) return isMemo(type) || isPureClass(type);
1266
1280
  return false;
1267
1281
  }
1282
+ var ANONYMOUS = "Anonymous";
1283
+ function explainTracking(type, o) {
1284
+ if (typeof type === "string")
1285
+ return { tracked: false, name: type, memoized: false, reason: `<${type}> is a DOM element, not a React component; only components are tracked.` };
1286
+ if (!isComponentLike(type))
1287
+ return { tracked: false, name: ANONYMOUS, memoized: false, reason: "This is not a React component type, so it is never tracked." };
1288
+ const name = getDisplayName(type);
1289
+ const memo = isMemo(type);
1290
+ const memoized = memo || isPureClass(type);
1291
+ if (o.exclude?.some((m) => matches(m, name)))
1292
+ return { tracked: false, name, memoized, reason: `<${name}> matches "exclude", which wins over every other rule.`, fix: `Remove "${name}" from the exclude list.` };
1293
+ if (hasMarker(type)) return { tracked: true, name, memoized, reason: `<${name}> is marked with track() (the ${MARKER} static).` };
1294
+ if (o.include?.some((m) => matches(m, name))) return { tracked: true, name, memoized, reason: `<${name}> matches "include".` };
1295
+ if (o.trackAllComponents) return { tracked: true, name, memoized, reason: '"Track every component" is on, so every component is tracked.' };
1296
+ if (o.trackAllMemoized && memoized)
1297
+ return { tracked: true, name, memoized, reason: `<${name}> is ${memo ? "a React.memo component" : "a PureComponent"}, and "Track every React.memo and PureComponent" is on.` };
1298
+ if (name === ANONYMOUS)
1299
+ return {
1300
+ tracked: false,
1301
+ name,
1302
+ memoized,
1303
+ reason: 'This component has no display name, so "include" and "exclude" cannot address it.',
1304
+ fix: "Give the function a name, set displayName, or mark it with track(fn, 'Name')."
1305
+ };
1306
+ if (o.trackAllMemoized)
1307
+ return {
1308
+ tracked: false,
1309
+ name,
1310
+ memoized,
1311
+ reason: `"Track every React.memo and PureComponent" only covers React.memo components and PureComponent classes, and <${name}> is neither.`,
1312
+ fix: `Add "${name}" to include, wrap it in React.memo, or turn on "Track every component".`
1313
+ };
1314
+ return {
1315
+ tracked: false,
1316
+ name,
1317
+ memoized,
1318
+ reason: `Nothing selects <${name}>: it is not marked with track(), no "include" pattern matches it, and neither "track every" option is on.`,
1319
+ fix: `Add "${name}" to include, or turn on "Track every React.memo and PureComponent" / "Track every component".`
1320
+ };
1321
+ }
1268
1322
  function init(options = {}) {
1269
1323
  const s = getState();
1270
1324
  s.options = { ...options };
1271
1325
  s.printed.clear();
1326
+ s.seen.clear();
1327
+ s.seenTracked.clear();
1328
+ s.seenOverflow = false;
1272
1329
  if (!s.enabled) {
1273
1330
  s.detach = attach();
1274
1331
  s.enabled = true;
@@ -1939,7 +1996,7 @@ function flash(target, duration = 500) {
1939
1996
  }
1940
1997
 
1941
1998
  // src/version.ts
1942
- var VERSION = "0.5.0" ;
1999
+ var VERSION = "0.7.0" ;
1943
2000
 
1944
2001
  // src/devtools.ts
1945
2002
  var DEVTOOLS_MARKER = "__rerenderLens";
@@ -2065,6 +2122,18 @@ function createDevtoolsNotifier(options = {}) {
2065
2122
  target.postMessage(msg, "*");
2066
2123
  };
2067
2124
  const source = options.source ?? "page";
2125
+ const trackingSummary = () => {
2126
+ const s = getState();
2127
+ const o = s.options;
2128
+ return {
2129
+ mode: o.trackAllComponents ? "all" : o.trackAllMemoized ? "memoized" : "marked",
2130
+ include: (o.include ?? []).map(matcherToString).filter((x) => x !== null),
2131
+ exclude: (o.exclude ?? []).map(matcherToString).filter((x) => x !== null),
2132
+ renderedCount: s.seen.size,
2133
+ trackedCount: s.seenTracked.size,
2134
+ overflow: s.seenOverflow
2135
+ };
2136
+ };
2068
2137
  const info = () => ({
2069
2138
  count: buffer.length,
2070
2139
  library: VERSION,
@@ -2078,7 +2147,8 @@ function createDevtoolsNotifier(options = {}) {
2078
2147
  scheduled: getState().scheduled,
2079
2148
  commits: getState().commits,
2080
2149
  overhead: { totalMs: getState().overheadMs, maxCommitMs: getState().maxCommitMs },
2081
- truncated: getState().truncated
2150
+ truncated: getState().truncated,
2151
+ tracking: trackingSummary()
2082
2152
  });
2083
2153
  const bridge = {
2084
2154
  replay: () => {
@@ -2124,6 +2194,10 @@ function createDevtoolsNotifier(options = {}) {
2124
2194
  flashAvoidable: (on) => {
2125
2195
  flashOn = !!on;
2126
2196
  },
2197
+ explain: (target2) => {
2198
+ const comp = typeof target2 === "number" ? fiberById(target2) : nearestComponent(fiberForNode(target2));
2199
+ return comp ? explainTracking(fiberType(comp), getState().options) : null;
2200
+ },
2127
2201
  inspect: (node) => {
2128
2202
  const comp = nearestComponent(fiberForNode(node));
2129
2203
  if (!comp) return null;
@@ -2138,6 +2212,7 @@ function createDevtoolsNotifier(options = {}) {
2138
2212
  component: fiberName(comp),
2139
2213
  instanceId: id,
2140
2214
  tracked: shouldTrack(fiberType(comp), getState().options),
2215
+ tracking: explainTracking(fiberType(comp), getState().options),
2141
2216
  path,
2142
2217
  reports: id === null ? [] : buffer.filter((e) => e.instanceId === id).slice(-20).map((e) => e.payload)
2143
2218
  };
@@ -2172,6 +2247,9 @@ function createDevtoolsNotifier(options = {}) {
2172
2247
  bridge.flashAvoidable(!!data.arg);
2173
2248
  reply.result = true;
2174
2249
  break;
2250
+ case "explain":
2251
+ reply.result = bridge.explain(data.arg);
2252
+ break;
2175
2253
  default:
2176
2254
  reply.error = `unknown command ${String(data.cmd)}`;
2177
2255
  }
@@ -2180,6 +2258,7 @@ function createDevtoolsNotifier(options = {}) {
2180
2258
  }
2181
2259
  return reply;
2182
2260
  };
2261
+ const isRelayGreeting = (data) => !!data && typeof data === "object" && data.__rerenderLensRelay === true && typeof data.app === "string";
2183
2262
  const isCommand = (data) => !!data && typeof data === "object" && data.__rerenderLensCmd === true && typeof data.id === "string";
2184
2263
  const envelope = (type, payload) => ({ [DEVTOOLS_MARKER]: true, version: PROTOCOL_VERSION, type, payload });
2185
2264
  const sinks = [];
@@ -2202,14 +2281,20 @@ function createDevtoolsNotifier(options = {}) {
2202
2281
  const relayUrl = options.relay ?? (typeof window !== "undefined" ? window.__RERENDER_LENS_RELAY__ : void 0);
2203
2282
  const ES = options.eventSource ?? (typeof EventSource === "function" ? EventSource : null);
2204
2283
  if (relayUrl && ES && typeof fetch === "function") {
2205
- const base = relayUrl.replace(/\/$/, "");
2284
+ const [rawBase, relayQuery = ""] = relayUrl.split("?");
2285
+ const base = (rawBase ?? "").replace(/\/$/, "");
2286
+ const relayToken = new URLSearchParams(relayQuery).get("token");
2287
+ const auth = relayToken ? `token=${encodeURIComponent(relayToken)}` : "";
2206
2288
  let queue = [];
2207
2289
  let scheduled = false;
2290
+ let appId = null;
2208
2291
  const flush = () => {
2209
2292
  scheduled = false;
2210
2293
  const batch = queue;
2211
2294
  queue = [];
2212
- fetch(`${base}/message`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(batch), keepalive: true }).catch(() => {
2295
+ const params = [appId ? `app=${encodeURIComponent(appId)}` : "", auth].filter(Boolean).join("&");
2296
+ const to = `${base}/message${params ? `?${params}` : ""}`;
2297
+ fetch(to, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(batch), keepalive: true }).catch(() => {
2213
2298
  });
2214
2299
  };
2215
2300
  const relaySend = (message) => {
@@ -2220,7 +2305,8 @@ function createDevtoolsNotifier(options = {}) {
2220
2305
  }
2221
2306
  };
2222
2307
  try {
2223
- const stream = new ES(`${base}/events?role=app`);
2308
+ const label = typeof location !== "undefined" ? `${location.host}${location.pathname}`.slice(0, 120) : "";
2309
+ const stream = new ES(`${base}/events?role=app${label ? `&label=${encodeURIComponent(label)}` : ""}${auth ? `&${auth}` : ""}`);
2224
2310
  stream.onmessage = (event) => {
2225
2311
  let parsed;
2226
2312
  try {
@@ -2228,7 +2314,10 @@ function createDevtoolsNotifier(options = {}) {
2228
2314
  } catch {
2229
2315
  return;
2230
2316
  }
2231
- for (const m of Array.isArray(parsed) ? parsed : [parsed]) if (isCommand(m)) relaySend(runCommand(m));
2317
+ for (const m of Array.isArray(parsed) ? parsed : [parsed]) {
2318
+ if (isRelayGreeting(m)) appId = m.app;
2319
+ else if (isCommand(m)) relaySend(runCommand(m));
2320
+ }
2232
2321
  };
2233
2322
  stream.onerror = () => {
2234
2323
  };
@@ -2299,6 +2388,7 @@ exports.diffLeaves = diffLeaves;
2299
2388
  exports.diffRecords = diffRecords;
2300
2389
  exports.disable = disable;
2301
2390
  exports.ensureDevtoolsHook = ensureDevtoolsHook;
2391
+ exports.explainTracking = explainTracking;
2302
2392
  exports.firstDifferentPath = firstDifferentPath;
2303
2393
  exports.fixKey = fixKey;
2304
2394
  exports.fixesFor = fixesFor;