@ogygia/devtools 0.0.0-stage → 0.11.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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -2
  3. package/dist/client.d.ts +3 -0
  4. package/dist/client.js +24 -0
  5. package/dist/devtools/BoundaryOverlay.svelte +396 -0
  6. package/dist/devtools/BoundaryOverlay.svelte.d.ts +19 -0
  7. package/dist/devtools/Devtools.svelte +663 -0
  8. package/dist/devtools/Devtools.svelte.d.ts +15 -0
  9. package/dist/devtools/HubTab.svelte +206 -0
  10. package/dist/devtools/HubTab.svelte.d.ts +11 -0
  11. package/dist/devtools/HydrationTab.svelte +237 -0
  12. package/dist/devtools/HydrationTab.svelte.d.ts +13 -0
  13. package/dist/devtools/IslandDetail.svelte +615 -0
  14. package/dist/devtools/IslandDetail.svelte.d.ts +15 -0
  15. package/dist/devtools/LedgerTab.svelte +287 -0
  16. package/dist/devtools/LedgerTab.svelte.d.ts +11 -0
  17. package/dist/devtools/LensTab.svelte +290 -0
  18. package/dist/devtools/LensTab.svelte.d.ts +19 -0
  19. package/dist/devtools/NavTab.svelte +229 -0
  20. package/dist/devtools/NavTab.svelte.d.ts +11 -0
  21. package/dist/devtools/PageTab.svelte +1122 -0
  22. package/dist/devtools/PageTab.svelte.d.ts +15 -0
  23. package/dist/devtools/ProfilerTab.svelte +755 -0
  24. package/dist/devtools/ProfilerTab.svelte.d.ts +15 -0
  25. package/dist/devtools/PropsTree.svelte +155 -0
  26. package/dist/devtools/PropsTree.svelte.d.ts +15 -0
  27. package/dist/devtools/SessionTab.svelte +796 -0
  28. package/dist/devtools/SessionTab.svelte.d.ts +11 -0
  29. package/dist/devtools/TimelineTab.svelte +267 -0
  30. package/dist/devtools/TimelineTab.svelte.d.ts +11 -0
  31. package/dist/devtools/WireTab.svelte +149 -0
  32. package/dist/devtools/WireTab.svelte.d.ts +11 -0
  33. package/dist/devtools/bytes.d.ts +70 -0
  34. package/dist/devtools/bytes.js +82 -0
  35. package/dist/devtools/cache-headers.d.ts +20 -0
  36. package/dist/devtools/cache-headers.js +81 -0
  37. package/dist/devtools/highlight.d.ts +7 -0
  38. package/dist/devtools/highlight.js +83 -0
  39. package/dist/devtools/hydration.d.ts +48 -0
  40. package/dist/devtools/hydration.js +93 -0
  41. package/dist/devtools/index.d.ts +3 -0
  42. package/dist/devtools/index.js +3 -0
  43. package/dist/devtools/ledger-dom.d.ts +7 -0
  44. package/dist/devtools/ledger-dom.js +151 -0
  45. package/dist/devtools/leftovers.d.ts +77 -0
  46. package/dist/devtools/leftovers.js +319 -0
  47. package/dist/devtools/names.d.ts +1 -0
  48. package/dist/devtools/names.js +34 -0
  49. package/dist/devtools/page.d.ts +96 -0
  50. package/dist/devtools/page.js +957 -0
  51. package/dist/devtools/profile-anchors.d.ts +22 -0
  52. package/dist/devtools/profile-anchors.js +135 -0
  53. package/dist/devtools/profile-store.d.ts +175 -0
  54. package/dist/devtools/profile-store.js +239 -0
  55. package/dist/devtools/regions.d.ts +77 -0
  56. package/dist/devtools/regions.js +132 -0
  57. package/dist/devtools/session.d.ts +31 -0
  58. package/dist/devtools/session.js +455 -0
  59. package/dist/devtools/since-load.d.ts +50 -0
  60. package/dist/devtools/since-load.js +89 -0
  61. package/dist/devtools/source-lines.d.ts +24 -0
  62. package/dist/devtools/source-lines.js +106 -0
  63. package/dist/devtools/styles.d.ts +52 -0
  64. package/dist/devtools/styles.js +248 -0
  65. package/dist/devtools/testing-engine.d.ts +83 -0
  66. package/dist/devtools/testing-engine.js +220 -0
  67. package/dist/devtools/ui-app.d.ts +5 -0
  68. package/dist/devtools/ui-app.js +69 -0
  69. package/dist/devtools/ui.d.ts +50 -0
  70. package/dist/devtools/ui.js +175 -0
  71. package/dist/profiler/alloc.d.ts +75 -0
  72. package/dist/profiler/alloc.js +76 -0
  73. package/dist/profiler/analyze.d.ts +437 -0
  74. package/dist/profiler/analyze.js +1941 -0
  75. package/dist/profiler/app-path.d.ts +7 -0
  76. package/dist/profiler/app-path.js +26 -0
  77. package/dist/profiler/async-io.d.ts +58 -0
  78. package/dist/profiler/async-io.js +187 -0
  79. package/dist/profiler/beacon-standalone.d.ts +4 -0
  80. package/dist/profiler/beacon-standalone.js +409 -0
  81. package/dist/profiler/browser-findings.d.ts +25 -0
  82. package/dist/profiler/browser-findings.js +260 -0
  83. package/dist/profiler/byte-strip.d.ts +58 -0
  84. package/dist/profiler/byte-strip.js +228 -0
  85. package/dist/profiler/client-files.d.ts +16 -0
  86. package/dist/profiler/client-files.js +60 -0
  87. package/dist/profiler/client-windows.d.ts +49 -0
  88. package/dist/profiler/client-windows.js +95 -0
  89. package/dist/profiler/client.d.ts +40 -0
  90. package/dist/profiler/client.js +82 -0
  91. package/dist/profiler/compare.d.ts +308 -0
  92. package/dist/profiler/compare.js +733 -0
  93. package/dist/profiler/compress.d.ts +10 -0
  94. package/dist/profiler/compress.js +36 -0
  95. package/dist/profiler/contention.d.ts +60 -0
  96. package/dist/profiler/contention.js +86 -0
  97. package/dist/profiler/crypto.d.ts +19 -0
  98. package/dist/profiler/crypto.js +101 -0
  99. package/dist/profiler/doc-diff.d.ts +47 -0
  100. package/dist/profiler/doc-diff.js +214 -0
  101. package/dist/profiler/dom-diff.d.ts +43 -0
  102. package/dist/profiler/dom-diff.js +121 -0
  103. package/dist/profiler/drill.d.ts +89 -0
  104. package/dist/profiler/drill.js +553 -0
  105. package/dist/profiler/embedded-maps.d.ts +37 -0
  106. package/dist/profiler/embedded-maps.js +135 -0
  107. package/dist/profiler/env.d.ts +6 -0
  108. package/dist/profiler/env.js +10 -0
  109. package/dist/profiler/forecast.d.ts +76 -0
  110. package/dist/profiler/forecast.js +225 -0
  111. package/dist/profiler/frames.d.ts +11 -0
  112. package/dist/profiler/frames.js +42 -0
  113. package/dist/profiler/gc.d.ts +144 -0
  114. package/dist/profiler/gc.js +271 -0
  115. package/dist/profiler/hole-slots.d.ts +31 -0
  116. package/dist/profiler/hole-slots.js +90 -0
  117. package/dist/profiler/index.d.ts +288 -0
  118. package/dist/profiler/index.js +4921 -0
  119. package/dist/profiler/insights.d.ts +96 -0
  120. package/dist/profiler/insights.js +239 -0
  121. package/dist/profiler/ledger.d.ts +121 -0
  122. package/dist/profiler/ledger.js +440 -0
  123. package/dist/profiler/lineage.d.ts +81 -0
  124. package/dist/profiler/lineage.js +359 -0
  125. package/dist/profiler/module-map.d.ts +12 -0
  126. package/dist/profiler/module-map.js +94 -0
  127. package/dist/profiler/net.d.ts +169 -0
  128. package/dist/profiler/net.js +586 -0
  129. package/dist/profiler/on-demand.d.ts +11 -0
  130. package/dist/profiler/on-demand.js +15 -0
  131. package/dist/profiler/own-requests.d.ts +9 -0
  132. package/dist/profiler/own-requests.js +17 -0
  133. package/dist/profiler/patterns.d.ts +476 -0
  134. package/dist/profiler/patterns.js +2203 -0
  135. package/dist/profiler/profiler-router.d.ts +245 -0
  136. package/dist/profiler/profiler-router.js +113 -0
  137. package/dist/profiler/refresh-stub.d.ts +2 -0
  138. package/dist/profiler/refresh-stub.js +37 -0
  139. package/dist/profiler/report.d.ts +1404 -0
  140. package/dist/profiler/report.js +2638 -0
  141. package/dist/profiler/river.d.ts +65 -0
  142. package/dist/profiler/river.js +298 -0
  143. package/dist/profiler/route-files.d.ts +22 -0
  144. package/dist/profiler/route-files.js +55 -0
  145. package/dist/profiler/route-imports.d.ts +14 -0
  146. package/dist/profiler/route-imports.js +83 -0
  147. package/dist/profiler/saving.d.ts +22 -0
  148. package/dist/profiler/saving.js +42 -0
  149. package/dist/profiler/score.d.ts +109 -0
  150. package/dist/profiler/score.js +261 -0
  151. package/dist/profiler/session-cookie.d.ts +28 -0
  152. package/dist/profiler/session-cookie.js +45 -0
  153. package/dist/profiler/sink.d.ts +81 -0
  154. package/dist/profiler/sink.js +124 -0
  155. package/dist/profiler/site-fixes.d.ts +25 -0
  156. package/dist/profiler/site-fixes.js +62 -0
  157. package/dist/profiler/source-scan.d.ts +210 -0
  158. package/dist/profiler/source-scan.js +1724 -0
  159. package/dist/profiler/span.d.ts +90 -0
  160. package/dist/profiler/span.js +109 -0
  161. package/dist/profiler/stacks.d.ts +43 -0
  162. package/dist/profiler/stacks.js +107 -0
  163. package/dist/profiler/standalone.d.ts +27 -0
  164. package/dist/profiler/standalone.js +98 -0
  165. package/dist/profiler/steps.d.ts +39 -0
  166. package/dist/profiler/steps.js +74 -0
  167. package/dist/profiler/storage/index.d.ts +87 -0
  168. package/dist/profiler/storage/index.js +76 -0
  169. package/dist/profiler/storage/postgres.d.ts +12 -0
  170. package/dist/profiler/storage/postgres.js +94 -0
  171. package/dist/profiler/storage/redis.d.ts +19 -0
  172. package/dist/profiler/storage/redis.js +148 -0
  173. package/dist/profiler/storage/sqlite.d.ts +2 -0
  174. package/dist/profiler/storage/sqlite.js +85 -0
  175. package/dist/profiler/storage/visits.d.ts +4 -0
  176. package/dist/profiler/storage/visits.js +6 -0
  177. package/dist/profiler/stream-tail.d.ts +26 -0
  178. package/dist/profiler/stream-tail.js +74 -0
  179. package/dist/profiler/timeline.d.ts +279 -0
  180. package/dist/profiler/timeline.js +690 -0
  181. package/dist/profiler/ui/AllocStrip.svelte +146 -0
  182. package/dist/profiler/ui/AllocStrip.svelte.d.ts +17 -0
  183. package/dist/profiler/ui/Awaits.svelte +363 -0
  184. package/dist/profiler/ui/Awaits.svelte.d.ts +16 -0
  185. package/dist/profiler/ui/ByteStrip.svelte +182 -0
  186. package/dist/profiler/ui/ByteStrip.svelte.d.ts +18 -0
  187. package/dist/profiler/ui/Compare.svelte +24 -0
  188. package/dist/profiler/ui/Compare.svelte.d.ts +16 -0
  189. package/dist/profiler/ui/CompareBody.svelte +429 -0
  190. package/dist/profiler/ui/CompareBody.svelte.d.ts +8 -0
  191. package/dist/profiler/ui/ComponentsTable.svelte +265 -0
  192. package/dist/profiler/ui/ComponentsTable.svelte.d.ts +20 -0
  193. package/dist/profiler/ui/Dashboard.svelte +492 -0
  194. package/dist/profiler/ui/Dashboard.svelte.d.ts +31 -0
  195. package/dist/profiler/ui/DataRiver.svelte +206 -0
  196. package/dist/profiler/ui/DataRiver.svelte.d.ts +13 -0
  197. package/dist/profiler/ui/DomTravel.svelte +207 -0
  198. package/dist/profiler/ui/DomTravel.svelte.d.ts +9 -0
  199. package/dist/profiler/ui/DownloadHtml.svelte +52 -0
  200. package/dist/profiler/ui/DownloadHtml.svelte.d.ts +10 -0
  201. package/dist/profiler/ui/Drill.svelte +276 -0
  202. package/dist/profiler/ui/Drill.svelte.d.ts +12 -0
  203. package/dist/profiler/ui/ExportButton.svelte +59 -0
  204. package/dist/profiler/ui/ExportButton.svelte.d.ts +8 -0
  205. package/dist/profiler/ui/Flame.svelte +222 -0
  206. package/dist/profiler/ui/Flame.svelte.d.ts +12 -0
  207. package/dist/profiler/ui/FrameDetails.svelte +308 -0
  208. package/dist/profiler/ui/FrameDetails.svelte.d.ts +16 -0
  209. package/dist/profiler/ui/FunctionsTable.svelte +156 -0
  210. package/dist/profiler/ui/FunctionsTable.svelte.d.ts +17 -0
  211. package/dist/profiler/ui/IslandHeatmap.svelte +151 -0
  212. package/dist/profiler/ui/IslandHeatmap.svelte.d.ts +16 -0
  213. package/dist/profiler/ui/IslandsTable.svelte +448 -0
  214. package/dist/profiler/ui/IslandsTable.svelte.d.ts +16 -0
  215. package/dist/profiler/ui/KeepLocal.svelte +46 -0
  216. package/dist/profiler/ui/KeepLocal.svelte.d.ts +8 -0
  217. package/dist/profiler/ui/Ledger.svelte +196 -0
  218. package/dist/profiler/ui/Ledger.svelte.d.ts +18 -0
  219. package/dist/profiler/ui/LocalCompare.svelte +48 -0
  220. package/dist/profiler/ui/LocalCompare.svelte.d.ts +8 -0
  221. package/dist/profiler/ui/LocalReports.svelte +68 -0
  222. package/dist/profiler/ui/LocalReports.svelte.d.ts +7 -0
  223. package/dist/profiler/ui/Login.svelte +13 -0
  224. package/dist/profiler/ui/Login.svelte.d.ts +12 -0
  225. package/dist/profiler/ui/LoginForm.svelte +42 -0
  226. package/dist/profiler/ui/LoginForm.svelte.d.ts +7 -0
  227. package/dist/profiler/ui/Message.svelte +10 -0
  228. package/dist/profiler/ui/Message.svelte.d.ts +12 -0
  229. package/dist/profiler/ui/OnThisPage.svelte +137 -0
  230. package/dist/profiler/ui/OnThisPage.svelte.d.ts +3 -0
  231. package/dist/profiler/ui/OneClock.svelte +297 -0
  232. package/dist/profiler/ui/OneClock.svelte.d.ts +27 -0
  233. package/dist/profiler/ui/Panel.svelte +10 -0
  234. package/dist/profiler/ui/Panel.svelte.d.ts +16 -0
  235. package/dist/profiler/ui/Paths.svelte +269 -0
  236. package/dist/profiler/ui/Paths.svelte.d.ts +15 -0
  237. package/dist/profiler/ui/Patterns.svelte +364 -0
  238. package/dist/profiler/ui/Patterns.svelte.d.ts +15 -0
  239. package/dist/profiler/ui/PermalinkGate.svelte +143 -0
  240. package/dist/profiler/ui/PermalinkGate.svelte.d.ts +10 -0
  241. package/dist/profiler/ui/RenderSteps.svelte +218 -0
  242. package/dist/profiler/ui/RenderSteps.svelte.d.ts +13 -0
  243. package/dist/profiler/ui/Report.svelte +28 -0
  244. package/dist/profiler/ui/Report.svelte.d.ts +20 -0
  245. package/dist/profiler/ui/ReportBody.svelte +2592 -0
  246. package/dist/profiler/ui/ReportBody.svelte.d.ts +21 -0
  247. package/dist/profiler/ui/Run.svelte +17 -0
  248. package/dist/profiler/ui/Run.svelte.d.ts +14 -0
  249. package/dist/profiler/ui/RunView.svelte +146 -0
  250. package/dist/profiler/ui/RunView.svelte.d.ts +10 -0
  251. package/dist/profiler/ui/ScoreCard.svelte +197 -0
  252. package/dist/profiler/ui/ScoreCard.svelte.d.ts +7 -0
  253. package/dist/profiler/ui/Scrub.svelte +293 -0
  254. package/dist/profiler/ui/Scrub.svelte.d.ts +18 -0
  255. package/dist/profiler/ui/SeedExplainer.svelte +193 -0
  256. package/dist/profiler/ui/SeedExplainer.svelte.d.ts +16 -0
  257. package/dist/profiler/ui/ShareLink.svelte +148 -0
  258. package/dist/profiler/ui/ShareLink.svelte.d.ts +8 -0
  259. package/dist/profiler/ui/Shell.svelte +50 -0
  260. package/dist/profiler/ui/Shell.svelte.d.ts +27 -0
  261. package/dist/profiler/ui/Sidebar.svelte +312 -0
  262. package/dist/profiler/ui/Sidebar.svelte.d.ts +7 -0
  263. package/dist/profiler/ui/Site.svelte +20 -0
  264. package/dist/profiler/ui/Site.svelte.d.ts +23 -0
  265. package/dist/profiler/ui/SiteView.svelte +385 -0
  266. package/dist/profiler/ui/SiteView.svelte.d.ts +27 -0
  267. package/dist/profiler/ui/ThemeSwitch.svelte +78 -0
  268. package/dist/profiler/ui/ThemeSwitch.svelte.d.ts +3 -0
  269. package/dist/profiler/ui/Timeline.svelte +672 -0
  270. package/dist/profiler/ui/Timeline.svelte.d.ts +22 -0
  271. package/dist/profiler/ui/Treemap.svelte +278 -0
  272. package/dist/profiler/ui/Treemap.svelte.d.ts +20 -0
  273. package/dist/profiler/ui/Upload.svelte +19 -0
  274. package/dist/profiler/ui/Upload.svelte.d.ts +10 -0
  275. package/dist/profiler/ui/UploadForm.svelte +59 -0
  276. package/dist/profiler/ui/UploadForm.svelte.d.ts +6 -0
  277. package/dist/profiler/ui/WaitingTable.svelte +55 -0
  278. package/dist/profiler/ui/WaitingTable.svelte.d.ts +14 -0
  279. package/dist/profiler/ui/Waterfall.svelte +371 -0
  280. package/dist/profiler/ui/Waterfall.svelte.d.ts +7 -0
  281. package/dist/profiler/ui/WhatIf.svelte +87 -0
  282. package/dist/profiler/ui/WhatIf.svelte.d.ts +18 -0
  283. package/dist/profiler/ui/fake-progress.svelte.d.ts +15 -0
  284. package/dist/profiler/ui/fake-progress.svelte.js +38 -0
  285. package/dist/profiler/ui/format.d.ts +20 -0
  286. package/dist/profiler/ui/format.js +71 -0
  287. package/dist/profiler/ui/permalink.d.ts +9 -0
  288. package/dist/profiler/ui/permalink.js +108 -0
  289. package/dist/profiler/ui/press.d.ts +5 -0
  290. package/dist/profiler/ui/press.js +19 -0
  291. package/dist/profiler/ui/profiler.css +650 -0
  292. package/dist/profiler/ui/report-data.d.ts +189 -0
  293. package/dist/profiler/ui/report-data.js +393 -0
  294. package/dist/profiler/ui/report-request.d.ts +6 -0
  295. package/dist/profiler/ui/report-request.js +50 -0
  296. package/dist/profiler/ui/row-anchor.svelte.d.ts +12 -0
  297. package/dist/profiler/ui/row-anchor.svelte.js +44 -0
  298. package/dist/profiler/ui/sort.svelte.d.ts +14 -0
  299. package/dist/profiler/ui/sort.svelte.js +37 -0
  300. package/dist/profiler/ui/store.d.ts +45 -0
  301. package/dist/profiler/ui/store.js +92 -0
  302. package/dist/profiler/visit.d.ts +389 -0
  303. package/dist/profiler/visit.js +1002 -0
  304. package/dist/report.d.ts +5 -0
  305. package/dist/report.js +4 -0
  306. package/dist/server.d.ts +11 -0
  307. package/dist/server.js +38 -0
  308. package/dist/vite.d.ts +12 -0
  309. package/dist/vite.js +78 -0
  310. package/package.json +103 -3
