@qwik.dev/devtools 0.2.1 → 0.2.3

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 (55) hide show
  1. package/dist/plugin/index.d.ts +4 -1
  2. package/dist/plugin/index.js +2078 -595
  3. package/dist/ui/_virtual/browser.qwik.mjs +8 -0
  4. package/dist/ui/_virtual/browser.qwik2.mjs +4 -0
  5. package/dist/ui/components/DevtoolsButton/DevtoolsButton.qwik.mjs +1 -1
  6. package/dist/ui/components/DevtoolsPanel/DevtoolsPanel.qwik.mjs +1 -1
  7. package/dist/ui/components/Tab/Tab.qwik.mjs +1 -1
  8. package/dist/ui/components/TabContent/TabContent.qwik.mjs +1 -1
  9. package/dist/ui/components/ThemeToggle/QwikThemeToggle.qwik.mjs +1 -1
  10. package/dist/ui/components/Tree/Tree.qwik.mjs +1 -1
  11. package/dist/ui/devtools.qwik.mjs +73 -72
  12. package/dist/ui/features/Assets/Assets.qwik.mjs +3 -3
  13. package/dist/ui/features/CodeBreack/CodeBreack.qwik.mjs +4 -4
  14. package/dist/ui/features/CodeBreack/HtmlParser.qwik.mjs +13 -20
  15. package/dist/ui/features/CodeBreack/StateParser.qwik.mjs +13 -20
  16. package/dist/ui/features/Overview/Overview.qwik.mjs +17 -17
  17. package/dist/ui/features/Packages/Packages.qwik.mjs +4 -4
  18. package/dist/ui/features/Packages/components/DependencyCard/DependencyCard.qwik.mjs +9 -9
  19. package/dist/ui/features/Packages/components/PackageIcon/PackageIcon.qwik.mjs +1 -1
  20. package/dist/ui/features/Performance/Performance.qwik.mjs +307 -0
  21. package/dist/ui/features/Performance/computePerfViewModel.qwik.mjs +101 -0
  22. package/dist/ui/features/Performance/transformPerformanceData.qwik.mjs +34 -0
  23. package/dist/ui/features/RenderTree/RenderTree.qwik.mjs +38 -45
  24. package/dist/ui/features/RenderTree/TreeBuilder.qwik.mjs +181 -0
  25. package/dist/ui/features/RenderTree/data.qwik.mjs +30 -16
  26. package/dist/ui/features/RenderTree/formatTreeData.qwik.mjs +205 -230
  27. package/dist/ui/features/RenderTree/types.qwik.mjs +50 -0
  28. package/dist/ui/features/Routes/Routes.qwik.mjs +3 -3
  29. package/dist/ui/features/inspect/Inspect.qwik.mjs +1 -1
  30. package/dist/ui/global.css.qwik.mjs +1 -1
  31. package/dist/ui/lib-types/kit/src/globals.d.ts +56 -5
  32. package/dist/ui/lib-types/kit/src/index.d.ts +1 -0
  33. package/dist/ui/lib-types/kit/src/types.d.ts +9 -0
  34. package/dist/ui/lib-types/ui/src/features/Performance/Performance.d.ts +1 -0
  35. package/dist/ui/lib-types/ui/src/features/Performance/computePerfViewModel.d.ts +33 -0
  36. package/dist/ui/lib-types/ui/src/features/Performance/computePerfViewModel.test.d.ts +1 -0
  37. package/dist/ui/lib-types/ui/src/features/Performance/transformPerformanceData.d.ts +22 -0
  38. package/dist/ui/lib-types/ui/src/features/Performance/transformPerformanceData.test.d.ts +1 -0
  39. package/dist/ui/lib-types/ui/src/features/RenderTree/TreeBuilder.d.ts +60 -0
  40. package/dist/ui/lib-types/ui/src/features/RenderTree/data.d.ts +34 -8
  41. package/dist/ui/lib-types/ui/src/features/RenderTree/formatTreeData.d.ts +79 -148
  42. package/dist/ui/lib-types/ui/src/features/RenderTree/index.d.ts +6 -0
  43. package/dist/ui/lib-types/ui/src/features/RenderTree/types.d.ts +116 -0
  44. package/dist/ui/lib-types/ui/src/types/state.d.ts +1 -1
  45. package/dist/ui/lib-types/ui/src/utils/shiki.d.ts +2 -0
  46. package/dist/ui/node_modules/.pnpm/@qwikest_icons@0.0.13_@builder.io_qwik@1.11.0_vite@7.1.3_@types_node@20.14.11_jiti@2.6._02d306fcbd9f637dd624291702bff9c0/node_modules/@qwikest/icons/lib/hi.qwik.qwik.mjs +19 -0
  47. package/dist/ui/node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/browser.qwik.mjs +177 -0
  48. package/dist/ui/node_modules/.pnpm/debug@4.4.3_supports-color@5.5.0/node_modules/debug/src/common.qwik.mjs +182 -0
  49. package/dist/ui/node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.qwik.mjs +120 -0
  50. package/dist/ui/packages/kit/src/constants.qwik.mjs +0 -2
  51. package/dist/ui/packages/kit/src/context.qwik.mjs +5 -4
  52. package/dist/ui/utils/shiki.qwik.mjs +23 -0
  53. package/package.json +3 -3
  54. package/dist/ui/features/RenderTree/transfromqseq.qwik.mjs +0 -91
  55. package/dist/ui/lib-types/ui/src/features/RenderTree/transfromqseq.d.ts +0 -7
@@ -19,12 +19,12 @@ const Overview = component$(({ state }) => {
19
19
  $(() => pageJump("routes")),
20
20
  stopPropagation
21
21
  ],
22
- class: "flex cursor-pointer items-center gap-5 rounded-xl border border-border bg-card-item-bg p-5 transition-all duration-200 hover:-translate-y-0.5 hover:bg-card-item-hover-bg",
22
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex cursor-pointer items-center gap-5 rounded-xl border p-5 transition-all duration-200 hover:-translate-y-0.5",
23
23
  children: [
24
24
  /* @__PURE__ */ jsx("div", {
25
- class: "bg-foreground/5 rounded-lg border border-border p-3.5",
25
+ class: "bg-foreground/5 border-border rounded-lg border p-3.5",
26
26
  children: /* @__PURE__ */ jsx(LuFolderTree, {
27
- class: "h-6 w-6 text-accent"
27
+ class: "text-accent h-6 w-6"
28
28
  })
29
29
  }),
30
30
  /* @__PURE__ */ jsxs("div", {
@@ -34,7 +34,7 @@ const Overview = component$(({ state }) => {
34
34
  children: state.routes?.length
35
35
  }),
36
36
  /* @__PURE__ */ jsx("div", {
37
- class: "text-sm text-muted-foreground",
37
+ class: "text-muted-foreground text-sm",
38
38
  children: "pages"
39
39
  })
40
40
  ]
@@ -46,12 +46,12 @@ const Overview = component$(({ state }) => {
46
46
  $(() => pageJump("components")),
47
47
  stopPropagation
48
48
  ],
49
- class: "flex cursor-pointer items-center gap-5 rounded-xl border border-border bg-card-item-bg p-5 transition-all duration-200 hover:-translate-y-0.5 hover:bg-card-item-hover-bg",
49
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex cursor-pointer items-center gap-5 rounded-xl border p-5 transition-all duration-200 hover:-translate-y-0.5",
50
50
  children: [
51
51
  /* @__PURE__ */ jsx("div", {
52
- class: "bg-foreground/5 rounded-lg border border-border p-3.5",
52
+ class: "bg-foreground/5 border-border rounded-lg border p-3.5",
53
53
  children: /* @__PURE__ */ jsx(HiCubeOutline, {
54
- class: "h-6 w-6 text-accent"
54
+ class: "text-accent h-6 w-6"
55
55
  })
56
56
  }),
57
57
  /* @__PURE__ */ jsxs("div", {
@@ -61,7 +61,7 @@ const Overview = component$(({ state }) => {
61
61
  children: state.components.length
62
62
  }),
63
63
  /* @__PURE__ */ jsx("div", {
64
- class: "text-sm text-muted-foreground",
64
+ class: "text-muted-foreground text-sm",
65
65
  children: "components"
66
66
  })
67
67
  ]
@@ -73,12 +73,12 @@ const Overview = component$(({ state }) => {
73
73
  $(() => pageJump("assets")),
74
74
  stopPropagation
75
75
  ],
76
- class: "flex cursor-pointer items-center gap-5 rounded-xl border border-border bg-card-item-bg p-5 transition-all duration-200 hover:-translate-y-0.5 hover:bg-card-item-hover-bg",
76
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex cursor-pointer items-center gap-5 rounded-xl border p-5 transition-all duration-200 hover:-translate-y-0.5",
77
77
  children: [
78
78
  /* @__PURE__ */ jsx("div", {
79
- class: "bg-foreground/5 rounded-lg border border-border p-3.5",
79
+ class: "bg-foreground/5 border-border rounded-lg border p-3.5",
80
80
  children: /* @__PURE__ */ jsx(HiPhotoOutline, {
81
- class: "h-6 w-6 text-accent"
81
+ class: "text-accent h-6 w-6"
82
82
  })
83
83
  }),
84
84
  /* @__PURE__ */ jsxs("div", {
@@ -88,7 +88,7 @@ const Overview = component$(({ state }) => {
88
88
  children: state.assets.length || 0
89
89
  }),
90
90
  /* @__PURE__ */ jsx("div", {
91
- class: "text-sm text-muted-foreground",
91
+ class: "text-muted-foreground text-sm",
92
92
  children: "assets"
93
93
  })
94
94
  ]
@@ -102,7 +102,7 @@ const Overview = component$(({ state }) => {
102
102
  $(() => pageJump("packages")),
103
103
  stopPropagation
104
104
  ],
105
- class: "cursor-pointer space-y-4 rounded-xl border border-border bg-card-item-bg p-5 hover:-translate-y-0.5 hover:bg-card-item-hover-bg mt-6 md:mt-6",
105
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg mt-6 cursor-pointer space-y-4 rounded-xl border p-5 hover:-translate-y-0.5 md:mt-6",
106
106
  children: [
107
107
  /* @__PURE__ */ jsx("h3", {
108
108
  class: "text-lg font-semibold",
@@ -118,7 +118,7 @@ const Overview = component$(({ state }) => {
118
118
  children: name
119
119
  }),
120
120
  /* @__PURE__ */ jsx("div", {
121
- class: "bg-foreground/5 rounded-full border border-border px-2 py-1 text-xs text-muted-foreground",
121
+ class: "bg-foreground/5 border-border text-muted-foreground rounded-full border px-2 py-1 text-xs",
122
122
  children: version
123
123
  })
124
124
  ]
@@ -127,7 +127,7 @@ const Overview = component$(({ state }) => {
127
127
  ]
128
128
  }),
129
129
  /* @__PURE__ */ jsxs("div", {
130
- class: "space-y-4 rounded-xl border border-border bg-card-item-bg p-5 mt-6 md:mt-6",
130
+ class: "border-border bg-card-item-bg mt-6 space-y-4 rounded-xl border p-5 md:mt-6",
131
131
  children: [
132
132
  /* @__PURE__ */ jsx("h3", {
133
133
  class: "text-lg font-semibold",
@@ -137,7 +137,7 @@ const Overview = component$(({ state }) => {
137
137
  class: "space-y-3",
138
138
  children: [
139
139
  /* @__PURE__ */ jsxs("div", {
140
- class: "flex justify-between border-b border-border py-2",
140
+ class: "border-border flex justify-between border-b py-2",
141
141
  children: [
142
142
  /* @__PURE__ */ jsx("span", {
143
143
  class: "text-muted-foreground",
@@ -150,7 +150,7 @@ const Overview = component$(({ state }) => {
150
150
  ]
151
151
  }),
152
152
  /* @__PURE__ */ jsxs("div", {
153
- class: "flex justify-between border-b border-border py-2",
153
+ class: "border-border flex justify-between border-b py-2",
154
154
  children: [
155
155
  /* @__PURE__ */ jsx("span", {
156
156
  class: "text-muted-foreground",
@@ -14,16 +14,16 @@ const Packages = component$(({ state }) => {
14
14
  class: "flex items-center gap-2",
15
15
  children: [
16
16
  /* @__PURE__ */ jsx("div", {
17
- class: "border-t-foreground/40 animate-spin h-5 w-5 rounded-full border-2 border-border"
17
+ class: "border-t-foreground/40 border-border h-5 w-5 animate-spin rounded-full border-2"
18
18
  }),
19
19
  /* @__PURE__ */ jsx("span", {
20
- class: "text-sm text-muted-foreground",
20
+ class: "text-muted-foreground text-sm",
21
21
  children: "Loading dependencies..."
22
22
  })
23
23
  ]
24
24
  }),
25
25
  /* @__PURE__ */ jsxs("div", {
26
- class: "text-center text-xs text-muted-foreground",
26
+ class: "text-muted-foreground text-center text-xs",
27
27
  children: [
28
28
  "Dependencies are being preloaded in the background...",
29
29
  /* @__PURE__ */ jsx("br", {}),
@@ -38,7 +38,7 @@ const Packages = component$(({ state }) => {
38
38
  return /* @__PURE__ */ jsx("div", {
39
39
  class: "py-8 text-center",
40
40
  children: /* @__PURE__ */ jsx("div", {
41
- class: "text-sm text-muted-foreground",
41
+ class: "text-muted-foreground text-sm",
42
42
  children: "No dependencies found in package.json"
43
43
  })
44
44
  });
@@ -49,13 +49,13 @@ const DependencyCard = component$(({ pkg }) => {
49
49
  class: "min-w-0 flex-1",
50
50
  children: [
51
51
  /* @__PURE__ */ jsx("h3", {
52
- class: "mb-1.5 cursor-pointer truncate text-base font-bold text-foreground transition-colors hover:text-primary",
52
+ class: "text-foreground hover:text-primary mb-1.5 cursor-pointer truncate text-base font-bold transition-colors",
53
53
  onClick$: handlePackageClick,
54
54
  title: pkg.name,
55
55
  children: pkg.name
56
56
  }),
57
57
  /* @__PURE__ */ jsxs("span", {
58
- class: "bg-primary/10 border-primary/20 inline-flex items-center gap-1 rounded-md border px-2.5 py-0.5 text-xs font-medium text-primary",
58
+ class: "bg-primary/10 border-primary/20 text-primary inline-flex items-center gap-1 rounded-md border px-2.5 py-0.5 text-xs font-medium",
59
59
  children: [
60
60
  /* @__PURE__ */ jsx("svg", {
61
61
  class: "h-3 w-3",
@@ -78,7 +78,7 @@ const DependencyCard = component$(({ pkg }) => {
78
78
  ]
79
79
  }),
80
80
  /* @__PURE__ */ jsx("p", {
81
- class: "line-clamp-2 min-h-[2.5rem] text-sm leading-relaxed text-muted-foreground",
81
+ class: "text-muted-foreground line-clamp-2 min-h-[2.5rem] text-sm leading-relaxed",
82
82
  children: pkg.description || "No description available"
83
83
  }),
84
84
  /* @__PURE__ */ jsx("div", {
@@ -95,14 +95,14 @@ const DependencyCard = component$(({ pkg }) => {
95
95
  onClick$: handleAuthorClick,
96
96
  title: `Contact ${pkg.author.name}`,
97
97
  children: /* @__PURE__ */ jsx("span", {
98
- class: "text-[10px] font-semibold text-accent",
98
+ class: "text-accent text-[10px] font-semibold",
99
99
  children: pkg.author.name.split(" ").map((n) => n.charAt(0)).join("").substring(0, 2).toUpperCase()
100
100
  })
101
101
  }),
102
102
  /* @__PURE__ */ jsx("span", {
103
- class: "truncate text-xs text-muted-foreground",
103
+ class: "text-muted-foreground truncate text-xs",
104
104
  children: /* @__PURE__ */ jsx("span", {
105
- class: "font-medium text-foreground",
105
+ class: "text-foreground font-medium",
106
106
  children: pkg.author.name
107
107
  })
108
108
  })
@@ -115,7 +115,7 @@ const DependencyCard = component$(({ pkg }) => {
115
115
  children: [
116
116
  pkg.homepage && /* @__PURE__ */ jsx("button", {
117
117
  onClick$: handleHomepageClick,
118
- class: "hover:bg-primary/10 group/btn rounded-lg p-1.5 text-muted-foreground transition-all duration-200 hover:text-primary",
118
+ class: "hover:bg-primary/10 group/btn text-muted-foreground hover:text-primary rounded-lg p-1.5 transition-all duration-200",
119
119
  title: "Homepage",
120
120
  children: /* @__PURE__ */ jsx("svg", {
121
121
  class: "h-4 w-4",
@@ -132,7 +132,7 @@ const DependencyCard = component$(({ pkg }) => {
132
132
  }),
133
133
  pkg.repository && /* @__PURE__ */ jsx("button", {
134
134
  onClick$: handleRepositoryClick,
135
- class: "hover:bg-primary/10 group/btn rounded-lg p-1.5 text-muted-foreground transition-all duration-200 hover:text-primary",
135
+ class: "hover:bg-primary/10 group/btn text-muted-foreground hover:text-primary rounded-lg p-1.5 transition-all duration-200",
136
136
  title: "Repository",
137
137
  children: /* @__PURE__ */ jsx("svg", {
138
138
  class: "h-4 w-4",
@@ -145,7 +145,7 @@ const DependencyCard = component$(({ pkg }) => {
145
145
  }),
146
146
  pkg.npmUrl && /* @__PURE__ */ jsx("button", {
147
147
  onClick$: handlePackageClick,
148
- class: "hover:bg-primary/10 group/btn rounded-lg p-1.5 text-muted-foreground transition-all duration-200 hover:text-primary",
148
+ class: "hover:bg-primary/10 group/btn text-muted-foreground hover:text-primary rounded-lg p-1.5 transition-all duration-200",
149
149
  title: "npm",
150
150
  children: /* @__PURE__ */ jsx("svg", {
151
151
  class: "h-4 w-4",
@@ -8,7 +8,7 @@ const PackageIcon = component$(({ packageName, iconUrl }) => {
8
8
  const fallbackInitial = packageName.split("/").pop()?.charAt(0).toUpperCase() || packageName.charAt(0).toUpperCase();
9
9
  if (!iconUrl || iconError.value) {
10
10
  return /* @__PURE__ */ jsx("span", {
11
- class: "text-sm font-bold text-primary",
11
+ class: "text-primary text-sm font-bold",
12
12
  children: fallbackInitial
13
13
  });
14
14
  }
@@ -0,0 +1,307 @@
1
+ import { jsx, jsxs, Fragment } from "@qwik.dev/core/jsx-runtime";
2
+ import { component$, useSignal, useTask$, isBrowser, useComputed$, $ } from "@qwik.dev/core";
3
+ import { computePerfViewModel, computeEventRows } from "./computePerfViewModel.qwik.mjs";
4
+ function formatMs(ms) {
5
+ if (!Number.isFinite(ms)) return "-";
6
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
7
+ if (ms >= 10) return `${ms.toFixed(0)}ms`;
8
+ return `${ms.toFixed(2)}ms`;
9
+ }
10
+ const Performance = component$(() => {
11
+ const perf = useSignal(null);
12
+ const selectedComponent = useSignal(null);
13
+ useTask$(() => {
14
+ if (!isBrowser) return;
15
+ perf.value = window.__QWIK_PERF__ || {
16
+ ssr: [],
17
+ csr: []
18
+ };
19
+ });
20
+ const vm = useComputed$(() => computePerfViewModel(perf.value));
21
+ const selectedVm = useComputed$(() => {
22
+ const name = selectedComponent.value;
23
+ if (!name) return null;
24
+ return vm.value.components.find((c) => c.componentName === name) || null;
25
+ });
26
+ const onSelect = $((name) => {
27
+ selectedComponent.value = name;
28
+ });
29
+ const clearSelect = $(() => {
30
+ selectedComponent.value = null;
31
+ });
32
+ return /* @__PURE__ */ jsx("div", {
33
+ class: "h-full w-full flex-1 overflow-hidden",
34
+ children: !perf.value?.ssr?.length && !perf.value?.csr?.length ? /* @__PURE__ */ jsx("div", {
35
+ class: "border-border bg-card-item-bg flex h-full items-center justify-center rounded-xl border p-8",
36
+ children: /* @__PURE__ */ jsxs("div", {
37
+ class: "text-muted-foreground text-center text-sm",
38
+ children: [
39
+ "No performance data found.",
40
+ /* @__PURE__ */ jsx("div", {
41
+ class: "mt-1 text-xs",
42
+ children: "Ensure instrumentation is enabled and interact with the app, then reopen this tab."
43
+ })
44
+ ]
45
+ })
46
+ }) : /* @__PURE__ */ jsxs("div", {
47
+ class: "flex h-full min-h-0 flex-col gap-4",
48
+ children: [
49
+ /* @__PURE__ */ jsxs("div", {
50
+ class: "grid grid-cols-1 gap-5 md:grid-cols-4",
51
+ children: [
52
+ /* @__PURE__ */ jsx("div", {
53
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex items-center gap-4 rounded-xl border p-5 transition-all duration-200",
54
+ children: /* @__PURE__ */ jsxs("div", {
55
+ class: "flex-1",
56
+ children: [
57
+ /* @__PURE__ */ jsx("div", {
58
+ class: "text-muted-foreground text-xs font-medium",
59
+ children: "TOTAL RENDER TIME"
60
+ }),
61
+ /* @__PURE__ */ jsx("div", {
62
+ class: "mt-1 text-3xl font-semibold",
63
+ children: formatMs(vm.value.overview.totalRenderTime)
64
+ })
65
+ ]
66
+ })
67
+ }),
68
+ /* @__PURE__ */ jsx("div", {
69
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex items-center gap-4 rounded-xl border p-5 transition-all duration-200",
70
+ children: /* @__PURE__ */ jsxs("div", {
71
+ class: "flex-1",
72
+ children: [
73
+ /* @__PURE__ */ jsx("div", {
74
+ class: "text-muted-foreground text-xs font-medium",
75
+ children: "SLOWEST COMPONENT"
76
+ }),
77
+ /* @__PURE__ */ jsx("div", {
78
+ class: "mt-1 text-lg font-semibold",
79
+ children: vm.value.overview.slowestComponent?.componentName || "-"
80
+ }),
81
+ /* @__PURE__ */ jsx("div", {
82
+ class: "text-muted-foreground mt-1 text-xs",
83
+ children: vm.value.overview.slowestComponent ? `${formatMs(vm.value.overview.slowestComponent.avgTime)} avg` : "-"
84
+ })
85
+ ]
86
+ })
87
+ }),
88
+ /* @__PURE__ */ jsx("div", {
89
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex items-center gap-4 rounded-xl border p-5 transition-all duration-200",
90
+ children: /* @__PURE__ */ jsxs("div", {
91
+ class: "flex-1",
92
+ children: [
93
+ /* @__PURE__ */ jsx("div", {
94
+ class: "text-muted-foreground text-xs font-medium",
95
+ children: "AVG TIME"
96
+ }),
97
+ /* @__PURE__ */ jsx("div", {
98
+ class: "mt-1 text-3xl font-semibold",
99
+ children: formatMs(vm.value.overview.avgTime)
100
+ })
101
+ ]
102
+ })
103
+ }),
104
+ /* @__PURE__ */ jsx("div", {
105
+ class: "border-border bg-card-item-bg hover:bg-card-item-hover-bg flex items-center gap-4 rounded-xl border p-5 transition-all duration-200",
106
+ children: /* @__PURE__ */ jsxs("div", {
107
+ class: "flex-1",
108
+ children: [
109
+ /* @__PURE__ */ jsx("div", {
110
+ class: "text-muted-foreground text-xs font-medium",
111
+ children: "TOTAL CALLS"
112
+ }),
113
+ /* @__PURE__ */ jsx("div", {
114
+ class: "mt-1 text-3xl font-semibold",
115
+ children: vm.value.overview.totalCalls
116
+ })
117
+ ]
118
+ })
119
+ })
120
+ ]
121
+ }),
122
+ /* @__PURE__ */ jsxs("div", {
123
+ class: "border-border bg-background flex min-h-0 flex-1 overflow-hidden rounded-md border",
124
+ children: [
125
+ /* @__PURE__ */ jsxs("div", {
126
+ class: "min-h-0 flex-1 overflow-y-auto p-4",
127
+ children: [
128
+ /* @__PURE__ */ jsx("div", {
129
+ class: "mb-3 flex items-center justify-between",
130
+ children: /* @__PURE__ */ jsxs("div", {
131
+ children: [
132
+ /* @__PURE__ */ jsx("div", {
133
+ class: "text-lg font-semibold",
134
+ children: "Components"
135
+ }),
136
+ /* @__PURE__ */ jsxs("div", {
137
+ class: "text-muted-foreground text-xs",
138
+ children: [
139
+ "CSR only • ",
140
+ vm.value.components.length,
141
+ " total"
142
+ ]
143
+ })
144
+ ]
145
+ })
146
+ }),
147
+ /* @__PURE__ */ jsx("div", {
148
+ class: "grid grid-cols-1 gap-4 md:grid-cols-2",
149
+ children: vm.value.components.map((c) => {
150
+ const selected = selectedComponent.value === c.componentName;
151
+ return /* @__PURE__ */ jsx("button", {
152
+ onClick$: () => onSelect(c.componentName),
153
+ class: [
154
+ "border-border bg-card-item-bg hover:bg-card-item-hover-bg w-full rounded-xl border p-4 text-left transition-all duration-200 hover:-translate-y-0.5",
155
+ selected ? "ring-primary-active ring-2" : ""
156
+ ].join(" "),
157
+ children: /* @__PURE__ */ jsxs("div", {
158
+ class: "flex items-start justify-between gap-4",
159
+ children: [
160
+ /* @__PURE__ */ jsxs("div", {
161
+ class: "min-w-0 flex-1",
162
+ children: [
163
+ /* @__PURE__ */ jsx("div", {
164
+ class: "truncate text-base font-semibold",
165
+ children: c.componentName
166
+ }),
167
+ /* @__PURE__ */ jsxs("div", {
168
+ class: "text-muted-foreground mt-1 text-xs",
169
+ children: [
170
+ "Avg: ",
171
+ formatMs(c.avgTime)
172
+ ]
173
+ })
174
+ ]
175
+ }),
176
+ /* @__PURE__ */ jsxs("div", {
177
+ class: "shrink-0 text-right",
178
+ children: [
179
+ /* @__PURE__ */ jsx("div", {
180
+ class: "text-primary text-lg font-semibold",
181
+ children: formatMs(c.totalTime)
182
+ }),
183
+ /* @__PURE__ */ jsxs("div", {
184
+ class: "text-muted-foreground text-xs",
185
+ children: [
186
+ "SSR: ",
187
+ typeof c.ssr?.ssrCount === "number" ? c.ssr.ssrCount : "-"
188
+ ]
189
+ })
190
+ ]
191
+ })
192
+ ]
193
+ })
194
+ }, c.componentName);
195
+ })
196
+ })
197
+ ]
198
+ }),
199
+ /* @__PURE__ */ jsx("div", {
200
+ class: "border-border border-l"
201
+ }),
202
+ /* @__PURE__ */ jsx("div", {
203
+ class: "flex w-[420px] min-w-[320px] flex-col overflow-hidden",
204
+ children: selectedVm.value ? /* @__PURE__ */ jsxs(Fragment, {
205
+ children: [
206
+ /* @__PURE__ */ jsxs("div", {
207
+ class: "border-border flex items-center justify-between border-b p-4",
208
+ children: [
209
+ /* @__PURE__ */ jsxs("div", {
210
+ class: "min-w-0",
211
+ children: [
212
+ /* @__PURE__ */ jsxs("div", {
213
+ class: "truncate text-base font-semibold",
214
+ children: [
215
+ selectedVm.value.componentName,
216
+ " Hook Details"
217
+ ]
218
+ }),
219
+ /* @__PURE__ */ jsxs("div", {
220
+ class: "text-muted-foreground mt-1 text-xs",
221
+ children: [
222
+ "Total: ",
223
+ formatMs(selectedVm.value.totalTime),
224
+ " • ",
225
+ selectedVm.value.calls,
226
+ " calls"
227
+ ]
228
+ })
229
+ ]
230
+ }),
231
+ /* @__PURE__ */ jsx("button", {
232
+ "aria-label": "close",
233
+ onClick$: clearSelect,
234
+ class: "text-muted-foreground hover:text-foreground rounded p-2 transition-colors",
235
+ children: "✕"
236
+ })
237
+ ]
238
+ }),
239
+ /* @__PURE__ */ jsx("div", {
240
+ class: "min-h-0 flex-1 overflow-y-auto p-4",
241
+ children: /* @__PURE__ */ jsxs("div", {
242
+ class: "border-border bg-card-item-bg rounded-lg border",
243
+ children: [
244
+ /* @__PURE__ */ jsxs("div", {
245
+ class: "border-border grid grid-cols-3 border-b px-3 py-2 text-xs font-medium",
246
+ children: [
247
+ /* @__PURE__ */ jsx("div", {
248
+ class: "text-muted-foreground",
249
+ children: "HOOK NAME"
250
+ }),
251
+ /* @__PURE__ */ jsx("div", {
252
+ class: "text-muted-foreground text-right",
253
+ children: "TIME"
254
+ }),
255
+ /* @__PURE__ */ jsx("div", {
256
+ class: "text-muted-foreground text-right",
257
+ children: "CALLS"
258
+ })
259
+ ]
260
+ }),
261
+ /* @__PURE__ */ jsxs("div", {
262
+ class: "divide-border divide-y",
263
+ children: [
264
+ computeEventRows(selectedVm.value.csrItems).map((row) => /* @__PURE__ */ jsxs("div", {
265
+ class: "grid grid-cols-3 px-3 py-2 text-sm",
266
+ children: [
267
+ /* @__PURE__ */ jsx("div", {
268
+ class: "truncate",
269
+ children: row.eventName
270
+ }),
271
+ /* @__PURE__ */ jsx("div", {
272
+ class: "text-right",
273
+ children: formatMs(row.time)
274
+ }),
275
+ /* @__PURE__ */ jsx("div", {
276
+ class: "text-right",
277
+ children: row.calls
278
+ })
279
+ ]
280
+ }, row.eventName)),
281
+ !selectedVm.value.csrItems.length && /* @__PURE__ */ jsx("div", {
282
+ class: "text-muted-foreground px-3 py-4 text-center text-sm",
283
+ children: "No CSR records for this component."
284
+ })
285
+ ]
286
+ })
287
+ ]
288
+ })
289
+ })
290
+ ]
291
+ }) : /* @__PURE__ */ jsx("div", {
292
+ class: "flex h-full items-center justify-center p-8",
293
+ children: /* @__PURE__ */ jsx("div", {
294
+ class: "text-muted-foreground text-center text-sm",
295
+ children: "Select a component to view hook details."
296
+ })
297
+ })
298
+ })
299
+ ]
300
+ })
301
+ ]
302
+ })
303
+ });
304
+ });
305
+ export {
306
+ Performance
307
+ };
@@ -0,0 +1,101 @@
1
+ import { groupCsrBySsr, parseComponentAndEventName } from "./transformPerformanceData.qwik.mjs";
2
+ function getCallsFromCsr(item) {
3
+ return typeof item.renderCount === "number" ? item.renderCount : 1;
4
+ }
5
+ function computeEventRows(csrItems) {
6
+ const byEvent = /* @__PURE__ */ new Map();
7
+ for (const item of csrItems) {
8
+ const eventName = item.eventName || "render";
9
+ const prev = byEvent.get(eventName) || {
10
+ time: 0,
11
+ calls: 0
12
+ };
13
+ prev.time += item.duration || 0;
14
+ prev.calls += getCallsFromCsr(item);
15
+ byEvent.set(eventName, prev);
16
+ }
17
+ return [
18
+ ...byEvent.entries()
19
+ ].map(([eventName, v]) => ({
20
+ eventName,
21
+ time: v.time,
22
+ calls: v.calls
23
+ })).sort((a, b) => b.time - a.time);
24
+ }
25
+ function computeComponentVmFromCsr(componentName, csrItems, ssr) {
26
+ let totalTime = 0;
27
+ let calls = 0;
28
+ for (const item of csrItems) {
29
+ totalTime += item.duration || 0;
30
+ calls += getCallsFromCsr(item);
31
+ }
32
+ const avgTime = calls > 0 ? totalTime / calls : 0;
33
+ return {
34
+ componentName,
35
+ totalTime,
36
+ calls,
37
+ avgTime,
38
+ ssr,
39
+ csrItems
40
+ };
41
+ }
42
+ function computePerfViewModel(perf) {
43
+ const safe = perf || {
44
+ ssr: [],
45
+ csr: []
46
+ };
47
+ const components = [];
48
+ if (safe.ssr?.length) {
49
+ const grouped = groupCsrBySsr(safe);
50
+ for (const ssrItem of safe.ssr) {
51
+ const componentName = parseComponentAndEventName(ssrItem.component).componentName;
52
+ const csrItems = grouped.get(ssrItem) || [];
53
+ components.push(computeComponentVmFromCsr(componentName, csrItems, ssrItem));
54
+ }
55
+ } else if (safe.csr?.length) {
56
+ const byName = /* @__PURE__ */ new Map();
57
+ for (const csrItem of safe.csr) {
58
+ const parsed = parseComponentAndEventName(csrItem.component);
59
+ const list = byName.get(parsed.componentName) || [];
60
+ list.push({
61
+ ...csrItem,
62
+ ...parsed
63
+ });
64
+ byName.set(parsed.componentName, list);
65
+ }
66
+ for (const [componentName, csrItems] of byName.entries()) {
67
+ components.push(computeComponentVmFromCsr(componentName, csrItems));
68
+ }
69
+ }
70
+ components.sort((a, b) => b.totalTime - a.totalTime);
71
+ let totalRenderTime = 0;
72
+ let totalCalls = 0;
73
+ for (const c of components) {
74
+ totalRenderTime += c.totalTime;
75
+ totalCalls += c.calls;
76
+ }
77
+ const avgTime = totalCalls > 0 ? totalRenderTime / totalCalls : 0;
78
+ const slowest = components.filter((c) => c.calls > 0).reduce((acc, cur) => {
79
+ if (!acc) return cur;
80
+ return cur.avgTime > acc.avgTime ? cur : acc;
81
+ }, void 0);
82
+ const overview = {
83
+ totalRenderTime,
84
+ totalCalls,
85
+ avgTime,
86
+ slowestComponent: slowest ? {
87
+ componentName: slowest.componentName,
88
+ avgTime: slowest.avgTime,
89
+ totalTime: slowest.totalTime,
90
+ calls: slowest.calls
91
+ } : void 0
92
+ };
93
+ return {
94
+ overview,
95
+ components
96
+ };
97
+ }
98
+ export {
99
+ computeEventRows,
100
+ computePerfViewModel
101
+ };
@@ -0,0 +1,34 @@
1
+ function parseComponentAndEventName(component) {
2
+ const componentName = (component?.split("_component_")[0] ?? component) || "";
3
+ const rest = component.includes("_component_") ? component.split("_component_")[1] ?? "" : "";
4
+ const parts = rest.split("_").filter(Boolean);
5
+ const eventName = parts.find((p) => /^use[A-Z_]/.test(p) || /^on[A-Z_]/.test(p));
6
+ return {
7
+ componentName,
8
+ eventName
9
+ };
10
+ }
11
+ function groupCsrBySsr(data) {
12
+ const ssrByName = /* @__PURE__ */ new Map();
13
+ for (const ssrItem of data.ssr) {
14
+ ssrByName.set(parseComponentAndEventName(ssrItem.component).componentName, ssrItem);
15
+ }
16
+ const result = /* @__PURE__ */ new WeakMap();
17
+ for (const ssrItem of data.ssr) {
18
+ result.set(ssrItem, []);
19
+ }
20
+ for (const csrItem of data.csr) {
21
+ const parsed = parseComponentAndEventName(csrItem.component);
22
+ const ssrItem = ssrByName.get(parsed.componentName);
23
+ if (!ssrItem) continue;
24
+ result.get(ssrItem).push({
25
+ ...csrItem,
26
+ ...parsed
27
+ });
28
+ }
29
+ return result;
30
+ }
31
+ export {
32
+ groupCsrBySsr,
33
+ parseComponentAndEventName
34
+ };