@@ -0,0 +1,287 @@
1
+ <!-- (its CSS injected into the dock's shadow root: see Devtools.svelte) -->
2
+ <svelte:options css="injected" />
3
+
4
+ <script>
5
+ /**
6
+ * The Bytes tab (byte ledger): real over-the-wire JS per island entry chunk + the shared runtime
7
+ * chunk, from PerformanceResourceTiming. Cold islands show `cold` and fill in live as the panel
8
+ * ticks. Measures each island's OWN chunk (not transitive deps); dev sizes are flagged.
9
+ */
10
+ import {
11
+ all_regions,
12
+ chunk_bytes,
13
+ basename,
14
+ kb,
15
+ region_name,
16
+ region_transitive
17
+ } from './regions.js';
18
+
19
+ import { page_ledger } from './ledger-dom.js';
20
+ import { profile_for, profiles_version } from './profile-store.js';
21
+
22
+ let { tick = 0 } = $props();
23
+ const IS_DEV = !!(import.meta.env && import.meta.env.DEV);
24
+
25
+ // THE EXACT LEDGER (a build): the page's island graph names every file each island needs, the
26
+ // browser says what each file weighed — each file counted once, and per island what only it needs
27
+ const exact = $derived.by(() => {
28
+ void tick;
29
+ return page_ledger();
30
+ });
31
+ // the modules the build shipped twice that this page loads both copies of (the last profile's)
32
+ const twice = $derived.by(() => {
33
+ void tick;
34
+ profiles_version();
35
+ return profile_for(location.pathname)?.assets?.twice ?? [];
36
+ });
37
+
38
+ const model = $derived.by(() => {
39
+ void tick; // refresh with the panel tick
40
+
41
+ // Group regions by entry chunk (dedupe: same component + strategy = ONE chunk, N instances).
42
+ const groups = new Map();
43
+ for (const r of all_regions()) {
44
+ if (!r.entry) continue;
45
+ const key = basename(r.entry);
46
+ const g = groups.get(key);
47
+ if (g) g.count++;
48
+ else groups.set(key, { entry: r.entry, kind: r.kind, wake: r.wake, count: 1 });
49
+ }
50
+
51
+ const rows = [...groups.values()]
52
+ .map((g) => {
53
+ const t = region_transitive(g.entry);
54
+ return {
55
+ ...g,
56
+ ...chunk_bytes(g.entry),
57
+ name: region_name(g.entry),
58
+ transitive: t ? t.bytes : 0,
59
+ modules: t ? t.modules : 0
60
+ };
61
+ })
62
+ // Sort by the real (transitive) cost when we have it, else by the entry-chunk wire size.
63
+ .sort((a, b) => b.transitive - a.transitive || b.wire - a.wire);
64
+
65
+ const runtimeSrc =
66
+ document.querySelector('script[data-ogygia-runtime]')?.getAttribute('src') || '';
67
+ const runtime = runtimeSrc ? { src: runtimeSrc, ...chunk_bytes(runtimeSrc) } : null;
68
+
69
+ // Page total over UNIQUE chunks (rows are already one-per-island). `wire` = wrapper chunks;
70
+ // `transitive` = each island's whole subgraph (the real-cost column).
71
+ const counted = new Set();
72
+ let wire = 0;
73
+ let transitive = 0;
74
+ for (const row of rows) {
75
+ const key = basename(row.entry);
76
+ if (counted.has(key)) continue;
77
+ counted.add(key);
78
+ if (row.loaded) wire += row.wire;
79
+ transitive += row.transitive;
80
+ }
81
+ if (runtime?.loaded && !counted.has(basename(runtime.src))) wire += runtime.wire;
82
+ return { rows, runtime, totalWire: wire, totalTransitive: transitive };
83
+ });
84
+ </script>
85
+
86
+ <h3>byte ledger — JavaScript per island</h3>
87
+ {#if exact}
88
+ <div class="note" data-og-ledger-exact>
89
+ Every file each island needs, from the page's island graph, weighed by the browser (over the
90
+ wire).
91
+ <b>only it</b> is what that island alone needs: what removing it would save. <b>shared</b> it shares
92
+ with other islands. The page total counts each file once.
93
+ </div>
94
+ <table>
95
+ <thead>
96
+ <tr
97
+ ><th>island</th><th>kind</th><th>files</th><th>loaded</th><th>only it</th><th>shared</th
98
+ ></tr
99
+ >
100
+ </thead>
101
+ <tbody>
102
+ {#each exact.rows as row (row.entry)}
103
+ <tr>
104
+ <td title={row.entry}
105
+ ><span class="nm">{row.name}</span>{#if row.count > 1}<span class="muted">
106
+ ×{row.count}</span
107
+ >{/if}</td
108
+ >
109
+ <td>{row.kind}{row.kind === 'island' ? ' · ' + row.wake : ''}</td>
110
+ <td
111
+ >{row.files}{#if row.cold}<span class="muted"> · {row.cold} cold</span>{/if}</td
112
+ >
113
+ <td
114
+ >{#if row.files > row.cold}{kb(row.wire)}{:else}<span class="muted">cold</span>{/if}</td
115
+ >
116
+ <td><span class="strong">{kb(row.unique)}</span></td>
117
+ <td class="muted">{kb(row.shared)}</td>
118
+ </tr>
119
+ {/each}
120
+ <tr>
121
+ <td>ogygia runtime</td>
122
+ <td class="muted">every island</td>
123
+ <td>{exact.runtime.files}</td>
124
+ <td>{kb(exact.runtime.wire)}</td>
125
+ <td class="muted">—</td>
126
+ <td class="muted">—</td>
127
+ </tr>
128
+ </tbody>
129
+ <tfoot>
130
+ <tr>
131
+ <td>page</td>
132
+ <td class="muted">each file once</td>
133
+ <td
134
+ >{exact.page.files}{#if exact.page.cold}<span class="muted">
135
+ · {exact.page.cold} cold</span
136
+ >{/if}</td
137
+ >
138
+ <td>{kb(exact.page.wire)}</td>
139
+ <td colspan="2" class="muted">{kb(exact.page.raw)} decoded</td>
140
+ </tr>
141
+ </tfoot>
142
+ </table>
143
+ {#if exact.shared.length}
144
+ <h3 class="sub">shared files</h3>
145
+ <table data-og-ledger-shared>
146
+ <tbody>
147
+ {#each exact.shared.slice(0, 8) as s (s.url)}
148
+ <tr>
149
+ <td title={s.url}>{basename(s.url)}</td>
150
+ <td>{kb(s.wire)}</td>
151
+ <td class="muted"
152
+ >{s.users.length > 4
153
+ ? `${s.users.slice(0, 3).join(', ')} and ${s.users.length - 3} more`
154
+ : s.users.join(', ')}</td
155
+ >
156
+ </tr>
157
+ {/each}
158
+ </tbody>
159
+ </table>
160
+ {/if}
161
+ {#if twice.length}
162
+ <!-- the last profile of this page: modules the build shipped twice, both copies loaded here -->
163
+ <h3 class="sub">loaded twice</h3>
164
+ <div class="note" data-og-ledger-twice>
165
+ One module reached by two paths (a package's source and its build, or two of its versions)
166
+ ships as two copies, and this page loads both: {kb(twice.reduce((s, d) => s + d.extra, 0))} of code
167
+ its browser downloads, parses and runs a second time. From the last profile.
168
+ </div>
169
+ <table>
170
+ <tbody>
171
+ {#each twice.slice(0, 8) as d (d.name)}
172
+ <tr>
173
+ <td>{d.name}</td>
174
+ <td>{kb(d.extra)}</td>
175
+ <td class="muted"
176
+ >{d.copies
177
+ .map((c) => `${basename(c.file)}${c.from ? ` (${c.from})` : ''}`)
178
+ .join(' · ')}</td
179
+ >
180
+ </tr>
181
+ {/each}
182
+ </tbody>
183
+ </table>
184
+ {/if}
185
+ {:else}
186
+ <div class="note">
187
+ Each <b>+deps</b> figure is that island's <b>whole bundle</b> — the component plus every shared
188
+ function and utility it imports. Shared code is therefore counted in <em>every</em> island that
189
+ uses it, so the figures overlap and the page total over-counts code that actually ships once.{#if IS_DEV}
190
+ Dev estimate: sizes are unbundled/unminified — build + preview for shipped numbers.{/if} A cold
191
+ island (not yet woken) shows <b>—</b> until it loads.
192
+ </div>
193
+
194
+ <table>
195
+ <thead>
196
+ <tr><th>island</th><th>kind</th><th>wrapper</th><th>+deps</th></tr>
197
+ </thead>
198
+ <tbody>
199
+ {#each model.rows as row (row.entry)}
200
+ <tr>
201
+ <td title={row.entry}>
202
+ <span class="nm">{row.name}</span>{#if row.count > 1}<span class="muted">
203
+ ×{row.count}</span
204
+ >{/if}
205
+ </td>
206
+ <td>{row.kind}{row.kind === 'island' ? ' · ' + row.wake : ''}</td>
207
+ <td
208
+ >{#if row.loaded}{kb(row.wire)}{:else}<span class="muted">cold</span>{/if}</td
209
+ >
210
+ <td>
211
+ {#if row.transitive}
212
+ <span class="strong">{kb(row.transitive)}</span><span class="muted">
213
+ · {row.modules} mod</span
214
+ >
215
+ {:else}<span class="muted">—</span>{/if}
216
+ </td>
217
+ </tr>
218
+ {:else}
219
+ <tr><td colspan="4" class="muted">no island chunks on this page</td></tr>
220
+ {/each}
221
+ {#if model.runtime}
222
+ <tr>
223
+ <td>ogygia runtime</td>
224
+ <td class="muted">shared</td>
225
+ <td>{model.runtime.loaded ? kb(model.runtime.wire) : '—'}</td>
226
+ <td class="muted">—</td>
227
+ </tr>
228
+ {/if}
229
+ </tbody>
230
+ <tfoot>
231
+ <tr>
232
+ <td>page total</td><td class="muted">unique · +deps</td>
233
+ <td>{kb(model.totalWire)}</td><td>{kb(model.totalTransitive)}</td>
234
+ </tr>
235
+ </tfoot>
236
+ </table>
237
+ {/if}
238
+
239
+ <style>
240
+ h3 {
241
+ margin: 0 0 8px;
242
+ font-size: 12px;
243
+ color: #5eead4;
244
+ }
245
+ h3.sub {
246
+ margin-top: 12px;
247
+ }
248
+ .note {
249
+ color: #94a3b8;
250
+ margin-bottom: 6px;
251
+ }
252
+ table {
253
+ border-collapse: collapse;
254
+ width: 100%;
255
+ }
256
+ th,
257
+ td {
258
+ text-align: right;
259
+ padding: 2px 8px;
260
+ white-space: nowrap;
261
+ }
262
+ th:first-child,
263
+ td:first-child,
264
+ th:nth-child(2),
265
+ td:nth-child(2) {
266
+ text-align: left;
267
+ }
268
+ thead th {
269
+ color: #94a3b8;
270
+ border-bottom: 1px solid rgba(148, 163, 184, 0.2);
271
+ }
272
+ tfoot td {
273
+ border-top: 1px solid rgba(148, 163, 184, 0.2);
274
+ color: #5eead4;
275
+ font-weight: 600;
276
+ }
277
+ .muted {
278
+ color: #94a3b8;
279
+ }
280
+ .nm {
281
+ color: #e2e8f0;
282
+ font-weight: 600;
283
+ }
284
+ .strong {
285
+ color: #e2e8f0;
286
+ }
287
+ </style>
@@ -0,0 +1,11 @@
1
+ export default LedgerTab;
2
+ type LedgerTab = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const LedgerTab: import("svelte").Component<{
7
+ tick?: number;
8
+ }, {}, "">;
9
+ type $$ComponentProps = {
10
+ tick?: number;
11
+ };
@@ -0,0 +1,290 @@
1
+ <!-- (its CSS injected into the dock's shadow root: see Devtools.svelte) -->
2
+ <svelte:options css="injected" />
3
+
4
+ <script>
5
+ /**
6
+ * The Lens tab: toggles the page-tinting {@link ./BoundaryOverlay.svelte overlay} and lists every
7
+ * region by NAME with its kind / schedule / JS cost / hydration state. Hovering a row lights up the
8
+ * matching box on the page (shared `focus`), and clicking a row smooth-scrolls that region into
9
+ * view — so the roster is a live index into the page, not just a static table. The overlay itself is
10
+ * drawn by BoundaryOverlay (a sibling under the root app); this tab controls it and mirrors it.
11
+ */
12
+ import { all_regions, region_name, region_transitive } from './regions.js';
13
+
14
+ let {
15
+ tick = 0,
16
+ overlay = $bindable(false),
17
+ focus = $bindable(null),
18
+ selected = $bindable(null),
19
+ picking = $bindable(false)
20
+ } = $props();
21
+
22
+ const kb = (n) => (n < 1024 ? n + ' B' : (n / 1024).toFixed(1) + ' KB');
23
+
24
+ const regions = $derived.by(() => {
25
+ void tick; // refresh with the panel tick
26
+ return all_regions().map((r) => ({
27
+ r,
28
+ name: region_name(r.entry),
29
+ js: r.kind === 'island' ? region_transitive(r.entry) : null
30
+ }));
31
+ });
32
+ const summary = $derived.by(() => {
33
+ const c = { island: 0, lake: 0, hole: 0 };
34
+ let js = 0;
35
+ let cold = 0;
36
+ for (const { r, js: t } of regions) {
37
+ c[r.kind]++;
38
+ if (t) js += t.bytes;
39
+ if (r.kind === 'island' && !r.hydrated) cold++;
40
+ }
41
+ return { ...c, js, cold };
42
+ });
43
+
44
+ function state_of(r) {
45
+ // (a nested island rides the island around it: awake with it, never on its own)
46
+ if (r.kind === 'island' && r.rides)
47
+ return r.hydrated ? 'rides its parent' : 'cold (with its parent)';
48
+ if (r.kind === 'island') return r.hydrated ? 'hydrated' : 'cold';
49
+ return r.hydrated ? 'filled' : 'pending';
50
+ }
51
+ function toggle_pick() {
52
+ picking = !picking;
53
+ if (picking) overlay = true; // need the boxes visible to pick one on the page
54
+ }
55
+ </script>
56
+
57
+ <div class="cap">
58
+ boundary lens <span class="muted">· every region on the page, x-rayed</span>
59
+ </div>
60
+
61
+ <div class="controls">
62
+ <button
63
+ class="btn"
64
+ data-og-overlay-toggle
65
+ class:on={overlay}
66
+ onclick={() => (overlay = !overlay)}
67
+ >
68
+ <span class="eye"></span>{overlay ? 'hide overlay' : 'show overlay'}
69
+ </button>
70
+ <button
71
+ class="btn pick"
72
+ data-og-pick
73
+ class:on={picking}
74
+ onclick={toggle_pick}
75
+ title="then click an island on the page"
76
+ >
77
+ <span class="target"></span>{picking ? 'click an island…' : 'pick on page'}
78
+ </button>
79
+ <span class="legend">
80
+ <span class="sw og-island"></span>{summary.island}
81
+ <span class="sw og-lake"></span>{summary.lake}
82
+ <span class="sw og-hole"></span>{summary.hole}
83
+ </span>
84
+ {#if summary.js > 0}<span class="tot"
85
+ >{kb(summary.js)} JS{#if summary.cold}<span class="muted">
86
+ · {summary.cold} cold</span
87
+ >{/if}</span
88
+ >{/if}
89
+ </div>
90
+
91
+ <table>
92
+ <thead>
93
+ <tr><th>island</th><th>wake</th><th>js + deps</th><th>state</th></tr>
94
+ </thead>
95
+ <tbody>
96
+ {#each regions as { r, name, js } (r.el)}
97
+ <tr
98
+ class:on={focus === r.el}
99
+ class:cold={r.kind === 'island' && !r.hydrated}
100
+ onmouseenter={() => (focus = r.el)}
101
+ onmouseleave={() => (focus = null)}
102
+ onclick={() => {
103
+ selected = r.el;
104
+ picking = false;
105
+ }}
106
+ title="inspect this region"
107
+ >
108
+ <!-- the name is a button: Tab reaches the row, Enter opens it (the press bubbles to the row) -->
109
+ <td
110
+ ><span class="dot og-{r.kind}"></span><button
111
+ class="nm rowbtn"
112
+ onfocus={() => (focus = r.el)}
113
+ onblur={() => (focus = null)}>{name}</button
114
+ ></td
115
+ >
116
+ <td>{r.kind === 'island' ? r.wake : r.kind}</td>
117
+ <td class="mono">
118
+ {#if r.kind !== 'island'}<span class="muted">0 B</span>
119
+ {:else if js}{kb(js.bytes)}
120
+ {:else}<span class="muted">—</span>{/if}
121
+ </td>
122
+ <td class:coldstate={r.kind === 'island' && !r.hydrated}>{state_of(r)}</td>
123
+ </tr>
124
+ {:else}
125
+ <tr><td colspan="4" class="muted">no regions on this page</td></tr>
126
+ {/each}
127
+ </tbody>
128
+ </table>
129
+
130
+ <style>
131
+ .cap {
132
+ font-size: 12px;
133
+ color: #5eead4;
134
+ margin-bottom: 8px;
135
+ }
136
+ .controls {
137
+ display: flex;
138
+ align-items: center;
139
+ gap: 12px;
140
+ margin-bottom: 10px;
141
+ }
142
+ .btn {
143
+ display: inline-flex;
144
+ align-items: center;
145
+ gap: 7px;
146
+ padding: 5px 11px;
147
+ border-radius: 7px;
148
+ border: 1px solid rgba(148, 163, 184, 0.3);
149
+ background: #0d1526;
150
+ color: #e2e8f0;
151
+ cursor: pointer;
152
+ font: inherit;
153
+ }
154
+ .btn .eye {
155
+ width: 9px;
156
+ height: 9px;
157
+ border-radius: 50%;
158
+ border: 1.5px solid currentColor;
159
+ opacity: 0.7;
160
+ }
161
+ .btn.on {
162
+ background: #14b8a6;
163
+ color: #022;
164
+ border-color: #0d9488;
165
+ }
166
+ .btn.on .eye {
167
+ opacity: 1;
168
+ background: currentColor;
169
+ }
170
+ .btn.pick .target {
171
+ width: 10px;
172
+ height: 10px;
173
+ border-radius: 50%;
174
+ border: 1.5px solid currentColor;
175
+ position: relative;
176
+ opacity: 0.75;
177
+ }
178
+ .btn.pick .target::after {
179
+ content: '';
180
+ position: absolute;
181
+ inset: 3px;
182
+ border-radius: 50%;
183
+ background: currentColor;
184
+ }
185
+ .btn.pick.on {
186
+ background: #f59e0b;
187
+ color: #201400;
188
+ border-color: #d97706;
189
+ }
190
+ .btn.pick.on .target {
191
+ opacity: 1;
192
+ }
193
+ .legend {
194
+ color: #94a3b8;
195
+ display: flex;
196
+ align-items: center;
197
+ gap: 5px;
198
+ }
199
+ .tot {
200
+ margin-left: auto;
201
+ color: #5eead4;
202
+ font-weight: 600;
203
+ }
204
+ .sw {
205
+ display: inline-block;
206
+ width: 10px;
207
+ height: 10px;
208
+ border-radius: 3px;
209
+ margin-left: 6px;
210
+ }
211
+ .sw.og-island,
212
+ .dot.og-island {
213
+ background: #14b8a6;
214
+ }
215
+ .sw.og-lake,
216
+ .dot.og-lake {
217
+ background: #f59e0b;
218
+ }
219
+ .sw.og-hole,
220
+ .dot.og-hole {
221
+ background: #8b5cf6;
222
+ }
223
+ .dot {
224
+ display: inline-block;
225
+ width: 8px;
226
+ height: 8px;
227
+ border-radius: 50%;
228
+ margin-right: 7px;
229
+ vertical-align: 0;
230
+ }
231
+ .nm {
232
+ color: #e2e8f0;
233
+ font-weight: 600;
234
+ }
235
+ /* a button that reads as the name it was */
236
+ .rowbtn {
237
+ all: unset;
238
+ cursor: pointer;
239
+ }
240
+ /* (after the reset: the name's own look) */
241
+ .rowbtn.nm {
242
+ color: #e2e8f0;
243
+ font-weight: 600;
244
+ }
245
+ .rowbtn:focus-visible {
246
+ outline: 2px solid rgba(94, 234, 212, 0.7);
247
+ outline-offset: 2px;
248
+ border-radius: 3px;
249
+ }
250
+ table {
251
+ border-collapse: collapse;
252
+ width: 100%;
253
+ }
254
+ th,
255
+ td {
256
+ text-align: right;
257
+ padding: 3px 8px;
258
+ white-space: nowrap;
259
+ }
260
+ th:first-child,
261
+ td:first-child,
262
+ th:nth-child(2),
263
+ td:nth-child(2) {
264
+ text-align: left;
265
+ }
266
+ thead th {
267
+ color: #94a3b8;
268
+ border-bottom: 1px solid rgba(148, 163, 184, 0.2);
269
+ }
270
+ tbody tr {
271
+ cursor: pointer;
272
+ border-radius: 5px;
273
+ }
274
+ tbody tr:hover,
275
+ tbody tr.on {
276
+ background: rgba(94, 234, 212, 0.12);
277
+ }
278
+ tbody tr.on {
279
+ box-shadow: inset 2px 0 0 #5eead4;
280
+ }
281
+ .muted {
282
+ color: #94a3b8;
283
+ }
284
+ .mono {
285
+ font-variant-numeric: tabular-nums;
286
+ }
287
+ .coldstate {
288
+ color: #94a3b8;
289
+ }
290
+ </style>
@@ -0,0 +1,19 @@
1
+ export default LensTab;
2
+ type LensTab = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const LensTab: import("svelte").Component<{
7
+ tick?: number;
8
+ overlay?: boolean;
9
+ focus?: any;
10
+ selected?: any;
11
+ picking?: boolean;
12
+ }, {}, "focus" | "overlay" | "selected" | "picking">;
13
+ type $$ComponentProps = {
14
+ tick?: number;
15
+ overlay?: boolean;
16
+ focus?: any;
17
+ selected?: any;
18
+ picking?: boolean;
19
+ };