@ng-prism/plugin-perf 22.2.1 → 22.4.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/README.md +7 -7
- package/dist/bundle/bundle-scanner.d.ts.map +1 -1
- package/dist/bundle/bundle-scanner.js +12 -8
- package/dist/bundle/bundle-section.component.d.ts +4 -4
- package/dist/bundle/bundle-section.component.d.ts.map +1 -1
- package/dist/bundle/bundle-section.component.js +3 -72
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/memory/memory-section.component.d.ts +1 -1
- package/dist/memory/memory-section.component.d.ts.map +1 -1
- package/dist/memory/memory-section.component.js +4 -78
- package/dist/memory/perf-memory.service.d.ts +1 -1
- package/dist/memory/perf-memory.service.d.ts.map +1 -1
- package/dist/memory/perf-memory.service.js +2 -5
- package/dist/perf-panel.component.d.ts +1 -1
- package/dist/perf-panel.component.d.ts.map +1 -1
- package/dist/perf-panel.component.js +7 -92
- package/dist/perf-plugin.browser.d.ts.map +1 -1
- package/dist/perf-plugin.browser.js +3 -3
- package/dist/perf-plugin.d.ts.map +1 -1
- package/dist/perf-plugin.js +6 -6
- package/dist/perf.types.d.ts.map +1 -1
- package/dist/perf.types.js +1 -1
- package/dist/render/perf-render.service.d.ts.map +1 -1
- package/dist/render/perf-render.service.js +1 -1
- package/dist/render/render-section.component.d.ts +1 -1
- package/dist/render/render-section.component.d.ts.map +1 -1
- package/dist/render/render-section.component.js +3 -50
- package/dist/render/sparkline.component.d.ts.map +1 -1
- package/dist/render/sparkline.component.js +7 -44
- package/dist/schematics/ng-add/index.d.ts.map +1 -1
- package/dist/schematics/ng-add/index.js +4 -4
- package/dist/schematics/ng-add/schema.d.ts.map +1 -1
- package/package.json +4 -3
- package/schematics/collection.json +7 -7
- package/schematics/ng-add/schema.json +14 -14
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Render performance profiling plugin for [@ng-prism/core](https://github.com/dyingangel666/ng-prism). Tracks component render and re-render timing via the Performance API.
|
|
4
4
|
|
|
5
|
-
> **Full documentation:** [ng-prism Docs
|
|
5
|
+
> **Full documentation:** [ng-prism Docs: Perf Plugin](https://dyingangel666.github.io/ng-prism/#/plugins/perf)
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -12,10 +12,10 @@ npm install @ng-prism/plugin-perf
|
|
|
12
12
|
|
|
13
13
|
### Peer Dependencies
|
|
14
14
|
|
|
15
|
-
| Package
|
|
16
|
-
|
|
15
|
+
| Package | Version |
|
|
16
|
+
| ---------------- | ---------- |
|
|
17
17
|
| `@ng-prism/core` | `>=21.0.0` |
|
|
18
|
-
| `@angular/core`
|
|
18
|
+
| `@angular/core` | `>=20.0.0` |
|
|
19
19
|
|
|
20
20
|
## Setup
|
|
21
21
|
|
|
@@ -25,7 +25,7 @@ import { defineConfig } from '@ng-prism/core/config';
|
|
|
25
25
|
import { perfPlugin } from '@ng-prism/plugin-perf';
|
|
26
26
|
|
|
27
27
|
export default defineConfig({
|
|
28
|
-
|
|
28
|
+
plugins: [perfPlugin()]
|
|
29
29
|
});
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -33,8 +33,8 @@ export default defineConfig({
|
|
|
33
33
|
|
|
34
34
|
- Adds a **Performance** view tab to the styleguide
|
|
35
35
|
- Profiles component lifecycle:
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
- Initial render time (`prism:render`)
|
|
37
|
+
- Re-render time on input changes (`prism:rerender`)
|
|
38
38
|
- Uses the browser's native Performance API (`performance.mark` / `performance.measure`)
|
|
39
39
|
- Displays timing metrics per variant
|
|
40
40
|
- Memory usage tracking
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle-scanner.d.ts","sourceRoot":"","sources":["../../src/bundle/bundle-scanner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"bundle-scanner.d.ts","sourceRoot":"","sources":["../../src/bundle/bundle-scanner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,aAAa,CAmB5E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
|
+
import { dirname, extname, resolve } from 'path';
|
|
2
3
|
import { gzipSync } from 'zlib';
|
|
3
|
-
import { dirname, resolve, extname } from 'path';
|
|
4
4
|
import ts from 'typescript';
|
|
5
5
|
export function scanBundle(filePath, maxTreeDepth = 5) {
|
|
6
6
|
const source = readFileSync(filePath, 'utf-8');
|
|
@@ -21,9 +21,7 @@ export function scanBundle(filePath, maxTreeDepth = 5) {
|
|
|
21
21
|
function extractImports(sourceFile) {
|
|
22
22
|
const imports = [];
|
|
23
23
|
ts.forEachChild(sourceFile, (node) => {
|
|
24
|
-
if (ts.isImportDeclaration(node) &&
|
|
25
|
-
node.moduleSpecifier &&
|
|
26
|
-
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
24
|
+
if (ts.isImportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
27
25
|
imports.push(node.moduleSpecifier.text);
|
|
28
26
|
}
|
|
29
27
|
});
|
|
@@ -49,7 +47,7 @@ function computeTreeDepth(filePath, imports, maxDepth, visited = new Set(), curr
|
|
|
49
47
|
deepest = Math.max(deepest, childDepth);
|
|
50
48
|
}
|
|
51
49
|
catch {
|
|
52
|
-
// File not readable
|
|
50
|
+
// File not readable, treat as leaf
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
53
|
return deepest;
|
|
@@ -64,7 +62,9 @@ function resolveImport(dir, importPath) {
|
|
|
64
62
|
readFileSync(withoutExt + ext);
|
|
65
63
|
return withoutExt + ext;
|
|
66
64
|
}
|
|
67
|
-
catch {
|
|
65
|
+
catch {
|
|
66
|
+
/* noop */
|
|
67
|
+
}
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
for (const ext of extensions) {
|
|
@@ -72,14 +72,18 @@ function resolveImport(dir, importPath) {
|
|
|
72
72
|
readFileSync(base + ext);
|
|
73
73
|
return base + ext;
|
|
74
74
|
}
|
|
75
|
-
catch {
|
|
75
|
+
catch {
|
|
76
|
+
/* noop */
|
|
77
|
+
}
|
|
76
78
|
}
|
|
77
79
|
for (const ext of extensions) {
|
|
78
80
|
try {
|
|
79
81
|
readFileSync(resolve(base, 'index' + ext));
|
|
80
82
|
return resolve(base, 'index' + ext);
|
|
81
83
|
}
|
|
82
|
-
catch {
|
|
84
|
+
catch {
|
|
85
|
+
/* noop */
|
|
86
|
+
}
|
|
83
87
|
}
|
|
84
88
|
return null;
|
|
85
89
|
}
|
|
@@ -7,10 +7,10 @@ export declare class BundleSectionComponent {
|
|
|
7
7
|
readonly gzipPercent: import("@angular/core").Signal<number>;
|
|
8
8
|
readonly sourceBarPercent: import("@angular/core").Signal<number>;
|
|
9
9
|
readonly gzipBarPercent: import("@angular/core").Signal<number>;
|
|
10
|
-
readonly sizeStatus: import("@angular/core").Signal<"
|
|
11
|
-
readonly sizeStatusText: import("@angular/core").Signal<"
|
|
12
|
-
readonly gzipStatus: import("@angular/core").Signal<"
|
|
13
|
-
readonly gzipStatusText: import("@angular/core").Signal<"
|
|
10
|
+
readonly sizeStatus: import("@angular/core").Signal<"" | "crit" | "warn" | "good">;
|
|
11
|
+
readonly sizeStatusText: import("@angular/core").Signal<"" | "crit" | "warn" | "good">;
|
|
12
|
+
readonly gzipStatus: import("@angular/core").Signal<"" | "crit" | "warn" | "good">;
|
|
13
|
+
readonly gzipStatusText: import("@angular/core").Signal<"" | "crit" | "warn" | "good">;
|
|
14
14
|
readonly visibleImports: import("@angular/core").Signal<string[]>;
|
|
15
15
|
readonly hiddenImportCount: import("@angular/core").Signal<number>;
|
|
16
16
|
formatBytes(bytes: number): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle-section.component.d.ts","sourceRoot":"","sources":["../../src/bundle/bundle-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;;AAEtD,
|
|
1
|
+
{"version":3,"file":"bundle-section.component.d.ts","sourceRoot":"","sources":["../../src/bundle/bundle-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;;AAEtD,qBAOa,sBAAsB;IAC/B,QAAQ,CAAC,OAAO,4DAAqC;IACrD,QAAQ,CAAC,MAAM,8CAAa;IAC5B,QAAQ,CAAC,MAAM,8CAAa;IAE5B,QAAQ,CAAC,WAAW,yCAKjB;IAEH,QAAQ,CAAC,gBAAgB,yCAOtB;IAEH,QAAQ,CAAC,cAAc,yCAOpB;IAEH,QAAQ,CAAC,UAAU,gEAShB;IAEH,QAAQ,CAAC,cAAc,gEAOpB;IAEH,QAAQ,CAAC,UAAU,gEAShB;IAEH,QAAQ,CAAC,cAAc,gEAOpB;IAEH,QAAQ,CAAC,cAAc,2CAIpB;IAEH,QAAQ,CAAC,iBAAiB,yCAKvB;IAEH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIlC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAM/B,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;yCA7FrB,sBAAsB;2CAAtB,sBAAsB;CAiGlC"}
|
|
@@ -262,79 +262,10 @@ export class BundleSectionComponent {
|
|
|
262
262
|
} if (rf & 2) {
|
|
263
263
|
let tmp_0_0;
|
|
264
264
|
i0.ɵɵconditional((tmp_0_0 = ctx.metrics()) ? 0 : 1, tmp_0_0);
|
|
265
|
-
} }, styles: [".perf-body[_ngcontent-%COMP%] {\n
|
|
265
|
+
} }, styles: [".perf-body[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-body--4col[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n}\n\n.perf-card[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--%NS%prism-bg-surface);\n border: 1px solid var(--%NS%prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block[_ngcontent-%COMP%] {\n display: block;\n}\n\n.perf-card-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--%NS%prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-status[_ngcontent-%COMP%] {\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n border-radius: 3px;\n}\n\n.perf-card-status.good[_ngcontent-%COMP%] {\n color: var(--%NS%prism-success);\n background: color-mix(in srgb, var(--%NS%prism-success) 15%, transparent);\n}\n\n.perf-card-status.warn[_ngcontent-%COMP%] {\n color: var(--%NS%prism-warn);\n background: color-mix(in srgb, var(--%NS%prism-warn) 15%, transparent);\n}\n\n.perf-card-status.crit[_ngcontent-%COMP%] {\n color: var(--%NS%prism-danger);\n background: color-mix(in srgb, var(--%NS%prism-danger) 15%, transparent);\n}\n\n.perf-card-val[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--%NS%prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-card-sub[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-detail[_ngcontent-%COMP%] {\n padding: 0 24px 16px;\n}\n\n.perf-detail--last[_ngcontent-%COMP%] {\n padding-bottom: 20px;\n}\n\n.perf-bars[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 80px 1fr auto;\n gap: 10px;\n align-items: center;\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n}\n\n.perf-bar-label[_ngcontent-%COMP%] {\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-bar-track[_ngcontent-%COMP%] {\n height: 8px;\n overflow: hidden;\n background: var(--%NS%prism-input-bg);\n border-radius: 4px;\n}\n\n.perf-bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n background: linear-gradient(90deg, var(--%NS%prism-primary-from), var(--%NS%prism-primary-to));\n border-radius: 4px;\n}\n\n.perf-bar-val[_ngcontent-%COMP%] {\n color: var(--%NS%prism-primary);\n}\n\n.perf-thresholds[_ngcontent-%COMP%] {\n margin-top: 10px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-thresholds--warn[_ngcontent-%COMP%] {\n color: var(--%NS%prism-warn);\n}\n\n.perf-thresholds--crit[_ngcontent-%COMP%] {\n color: var(--%NS%prism-danger);\n}\n\n.perf-chips[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 10px;\n}\n\n.perf-chip[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-2);\n background: var(--%NS%prism-input-bg);\n border: 1px solid var(--%NS%prism-border);\n border-radius: 5px;\n}\n\n.perf-chip.angular[_ngcontent-%COMP%] {\n color: var(--%NS%prism-primary);\n background: color-mix(in srgb, var(--%NS%prism-primary) 10%, transparent);\n border-color: color-mix(in srgb, var(--%NS%prism-primary) 25%, transparent);\n}\n\n.perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--%NS%prism-text-ghost);\n}\n\n.perf-empty-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--%NS%prism-text-ghost);\n opacity: 0.6;\n}"] });
|
|
266
266
|
}
|
|
267
267
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BundleSectionComponent, [{
|
|
268
268
|
type: Component,
|
|
269
|
-
args: [{ selector: 'perf-bundle-section', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template:
|
|
270
|
-
@if (metrics(); as m) {
|
|
271
|
-
<div class="perf-body perf-body--4col">
|
|
272
|
-
<div class="perf-card">
|
|
273
|
-
<div class="perf-card-head">
|
|
274
|
-
<span class="perf-card-name">Source Size</span>
|
|
275
|
-
<span class="perf-card-status" [class]="sizeStatus()">{{ sizeStatusText() }}</span>
|
|
276
|
-
</div>
|
|
277
|
-
<div class="perf-card-val">{{ formatKb(m.sourceSize) }}<span>kb</span></div>
|
|
278
|
-
<div class="perf-card-sub">{{ formatBytes(m.sourceSize) }} bytes</div>
|
|
279
|
-
</div>
|
|
280
|
-
<div class="perf-card">
|
|
281
|
-
<div class="perf-card-head">
|
|
282
|
-
<span class="perf-card-name">Gzip Estimate</span>
|
|
283
|
-
<span class="perf-card-status" [class]="gzipStatus()">{{ gzipStatusText() }}</span>
|
|
284
|
-
</div>
|
|
285
|
-
<div class="perf-card-val">{{ formatKb(m.gzipEstimate) }}<span>kb</span></div>
|
|
286
|
-
<div class="perf-card-sub">~{{ gzipPercent() }}% of source</div>
|
|
287
|
-
</div>
|
|
288
|
-
<div class="perf-card">
|
|
289
|
-
<div class="perf-card-head">
|
|
290
|
-
<span class="perf-card-name">Direct Imports</span>
|
|
291
|
-
</div>
|
|
292
|
-
<div class="perf-card-val">{{ m.directImports }}</div>
|
|
293
|
-
<div class="perf-card-sub">top-level only</div>
|
|
294
|
-
</div>
|
|
295
|
-
<div class="perf-card">
|
|
296
|
-
<div class="perf-card-head">
|
|
297
|
-
<span class="perf-card-name">Tree Depth</span>
|
|
298
|
-
</div>
|
|
299
|
-
<div class="perf-card-val">{{ m.treeDepth }}<span>/ 10</span></div>
|
|
300
|
-
<div class="perf-card-sub">import levels</div>
|
|
301
|
-
</div>
|
|
302
|
-
</div>
|
|
303
|
-
|
|
304
|
-
<div class="perf-detail">
|
|
305
|
-
<div class="perf-card perf-card--block">
|
|
306
|
-
<div class="perf-card-head"><span class="perf-card-name">Size Breakdown</span></div>
|
|
307
|
-
<div class="perf-bars">
|
|
308
|
-
<span class="perf-bar-label">source</span>
|
|
309
|
-
<div class="perf-bar-track"><div class="perf-bar-fill" [style.width.%]="sourceBarPercent()"></div></div>
|
|
310
|
-
<span class="perf-bar-val">{{ formatKb(m.sourceSize) }} KB</span>
|
|
311
|
-
<span class="perf-bar-label">gzip est.</span>
|
|
312
|
-
<div class="perf-bar-track"><div class="perf-bar-fill" [style.width.%]="gzipBarPercent()"></div></div>
|
|
313
|
-
<span class="perf-bar-val">{{ formatKb(m.gzipEstimate) }} KB</span>
|
|
314
|
-
</div>
|
|
315
|
-
<div class="perf-thresholds">Thresholds: <span class="perf-thresholds--warn">warn ≥ {{ warnKb() }} KB</span> · <span class="perf-thresholds--crit">crit ≥ {{ critKb() }} KB</span></div>
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
|
|
319
|
-
<div class="perf-detail perf-detail--last">
|
|
320
|
-
<div class="perf-card perf-card--block">
|
|
321
|
-
<div class="perf-card-head"><span class="perf-card-name">Direct Imports ({{ m.directImports }})</span></div>
|
|
322
|
-
<div class="perf-chips">
|
|
323
|
-
@for (imp of visibleImports(); track imp) {
|
|
324
|
-
<span class="perf-chip" [class]="chipClass(imp)">{{ imp }}</span>
|
|
325
|
-
}
|
|
326
|
-
@if (hiddenImportCount() > 0) {
|
|
327
|
-
<span class="perf-chip">+{{ hiddenImportCount() }} more</span>
|
|
328
|
-
}
|
|
329
|
-
</div>
|
|
330
|
-
</div>
|
|
331
|
-
</div>
|
|
332
|
-
} @else {
|
|
333
|
-
<div class="perf-empty">
|
|
334
|
-
<div class="perf-empty-text">No bundle data available</div>
|
|
335
|
-
<div class="perf-empty-hint">Bundle metrics are collected at build time</div>
|
|
336
|
-
</div>
|
|
337
|
-
}
|
|
338
|
-
`, styles: ["\n .perf-body {\n padding: 20px 24px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n }\n .perf-body--4col { grid-template-columns: repeat(4, 1fr); }\n\n .perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n }\n .perf-card--block { display: block; }\n .perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .perf-card-name {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n }\n .perf-card-status {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 3px;\n font-weight: 700;\n letter-spacing: 0.04em;\n }\n .perf-card-status.good {\n background: color-mix(in srgb, var(--prism-success) 15%, transparent);\n color: var(--prism-success);\n }\n .perf-card-status.warn {\n background: color-mix(in srgb, var(--prism-warn) 15%, transparent);\n color: var(--prism-warn);\n }\n .perf-card-status.crit {\n background: color-mix(in srgb, var(--prism-danger) 15%, transparent);\n color: var(--prism-danger);\n }\n .perf-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n display: flex;\n align-items: baseline;\n gap: 4px;\n }\n .perf-card-val span {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .perf-card-sub {\n font-size: 11px;\n color: var(--prism-text-muted);\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-detail { padding: 0 24px 16px; }\n .perf-detail--last { padding-bottom: 20px; }\n\n .perf-bars {\n display: grid;\n grid-template-columns: 80px 1fr auto;\n gap: 10px;\n align-items: center;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n margin-top: 8px;\n }\n .perf-bar-label { color: var(--prism-text-muted); }\n .perf-bar-track {\n height: 8px;\n background: var(--prism-input-bg);\n border-radius: 4px;\n overflow: hidden;\n }\n .perf-bar-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--prism-primary-from), var(--prism-primary-to));\n border-radius: 4px;\n }\n .perf-bar-val { color: var(--prism-primary); }\n\n .perf-thresholds {\n margin-top: 10px;\n font-size: 11px;\n color: var(--prism-text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n .perf-thresholds--warn { color: var(--prism-warn); }\n .perf-thresholds--crit { color: var(--prism-danger); }\n\n .perf-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 10px;\n }\n .perf-chip {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n padding: 4px 10px;\n background: var(--prism-input-bg);\n color: var(--prism-text-2);\n border: 1px solid var(--prism-border);\n border-radius: 5px;\n }\n .perf-chip.angular {\n background: color-mix(in srgb, var(--prism-primary) 10%, transparent);\n color: var(--prism-primary);\n border-color: color-mix(in srgb, var(--prism-primary) 25%, transparent);\n }\n\n .perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .perf-empty-text { font-size: 12px; color: var(--prism-text-ghost); }\n .perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost); opacity: 0.6; }\n "] }]
|
|
269
|
+
args: [{ selector: 'perf-bundle-section', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (metrics(); as m) {\n <div class=\"perf-body perf-body--4col\">\n <div class=\"perf-card\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">Source Size</span>\n <span\n class=\"perf-card-status\"\n [class]=\"sizeStatus()\"\n >{{ sizeStatusText() }}</span\n >\n </div>\n <div class=\"perf-card-val\">{{ formatKb(m.sourceSize) }}<span>kb</span></div>\n <div class=\"perf-card-sub\">{{ formatBytes(m.sourceSize) }} bytes</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">Gzip Estimate</span>\n <span\n class=\"perf-card-status\"\n [class]=\"gzipStatus()\"\n >{{ gzipStatusText() }}</span\n >\n </div>\n <div class=\"perf-card-val\">{{ formatKb(m.gzipEstimate) }}<span>kb</span></div>\n <div class=\"perf-card-sub\">~{{ gzipPercent() }}% of source</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">Direct Imports</span>\n </div>\n <div class=\"perf-card-val\">{{ m.directImports }}</div>\n <div class=\"perf-card-sub\">top-level only</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">Tree Depth</span>\n </div>\n <div class=\"perf-card-val\">{{ m.treeDepth }}<span>/ 10</span></div>\n <div class=\"perf-card-sub\">import levels</div>\n </div>\n </div>\n\n <div class=\"perf-detail\">\n <div class=\"perf-card perf-card--block\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Size Breakdown</span></div>\n <div class=\"perf-bars\">\n <span class=\"perf-bar-label\">source</span>\n <div class=\"perf-bar-track\"\n ><div\n class=\"perf-bar-fill\"\n [style.width.%]=\"sourceBarPercent()\"></div\n ></div>\n <span class=\"perf-bar-val\">{{ formatKb(m.sourceSize) }} KB</span>\n <span class=\"perf-bar-label\">gzip est.</span>\n <div class=\"perf-bar-track\"\n ><div\n class=\"perf-bar-fill\"\n [style.width.%]=\"gzipBarPercent()\"></div\n ></div>\n <span class=\"perf-bar-val\">{{ formatKb(m.gzipEstimate) }} KB</span>\n </div>\n <div class=\"perf-thresholds\"\n >Thresholds: <span class=\"perf-thresholds--warn\">warn ≥ {{ warnKb() }} KB</span> ·\n <span class=\"perf-thresholds--crit\">crit ≥ {{ critKb() }} KB</span></div\n >\n </div>\n </div>\n\n <div class=\"perf-detail perf-detail--last\">\n <div class=\"perf-card perf-card--block\">\n <div class=\"perf-card-head\"\n ><span class=\"perf-card-name\">Direct Imports ({{ m.directImports }})</span></div\n >\n <div class=\"perf-chips\">\n @for (imp of visibleImports(); track imp) {\n <span\n class=\"perf-chip\"\n [class]=\"chipClass(imp)\"\n >{{ imp }}</span\n >\n }\n @if (hiddenImportCount() > 0) {\n <span class=\"perf-chip\">+{{ hiddenImportCount() }} more</span>\n }\n </div>\n </div>\n </div>\n} @else {\n <div class=\"perf-empty\">\n <div class=\"perf-empty-text\">No bundle data available</div>\n <div class=\"perf-empty-hint\">Bundle metrics are collected at build time</div>\n </div>\n}\n", styles: [".perf-body {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-body--4col {\n grid-template-columns: repeat(4, 1fr);\n}\n\n.perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block {\n display: block;\n}\n\n.perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name {\n font-size: 11px;\n font-weight: 700;\n color: var(--prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-status {\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n border-radius: 3px;\n}\n\n.perf-card-status.good {\n color: var(--prism-success);\n background: color-mix(in srgb, var(--prism-success) 15%, transparent);\n}\n\n.perf-card-status.warn {\n color: var(--prism-warn);\n background: color-mix(in srgb, var(--prism-warn) 15%, transparent);\n}\n\n.perf-card-status.crit {\n color: var(--prism-danger);\n background: color-mix(in srgb, var(--prism-danger) 15%, transparent);\n}\n\n.perf-card-val {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val span {\n font-size: 13px;\n font-weight: 500;\n color: var(--prism-text-muted);\n}\n\n.perf-card-sub {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.perf-detail {\n padding: 0 24px 16px;\n}\n\n.perf-detail--last {\n padding-bottom: 20px;\n}\n\n.perf-bars {\n display: grid;\n grid-template-columns: 80px 1fr auto;\n gap: 10px;\n align-items: center;\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n}\n\n.perf-bar-label {\n color: var(--prism-text-muted);\n}\n\n.perf-bar-track {\n height: 8px;\n overflow: hidden;\n background: var(--prism-input-bg);\n border-radius: 4px;\n}\n\n.perf-bar-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--prism-primary-from), var(--prism-primary-to));\n border-radius: 4px;\n}\n\n.perf-bar-val {\n color: var(--prism-primary);\n}\n\n.perf-thresholds {\n margin-top: 10px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.perf-thresholds--warn {\n color: var(--prism-warn);\n}\n\n.perf-thresholds--crit {\n color: var(--prism-danger);\n}\n\n.perf-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 10px;\n}\n\n.perf-chip {\n padding: 4px 10px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-2);\n background: var(--prism-input-bg);\n border: 1px solid var(--prism-border);\n border-radius: 5px;\n}\n\n.perf-chip.angular {\n color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 10%, transparent);\n border-color: color-mix(in srgb, var(--prism-primary) 25%, transparent);\n}\n\n.perf-empty {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text {\n font-size: 12px;\n color: var(--prism-text-ghost);\n}\n\n.perf-empty-hint {\n font-size: 11px;\n color: var(--prism-text-ghost);\n opacity: 0.6;\n}\n"] }]
|
|
339
270
|
}], null, { metrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "metrics", required: false }] }], warnKb: [{ type: i0.Input, args: [{ isSignal: true, alias: "warnKb", required: false }] }], critKb: [{ type: i0.Input, args: [{ isSignal: true, alias: "critKb", required: false }] }] }); })();
|
|
340
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(BundleSectionComponent, { className: "BundleSectionComponent", filePath: "bundle/bundle-section.component.ts", lineNumber:
|
|
271
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(BundleSectionComponent, { className: "BundleSectionComponent", filePath: "bundle/bundle-section.component.ts", lineNumber: 11 }); })();
|
package/dist/index.browser.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { perfPlugin } from './perf-plugin.browser.js';
|
|
2
2
|
export { PerfPanelComponent } from './perf-panel.component.js';
|
|
3
3
|
export { PERF_PLUGIN_CONFIG } from './perf-config.token.js';
|
|
4
|
-
export type { PerfPluginOptions, PerfThresholds
|
|
4
|
+
export type { BundleMetrics, PerfPluginOptions, PerfThresholds } from './perf.types.js';
|
|
5
5
|
//# sourceMappingURL=index.browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { perfPlugin } from './perf-plugin.js';
|
|
2
2
|
export { PerfPanelComponent } from './perf-panel.component.js';
|
|
3
3
|
export { PERF_PLUGIN_CONFIG } from './perf-config.token.js';
|
|
4
|
-
export type { PerfPluginOptions, PerfThresholds
|
|
4
|
+
export type { BundleMetrics, PerfPluginOptions, PerfThresholds } from './perf.types.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -6,7 +6,7 @@ export declare class MemorySectionComponent {
|
|
|
6
6
|
readonly deltaText: import("@angular/core").Signal<string>;
|
|
7
7
|
readonly residualText: import("@angular/core").Signal<string>;
|
|
8
8
|
readonly afterCreateColor: import("@angular/core").Signal<"" | "var(--prism-warn)">;
|
|
9
|
-
readonly destroyColor: import("@angular/core").Signal<"" | "var(--prism-
|
|
9
|
+
readonly destroyColor: import("@angular/core").Signal<"" | "var(--prism-text-ghost)" | "var(--prism-success)" | "var(--prism-danger)">;
|
|
10
10
|
barPercent(bytes: number | undefined): number;
|
|
11
11
|
formatMb(bytes: number | null | undefined): string;
|
|
12
12
|
static ɵfac: i0.ɵɵFactoryDeclaration<MemorySectionComponent, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-section.component.d.ts","sourceRoot":"","sources":["../../src/memory/memory-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;;AAElE,
|
|
1
|
+
{"version":3,"file":"memory-section.component.d.ts","sourceRoot":"","sources":["../../src/memory/memory-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;;AAElE,qBAOa,sBAAsB;IAC/B,QAAQ,CAAC,aAAa,yDAAuC;IAE7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAKtB;IAEH,QAAQ,CAAC,SAAS,yCAKf;IAEH,QAAQ,CAAC,YAAY,yCAKlB;IAEH,QAAQ,CAAC,gBAAgB,2DAKtB;IAEH,QAAQ,CAAC,YAAY,kHASlB;IAEH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM;IAK7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;yCA/CzC,sBAAsB;2CAAtB,sBAAsB;CAmDlC"}
|
|
@@ -146,11 +146,7 @@ export class MemorySectionComponent {
|
|
|
146
146
|
...(ngDevMode ? [{ debugName: "memoryService" }] : /* istanbul ignore next */ []));
|
|
147
147
|
maxBytes = computed(() => {
|
|
148
148
|
const svc = this.memoryService();
|
|
149
|
-
const vals = [
|
|
150
|
-
svc.beforeCreate()?.bytes ?? 0,
|
|
151
|
-
svc.afterCreate()?.bytes ?? 0,
|
|
152
|
-
svc.afterDestroy()?.bytes ?? 0,
|
|
153
|
-
];
|
|
149
|
+
const vals = [svc.beforeCreate()?.bytes ?? 0, svc.afterCreate()?.bytes ?? 0, svc.afterDestroy()?.bytes ?? 0];
|
|
154
150
|
return Math.max(...vals);
|
|
155
151
|
}, /* @ts-ignore */
|
|
156
152
|
...(ngDevMode ? [{ debugName: "maxBytes" }] : /* istanbul ignore next */ []));
|
|
@@ -203,80 +199,10 @@ export class MemorySectionComponent {
|
|
|
203
199
|
} if (rf & 2) {
|
|
204
200
|
let tmp_0_0;
|
|
205
201
|
i0.ɵɵconditional((tmp_0_0 = ctx.memoryService()) ? 0 : -1, tmp_0_0);
|
|
206
|
-
} }, styles: [".perf-body[_ngcontent-%COMP%] {\n
|
|
202
|
+
} }, styles: [".perf-body[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-card[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--%NS%prism-bg-surface);\n border: 1px solid var(--%NS%prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block[_ngcontent-%COMP%] {\n display: block;\n}\n\n.perf-card-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--%NS%prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-status[_ngcontent-%COMP%] {\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n border-radius: 3px;\n}\n\n.perf-card-status.warn[_ngcontent-%COMP%] {\n color: var(--%NS%prism-warn);\n background: color-mix(in srgb, var(--%NS%prism-warn) 15%, transparent);\n}\n\n.perf-card-val[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--%NS%prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-card-sub[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-detail[_ngcontent-%COMP%] {\n padding: 0 24px 16px;\n}\n\n.perf-detail--last[_ngcontent-%COMP%] {\n padding-bottom: 20px;\n}\n\n.perf-bars[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 1fr auto;\n gap: 10px;\n align-items: center;\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n}\n\n.perf-bar-label[_ngcontent-%COMP%] {\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-bar-track[_ngcontent-%COMP%] {\n height: 8px;\n overflow: hidden;\n background: var(--%NS%prism-input-bg);\n border-radius: 4px;\n}\n\n.perf-bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n background: linear-gradient(90deg, var(--%NS%prism-primary-from), var(--%NS%prism-primary-to));\n border-radius: 4px;\n}\n\n.perf-bar-fill--warn[_ngcontent-%COMP%] {\n background: linear-gradient(90deg, var(--%NS%prism-warn), var(--%NS%prism-warn));\n opacity: 0.8;\n}\n\n.perf-bar-val[_ngcontent-%COMP%] {\n color: var(--%NS%prism-primary);\n}\n\n.perf-bar-val--warn[_ngcontent-%COMP%] {\n color: var(--%NS%prism-warn);\n}\n\n.perf-leak-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n gap: 8px;\n align-items: center;\n padding: 8px 14px;\n margin-top: 8px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 5px;\n}\n\n.perf-leak-badge--ok[_ngcontent-%COMP%] {\n color: var(--%NS%prism-success);\n background: color-mix(in srgb, var(--%NS%prism-success) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--%NS%prism-success) 25%, transparent);\n}\n\n.perf-leak-badge--warn[_ngcontent-%COMP%] {\n color: var(--%NS%prism-warn);\n background: color-mix(in srgb, var(--%NS%prism-warn) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--%NS%prism-warn) 25%, transparent);\n}\n\n.perf-leak-dot[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n}\n\n.perf-leak-badge--ok[_ngcontent-%COMP%] .perf-leak-dot[_ngcontent-%COMP%] {\n background: var(--%NS%prism-success);\n}\n\n.perf-leak-badge--warn[_ngcontent-%COMP%] .perf-leak-dot[_ngcontent-%COMP%] {\n background: var(--%NS%prism-warn);\n box-shadow: 0 0 6px var(--%NS%prism-warn);\n}\n\n.perf-disclaimer[_ngcontent-%COMP%] {\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--%NS%prism-text-ghost);\n}\n\n.perf-empty-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--%NS%prism-text-ghost);\n opacity: 0.6;\n}"] });
|
|
207
203
|
}
|
|
208
204
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MemorySectionComponent, [{
|
|
209
205
|
type: Component,
|
|
210
|
-
args: [{ selector: 'perf-memory-section', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template:
|
|
211
|
-
@if (memoryService(); as svc) {
|
|
212
|
-
@if (!svc.available()) {
|
|
213
|
-
<div class="perf-empty">
|
|
214
|
-
<div class="perf-empty-text">Memory API not available</div>
|
|
215
|
-
<div class="perf-empty-hint">performance.memory is Chrome-only (non-standard)</div>
|
|
216
|
-
</div>
|
|
217
|
-
} @else if (svc.snapshots().length > 0) {
|
|
218
|
-
<div class="perf-body">
|
|
219
|
-
<div class="perf-card">
|
|
220
|
-
<div class="perf-card-head"><span class="perf-card-name">Before Create</span></div>
|
|
221
|
-
<div class="perf-card-val">{{ formatMb(svc.beforeCreate()?.bytes) }}<span>MB</span></div>
|
|
222
|
-
<div class="perf-card-sub">baseline heap</div>
|
|
223
|
-
</div>
|
|
224
|
-
<div class="perf-card">
|
|
225
|
-
<div class="perf-card-head">
|
|
226
|
-
<span class="perf-card-name">After Create</span>
|
|
227
|
-
@if (svc.delta() !== null && svc.delta()! > 0) {
|
|
228
|
-
<span class="perf-card-status warn">watch</span>
|
|
229
|
-
}
|
|
230
|
-
</div>
|
|
231
|
-
<div class="perf-card-val" [style.color]="afterCreateColor()">{{ formatMb(svc.afterCreate()?.bytes) }}<span>MB</span></div>
|
|
232
|
-
<div class="perf-card-sub">{{ deltaText() }}</div>
|
|
233
|
-
</div>
|
|
234
|
-
<div class="perf-card">
|
|
235
|
-
<div class="perf-card-head"><span class="perf-card-name">After Destroy</span></div>
|
|
236
|
-
<div class="perf-card-val" [style.color]="destroyColor()">{{ formatMb(svc.afterDestroy()?.bytes) }}<span>MB</span></div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
|
|
240
|
-
@if (svc.beforeCreate() && svc.afterCreate()) {
|
|
241
|
-
<div class="perf-detail">
|
|
242
|
-
<div class="perf-card perf-card--block">
|
|
243
|
-
<div class="perf-card-head"><span class="perf-card-name">Heap Comparison</span></div>
|
|
244
|
-
<div class="perf-bars">
|
|
245
|
-
<span class="perf-bar-label">before</span>
|
|
246
|
-
<div class="perf-bar-track"><div class="perf-bar-fill" [style.width.%]="barPercent(svc.beforeCreate()?.bytes)"></div></div>
|
|
247
|
-
<span class="perf-bar-val">{{ formatMb(svc.beforeCreate()?.bytes) }} MB</span>
|
|
248
|
-
<span class="perf-bar-label">after create</span>
|
|
249
|
-
<div class="perf-bar-track"><div class="perf-bar-fill perf-bar-fill--warn" [style.width.%]="barPercent(svc.afterCreate()?.bytes)"></div></div>
|
|
250
|
-
<span class="perf-bar-val perf-bar-val--warn">{{ formatMb(svc.afterCreate()?.bytes) }} MB</span>
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
<div class="perf-detail perf-detail--last">
|
|
257
|
-
<div class="perf-card perf-card--block">
|
|
258
|
-
<div class="perf-card-head"><span class="perf-card-name">Leak Analysis</span></div>
|
|
259
|
-
@if (svc.leakStatus() === 'ok') {
|
|
260
|
-
<div class="perf-leak-badge perf-leak-badge--ok">
|
|
261
|
-
<span class="perf-leak-dot"></span>
|
|
262
|
-
No significant leak detected
|
|
263
|
-
</div>
|
|
264
|
-
} @else if (svc.leakStatus() === 'warn') {
|
|
265
|
-
<div class="perf-leak-badge perf-leak-badge--warn">
|
|
266
|
-
<span class="perf-leak-dot"></span>
|
|
267
|
-
Possible leak — +{{ formatMb(svc.residual()!) }} MB not reclaimed
|
|
268
|
-
</div>
|
|
269
|
-
}
|
|
270
|
-
<div class="perf-disclaimer">ⓘ performance.memory is Chrome-only (non-standard). Not available in other browsers.</div>
|
|
271
|
-
</div>
|
|
272
|
-
</div>
|
|
273
|
-
} @else {
|
|
274
|
-
<div class="perf-empty">
|
|
275
|
-
<div class="perf-empty-text">No memory snapshots yet</div>
|
|
276
|
-
<div class="perf-empty-hint">Click Snapshot to capture heap data</div>
|
|
277
|
-
</div>
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
`, styles: ["\n .perf-body {\n padding: 20px 24px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n }\n\n .perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n }\n .perf-card--block { display: block; }\n .perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .perf-card-name {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n }\n .perf-card-status {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 3px;\n font-weight: 700;\n letter-spacing: 0.04em;\n }\n .perf-card-status.warn {\n background: color-mix(in srgb, var(--prism-warn) 15%, transparent);\n color: var(--prism-warn);\n }\n .perf-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n display: flex;\n align-items: baseline;\n gap: 4px;\n }\n .perf-card-val span {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .perf-card-sub {\n font-size: 11px;\n color: var(--prism-text-muted);\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-detail { padding: 0 24px 16px; }\n .perf-detail--last { padding-bottom: 20px; }\n\n .perf-bars {\n display: grid;\n grid-template-columns: 100px 1fr auto;\n gap: 10px;\n align-items: center;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n margin-top: 8px;\n }\n .perf-bar-label { color: var(--prism-text-muted); }\n .perf-bar-track {\n height: 8px;\n background: var(--prism-input-bg);\n border-radius: 4px;\n overflow: hidden;\n }\n .perf-bar-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--prism-primary-from), var(--prism-primary-to));\n border-radius: 4px;\n }\n .perf-bar-fill--warn {\n background: linear-gradient(90deg, var(--prism-warn), var(--prism-warn));\n opacity: 0.8;\n }\n .perf-bar-val { color: var(--prism-primary); }\n .perf-bar-val--warn { color: var(--prism-warn); }\n\n .perf-leak-badge {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 500;\n margin-top: 8px;\n }\n .perf-leak-badge--ok {\n background: color-mix(in srgb, var(--prism-success) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--prism-success) 25%, transparent);\n color: var(--prism-success);\n }\n .perf-leak-badge--warn {\n background: color-mix(in srgb, var(--prism-warn) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--prism-warn) 25%, transparent);\n color: var(--prism-warn);\n }\n .perf-leak-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n }\n .perf-leak-badge--ok .perf-leak-dot { background: var(--prism-success); }\n .perf-leak-badge--warn .perf-leak-dot {\n background: var(--prism-warn);\n box-shadow: 0 0 6px var(--prism-warn);\n }\n\n .perf-disclaimer {\n margin-top: 8px;\n font-size: 12px;\n color: var(--prism-text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .perf-empty-text { font-size: 12px; color: var(--prism-text-ghost); }\n .perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost); opacity: 0.6; }\n "] }]
|
|
206
|
+
args: [{ selector: 'perf-memory-section', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (memoryService(); as svc) {\n @if (!svc.available()) {\n <div class=\"perf-empty\">\n <div class=\"perf-empty-text\">Memory API not available</div>\n <div class=\"perf-empty-hint\">performance.memory is Chrome-only (non-standard)</div>\n </div>\n } @else if (svc.snapshots().length > 0) {\n <div class=\"perf-body\">\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Before Create</span></div>\n <div class=\"perf-card-val\">{{ formatMb(svc.beforeCreate()?.bytes) }}<span>MB</span></div>\n <div class=\"perf-card-sub\">baseline heap</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">After Create</span>\n @if (svc.delta() !== null && svc.delta()! > 0) {\n <span class=\"perf-card-status warn\">watch</span>\n }\n </div>\n <div\n class=\"perf-card-val\"\n [style.color]=\"afterCreateColor()\"\n >{{ formatMb(svc.afterCreate()?.bytes) }}<span>MB</span></div\n >\n <div class=\"perf-card-sub\">{{ deltaText() }}</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">After Destroy</span></div>\n <div\n class=\"perf-card-val\"\n [style.color]=\"destroyColor()\"\n >{{ formatMb(svc.afterDestroy()?.bytes) }}<span>MB</span></div\n >\n </div>\n </div>\n\n @if (svc.beforeCreate() && svc.afterCreate()) {\n <div class=\"perf-detail\">\n <div class=\"perf-card perf-card--block\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Heap Comparison</span></div>\n <div class=\"perf-bars\">\n <span class=\"perf-bar-label\">before</span>\n <div class=\"perf-bar-track\"\n ><div\n class=\"perf-bar-fill\"\n [style.width.%]=\"barPercent(svc.beforeCreate()?.bytes)\"></div\n ></div>\n <span class=\"perf-bar-val\">{{ formatMb(svc.beforeCreate()?.bytes) }} MB</span>\n <span class=\"perf-bar-label\">after create</span>\n <div class=\"perf-bar-track\"\n ><div\n class=\"perf-bar-fill perf-bar-fill--warn\"\n [style.width.%]=\"barPercent(svc.afterCreate()?.bytes)\"></div\n ></div>\n <span class=\"perf-bar-val perf-bar-val--warn\">{{ formatMb(svc.afterCreate()?.bytes) }} MB</span>\n </div>\n </div>\n </div>\n }\n\n <div class=\"perf-detail perf-detail--last\">\n <div class=\"perf-card perf-card--block\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Leak Analysis</span></div>\n @if (svc.leakStatus() === 'ok') {\n <div class=\"perf-leak-badge perf-leak-badge--ok\">\n <span class=\"perf-leak-dot\"></span>\n No significant leak detected\n </div>\n } @else if (svc.leakStatus() === 'warn') {\n <div class=\"perf-leak-badge perf-leak-badge--warn\">\n <span class=\"perf-leak-dot\"></span>\n Possible leak — +{{ formatMb(svc.residual()!) }} MB not reclaimed\n </div>\n }\n <div class=\"perf-disclaimer\">ⓘ performance.memory is Chrome-only (non-standard). Not available in other browsers.</div>\n </div>\n </div>\n } @else {\n <div class=\"perf-empty\">\n <div class=\"perf-empty-text\">No memory snapshots yet</div>\n <div class=\"perf-empty-hint\">Click Snapshot to capture heap data</div>\n </div>\n }\n}\n", styles: [".perf-body {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block {\n display: block;\n}\n\n.perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name {\n font-size: 11px;\n font-weight: 700;\n color: var(--prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-status {\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n border-radius: 3px;\n}\n\n.perf-card-status.warn {\n color: var(--prism-warn);\n background: color-mix(in srgb, var(--prism-warn) 15%, transparent);\n}\n\n.perf-card-val {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val span {\n font-size: 13px;\n font-weight: 500;\n color: var(--prism-text-muted);\n}\n\n.perf-card-sub {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.perf-detail {\n padding: 0 24px 16px;\n}\n\n.perf-detail--last {\n padding-bottom: 20px;\n}\n\n.perf-bars {\n display: grid;\n grid-template-columns: 100px 1fr auto;\n gap: 10px;\n align-items: center;\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n}\n\n.perf-bar-label {\n color: var(--prism-text-muted);\n}\n\n.perf-bar-track {\n height: 8px;\n overflow: hidden;\n background: var(--prism-input-bg);\n border-radius: 4px;\n}\n\n.perf-bar-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--prism-primary-from), var(--prism-primary-to));\n border-radius: 4px;\n}\n\n.perf-bar-fill--warn {\n background: linear-gradient(90deg, var(--prism-warn), var(--prism-warn));\n opacity: 0.8;\n}\n\n.perf-bar-val {\n color: var(--prism-primary);\n}\n\n.perf-bar-val--warn {\n color: var(--prism-warn);\n}\n\n.perf-leak-badge {\n display: inline-flex;\n gap: 8px;\n align-items: center;\n padding: 8px 14px;\n margin-top: 8px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 5px;\n}\n\n.perf-leak-badge--ok {\n color: var(--prism-success);\n background: color-mix(in srgb, var(--prism-success) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--prism-success) 25%, transparent);\n}\n\n.perf-leak-badge--warn {\n color: var(--prism-warn);\n background: color-mix(in srgb, var(--prism-warn) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--prism-warn) 25%, transparent);\n}\n\n.perf-leak-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n}\n\n.perf-leak-badge--ok .perf-leak-dot {\n background: var(--prism-success);\n}\n\n.perf-leak-badge--warn .perf-leak-dot {\n background: var(--prism-warn);\n box-shadow: 0 0 6px var(--prism-warn);\n}\n\n.perf-disclaimer {\n margin-top: 8px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 12px;\n color: var(--prism-text-muted);\n}\n\n.perf-empty {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text {\n font-size: 12px;\n color: var(--prism-text-ghost);\n}\n\n.perf-empty-hint {\n font-size: 11px;\n color: var(--prism-text-ghost);\n opacity: 0.6;\n}\n"] }]
|
|
281
207
|
}], null, { memoryService: [{ type: i0.Input, args: [{ isSignal: true, alias: "memoryService", required: true }] }] }); })();
|
|
282
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MemorySectionComponent, { className: "MemorySectionComponent", filePath: "memory/memory-section.component.ts", lineNumber:
|
|
208
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MemorySectionComponent, { className: "MemorySectionComponent", filePath: "memory/memory-section.component.ts", lineNumber: 11 }); })();
|
|
@@ -14,7 +14,7 @@ export declare class PerfMemoryService implements PrismRendererHooks {
|
|
|
14
14
|
readonly afterDestroy: import("@angular/core").Signal<HeapSnapshot | null>;
|
|
15
15
|
readonly delta: import("@angular/core").Signal<number | null>;
|
|
16
16
|
readonly residual: import("@angular/core").Signal<number | null>;
|
|
17
|
-
readonly leakStatus: import("@angular/core").Signal<"
|
|
17
|
+
readonly leakStatus: import("@angular/core").Signal<"warn" | "ok" | "unknown">;
|
|
18
18
|
configure(gcDelayMs: number): void;
|
|
19
19
|
onBeforeCreate(_selector: string): void;
|
|
20
20
|
onAfterCreate(_selector: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-memory.service.d.ts","sourceRoot":"","sources":["../../src/memory/perf-memory.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,YAAY;
|
|
1
|
+
{"version":3,"file":"perf-memory.service.d.ts","sourceRoot":"","sources":["../../src/memory/perf-memory.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACrB;AAID,qBAAa,iBAAkB,YAAW,kBAAkB;IACxD,MAAM,CAAC,WAAW,IAAI,iBAAiB;IAKvC,QAAQ,CAAC,SAAS,yDAA8B;IAChD,QAAQ,CAAC,SAAS,0CAAiF;IAEnG,OAAO,CAAC,OAAO,CAAO;IAEtB,QAAQ,CAAC,YAAY,sDAAsD;IAC3E,QAAQ,CAAC,WAAW,sDAAqD;IACzE,QAAQ,CAAC,YAAY,sDAAsD;IAE3E,QAAQ,CAAC,KAAK,gDAMX;IAEH,QAAQ,CAAC,QAAQ,gDAMd;IAEH,QAAQ,CAAC,UAAU,4DAKhB;IAEH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIlC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIvC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAItC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIvC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,YAAY;CAGvB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { computed, signal } from '@angular/core';
|
|
2
2
|
let instance = null;
|
|
3
3
|
export class PerfMemoryService {
|
|
4
4
|
static getInstance() {
|
|
@@ -56,10 +56,7 @@ export class PerfMemoryService {
|
|
|
56
56
|
if (!this.available())
|
|
57
57
|
return;
|
|
58
58
|
const mem = performance.memory;
|
|
59
|
-
this.snapshots.update((arr) => [
|
|
60
|
-
...arr.filter((s) => s.label !== label),
|
|
61
|
-
{ label, bytes: mem.usedJSHeapSize, timestamp: Date.now() },
|
|
62
|
-
]);
|
|
59
|
+
this.snapshots.update((arr) => [...arr.filter((s) => s.label !== label), { label, bytes: mem.usedJSHeapSize, timestamp: Date.now() }]);
|
|
63
60
|
}
|
|
64
61
|
clear() {
|
|
65
62
|
this.snapshots.set([]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { PerfMemoryService } from './memory/perf-memory.service.js';
|
|
1
2
|
import type { BundleMetrics, PerfThresholds } from './perf.types.js';
|
|
2
3
|
import { PerfRenderService } from './render/perf-render.service.js';
|
|
3
|
-
import { PerfMemoryService } from './memory/perf-memory.service.js';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
type SubTab = 'bundle' | 'render' | 'memory';
|
|
6
6
|
export declare class PerfPanelComponent {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-panel.component.d.ts","sourceRoot":"","sources":["../src/perf-panel.component.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"perf-panel.component.d.ts","sourceRoot":"","sources":["../src/perf-panel.component.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;;AAGpE,KAAK,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7C,qBAQa,kBAAkB;IAC3B,QAAQ,CAAC,eAAe,+CAAwB;IAEhD,QAAQ,CAAC,SAAS,iDAA4B;IAC9C,QAAQ,CAAC,aAAa,oBAAmC;IACzD,QAAQ,CAAC,aAAa,oBAAmC;IAEzD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAsB;IAEzD,sBAAsB,IAAI,IAAI;IAK9B,QAAQ,CAAC,aAAa,uDAQnB;yCAtBM,kBAAkB;2CAAlB,kBAAkB;CAuB9B"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, computed, input, signal
|
|
1
|
+
import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';
|
|
2
|
+
import { BundleSectionComponent } from './bundle/bundle-section.component.js';
|
|
3
|
+
import { MemorySectionComponent } from './memory/memory-section.component.js';
|
|
4
|
+
import { PerfMemoryService } from './memory/perf-memory.service.js';
|
|
2
5
|
import { DEFAULT_THRESHOLDS } from './perf.types.js';
|
|
3
6
|
import { PerfRenderService } from './render/perf-render.service.js';
|
|
4
|
-
import { PerfMemoryService } from './memory/perf-memory.service.js';
|
|
5
|
-
import { BundleSectionComponent } from './bundle/bundle-section.component.js';
|
|
6
7
|
import { RenderSectionComponent } from './render/render-section.component.js';
|
|
7
|
-
import { MemorySectionComponent } from './memory/memory-section.component.js';
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
function PerfPanelComponent_Conditional_9_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
10
10
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
@@ -137,95 +137,10 @@ export class PerfPanelComponent {
|
|
|
137
137
|
i0.ɵɵconditional(ctx.renderService.cdRunCount() > 0 ? 11 : -1);
|
|
138
138
|
i0.ɵɵadvance(2);
|
|
139
139
|
i0.ɵɵconditional((tmp_6_0 = ctx.activeTab()) === "bundle" ? 13 : tmp_6_0 === "render" ? 14 : tmp_6_0 === "memory" ? 15 : -1);
|
|
140
|
-
} }, dependencies: [BundleSectionComponent,
|
|
141
|
-
RenderSectionComponent,
|
|
142
|
-
MemorySectionComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .prism-perf-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .prism-subtabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n padding: 10px 20px 0;\n border-bottom: 1px solid var(--%NS%prism-border);\n background: var(--%NS%prism-bg-elevated);\n position: sticky;\n top: 0;\n z-index: 2;\n }\n\n .prism-st-tab[_ngcontent-%COMP%] {\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n border-radius: 6px 6px 0 0;\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n background: transparent;\n border: none;\n font-family: var(--%NS%font-sans);\n transition: color var(--%NS%dur-fast);\n }\n .prism-st-tab[_ngcontent-%COMP%]:hover { color: var(--%NS%prism-text-2); }\n .prism-st-tab--active[_ngcontent-%COMP%] { color: var(--%NS%prism-text); }\n .prism-st-tab--%NS%active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n bottom: -1px;\n height: 2px;\n background: var(--%NS%prism-primary);\n border-radius: 1px;\n }\n\n .prism-subtabs-actions[_ngcontent-%COMP%] {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .prism-perf-cd-badge[_ngcontent-%COMP%] {\n font-family: var(--%NS%font-mono, 'JetBrains Mono', monospace);\n font-size: 11px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n height: 24px;\n background: color-mix(in srgb, var(--%NS%prism-primary) 12%, transparent);\n color: var(--%NS%prism-primary);\n border: 1px solid color-mix(in srgb, var(--%NS%prism-primary) 25%, transparent);\n border-radius: 5px;\n }\n .prism-tool-btn[_ngcontent-%COMP%] {\n height: 24px;\n padding: 0 9px;\n border-radius: 5px;\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11.5px;\n color: var(--%NS%prism-text-muted);\n transition: all 0.12s;\n font-weight: 500;\n background: none;\n border: none;\n cursor: pointer;\n font-family: var(--%NS%font-sans);\n }\n .prism-tool-btn[_ngcontent-%COMP%]:hover {\n color: var(--%NS%prism-text);\n background: color-mix(in srgb, var(--%NS%prism-primary) 8%, transparent);\n }\n\n .prism-perf-status[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n font-family: var(--%NS%font-mono);\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .prism-perf-status-dot[_ngcontent-%COMP%] {\n display: inline-block;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--%NS%prism-success);\n box-shadow: 0 0 6px var(--%NS%prism-success);\n animation: _ngcontent-%COMP%_prism-perf-pulse 2s ease-in-out infinite;\n }\n @keyframes _ngcontent-%COMP%_prism-perf-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n\n .prism-perf-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n }"] });
|
|
140
|
+
} }, dependencies: [BundleSectionComponent, RenderSectionComponent, MemorySectionComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.prism-perf-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.prism-subtabs[_ngcontent-%COMP%] {\n position: sticky;\n top: 0;\n z-index: 2;\n display: flex;\n gap: 2px;\n padding: 10px 20px 0;\n background: var(--%NS%prism-bg-elevated);\n border-bottom: 1px solid var(--%NS%prism-border);\n}\n\n.prism-st-tab[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n gap: 6px;\n align-items: center;\n padding: 7px 12px;\n font-family: var(--%NS%font-sans);\n font-size: 12px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 6px 6px 0 0;\n transition: color var(--%NS%dur-fast);\n}\n\n.prism-st-tab[_ngcontent-%COMP%]:hover {\n color: var(--%NS%prism-text-2);\n}\n\n.prism-st-tab--active[_ngcontent-%COMP%] {\n color: var(--%NS%prism-text);\n}\n\n.prism-st-tab--%NS%active[_ngcontent-%COMP%]::after {\n position: absolute;\n right: 8px;\n bottom: -1px;\n left: 8px;\n height: 2px;\n content: '';\n background: var(--%NS%prism-primary);\n border-radius: 1px;\n}\n\n.prism-subtabs-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n margin-left: auto;\n}\n\n.prism-perf-cd-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 24px;\n padding: 0 8px;\n font-family: var(--%NS%font-mono, 'JetBrains Mono', monospace);\n font-size: 11px;\n color: var(--%NS%prism-primary);\n background: color-mix(in srgb, var(--%NS%prism-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--%NS%prism-primary) 25%, transparent);\n border-radius: 5px;\n}\n\n.prism-tool-btn[_ngcontent-%COMP%] {\n display: flex;\n gap: 5px;\n align-items: center;\n height: 24px;\n padding: 0 9px;\n font-family: var(--%NS%font-sans);\n font-size: 11.5px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 5px;\n transition: all 0.12s;\n}\n\n.prism-tool-btn[_ngcontent-%COMP%]:hover {\n color: var(--%NS%prism-text);\n background: color-mix(in srgb, var(--%NS%prism-primary) 8%, transparent);\n}\n\n.prism-perf-status[_ngcontent-%COMP%] {\n display: flex;\n gap: 5px;\n align-items: center;\n font-family: var(--%NS%font-mono);\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.prism-perf-status-dot[_ngcontent-%COMP%] {\n display: inline-block;\n width: 5px;\n height: 5px;\n background: var(--%NS%prism-success);\n border-radius: 50%;\n box-shadow: 0 0 6px var(--%NS%prism-success);\n animation: _ngcontent-%COMP%_prism-perf-pulse 2s ease-in-out infinite;\n}\n\n@keyframes _ngcontent-%COMP%_prism-perf-pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.4;\n }\n}\n\n.prism-perf-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}"] });
|
|
143
141
|
}
|
|
144
142
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PerfPanelComponent, [{
|
|
145
143
|
type: Component,
|
|
146
|
-
args: [{ selector: 'prism-perf-panel', standalone: true, imports: [
|
|
147
|
-
BundleSectionComponent,
|
|
148
|
-
RenderSectionComponent,
|
|
149
|
-
MemorySectionComponent,
|
|
150
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
151
|
-
<div class="prism-perf-panel">
|
|
152
|
-
<div class="prism-subtabs">
|
|
153
|
-
<button
|
|
154
|
-
class="prism-st-tab"
|
|
155
|
-
[class.prism-st-tab--active]="activeTab() === 'bundle'"
|
|
156
|
-
(click)="activeTab.set('bundle')"
|
|
157
|
-
>
|
|
158
|
-
Bundle
|
|
159
|
-
</button>
|
|
160
|
-
<button
|
|
161
|
-
class="prism-st-tab"
|
|
162
|
-
[class.prism-st-tab--active]="activeTab() === 'render'"
|
|
163
|
-
(click)="activeTab.set('render')"
|
|
164
|
-
>
|
|
165
|
-
Render
|
|
166
|
-
</button>
|
|
167
|
-
<button
|
|
168
|
-
class="prism-st-tab"
|
|
169
|
-
[class.prism-st-tab--active]="activeTab() === 'memory'"
|
|
170
|
-
(click)="activeTab.set('memory')"
|
|
171
|
-
>
|
|
172
|
-
Memory
|
|
173
|
-
</button>
|
|
174
|
-
<div class="prism-subtabs-actions">
|
|
175
|
-
@if (activeTab() === 'render') {
|
|
176
|
-
@if (renderService.isRecording()) {
|
|
177
|
-
<button class="prism-tool-btn" (click)="renderService.stopRecording()">
|
|
178
|
-
⏸ Pause
|
|
179
|
-
</button>
|
|
180
|
-
} @else {
|
|
181
|
-
<button class="prism-tool-btn" (click)="renderService.startRecording()">
|
|
182
|
-
▶ Profile
|
|
183
|
-
</button>
|
|
184
|
-
}
|
|
185
|
-
<button class="prism-tool-btn" (click)="renderService.clear()">
|
|
186
|
-
✕ Clear
|
|
187
|
-
</button>
|
|
188
|
-
@if (renderService.isRecording()) {
|
|
189
|
-
<span class="prism-perf-status">
|
|
190
|
-
<span class="prism-perf-status-dot"></span> live ·
|
|
191
|
-
{{ renderService.sampleCount() }} samples
|
|
192
|
-
</span>
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
@if (activeTab() === 'memory') {
|
|
196
|
-
<button class="prism-tool-btn" (click)="captureMemorySnapshots()">
|
|
197
|
-
▶ Snapshot
|
|
198
|
-
</button>
|
|
199
|
-
<button class="prism-tool-btn" (click)="memoryService.clear()">
|
|
200
|
-
✕ Clear
|
|
201
|
-
</button>
|
|
202
|
-
}
|
|
203
|
-
@if (renderService.cdRunCount() > 0) {
|
|
204
|
-
<span class="prism-perf-cd-badge">
|
|
205
|
-
{{ renderService.cdRunCount() }} CD runs
|
|
206
|
-
</span>
|
|
207
|
-
}
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
<div class="prism-perf-content">
|
|
212
|
-
@switch (activeTab()) { @case ('bundle') {
|
|
213
|
-
<perf-bundle-section
|
|
214
|
-
[metrics]="bundleMetrics()"
|
|
215
|
-
[warnKb]="thresholds.bundleWarnKb"
|
|
216
|
-
[critKb]="thresholds.bundleCritKb"
|
|
217
|
-
/>
|
|
218
|
-
} @case ('render') {
|
|
219
|
-
<perf-render-section
|
|
220
|
-
[renderService]="renderService"
|
|
221
|
-
[warnMs]="thresholds.renderWarnMs"
|
|
222
|
-
[critMs]="thresholds.renderCritMs"
|
|
223
|
-
/>
|
|
224
|
-
} @case ('memory') {
|
|
225
|
-
<perf-memory-section [memoryService]="memoryService" />
|
|
226
|
-
} }
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
`, styles: ["\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .prism-perf-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .prism-subtabs {\n display: flex;\n gap: 2px;\n padding: 10px 20px 0;\n border-bottom: 1px solid var(--prism-border);\n background: var(--prism-bg-elevated);\n position: sticky;\n top: 0;\n z-index: 2;\n }\n\n .prism-st-tab {\n padding: 7px 12px;\n font-size: 12px;\n font-weight: 500;\n color: var(--prism-text-muted);\n border-radius: 6px 6px 0 0;\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n background: transparent;\n border: none;\n font-family: var(--font-sans);\n transition: color var(--dur-fast);\n }\n .prism-st-tab:hover { color: var(--prism-text-2); }\n .prism-st-tab--active { color: var(--prism-text); }\n .prism-st-tab--active::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n bottom: -1px;\n height: 2px;\n background: var(--prism-primary);\n border-radius: 1px;\n }\n\n .prism-subtabs-actions {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .prism-perf-cd-badge {\n font-family: var(--font-mono, 'JetBrains Mono', monospace);\n font-size: 11px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n height: 24px;\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n color: var(--prism-primary);\n border: 1px solid color-mix(in srgb, var(--prism-primary) 25%, transparent);\n border-radius: 5px;\n }\n .prism-tool-btn {\n height: 24px;\n padding: 0 9px;\n border-radius: 5px;\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11.5px;\n color: var(--prism-text-muted);\n transition: all 0.12s;\n font-weight: 500;\n background: none;\n border: none;\n cursor: pointer;\n font-family: var(--font-sans);\n }\n .prism-tool-btn:hover {\n color: var(--prism-text);\n background: color-mix(in srgb, var(--prism-primary) 8%, transparent);\n }\n\n .prism-perf-status {\n font-size: 11px;\n color: var(--prism-text-muted);\n font-family: var(--font-mono);\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .prism-perf-status-dot {\n display: inline-block;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--prism-success);\n box-shadow: 0 0 6px var(--prism-success);\n animation: prism-perf-pulse 2s ease-in-out infinite;\n }\n @keyframes prism-perf-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n\n .prism-perf-content {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n }\n "] }]
|
|
144
|
+
args: [{ selector: 'prism-perf-panel', standalone: true, imports: [BundleSectionComponent, RenderSectionComponent, MemorySectionComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"prism-perf-panel\">\n <div class=\"prism-subtabs\">\n <button\n class=\"prism-st-tab\"\n [class.prism-st-tab--active]=\"activeTab() === 'bundle'\"\n (click)=\"activeTab.set('bundle')\">\n Bundle\n </button>\n <button\n class=\"prism-st-tab\"\n [class.prism-st-tab--active]=\"activeTab() === 'render'\"\n (click)=\"activeTab.set('render')\">\n Render\n </button>\n <button\n class=\"prism-st-tab\"\n [class.prism-st-tab--active]=\"activeTab() === 'memory'\"\n (click)=\"activeTab.set('memory')\">\n Memory\n </button>\n <div class=\"prism-subtabs-actions\">\n @if (activeTab() === 'render') {\n @if (renderService.isRecording()) {\n <button\n class=\"prism-tool-btn\"\n (click)=\"renderService.stopRecording()\">\n ⏸ Pause\n </button>\n } @else {\n <button\n class=\"prism-tool-btn\"\n (click)=\"renderService.startRecording()\">\n ▶ Profile\n </button>\n }\n <button\n class=\"prism-tool-btn\"\n (click)=\"renderService.clear()\">\n ✕ Clear\n </button>\n @if (renderService.isRecording()) {\n <span class=\"prism-perf-status\"> <span class=\"prism-perf-status-dot\"></span> live · {{ renderService.sampleCount() }} samples </span>\n }\n }\n @if (activeTab() === 'memory') {\n <button\n class=\"prism-tool-btn\"\n (click)=\"captureMemorySnapshots()\">\n ▶ Snapshot\n </button>\n <button\n class=\"prism-tool-btn\"\n (click)=\"memoryService.clear()\">\n ✕ Clear\n </button>\n }\n @if (renderService.cdRunCount() > 0) {\n <span class=\"prism-perf-cd-badge\"> {{ renderService.cdRunCount() }} CD runs </span>\n }\n </div>\n </div>\n\n <div class=\"prism-perf-content\">\n @switch (activeTab()) {\n @case ('bundle') {\n <perf-bundle-section\n [metrics]=\"bundleMetrics()\"\n [warnKb]=\"thresholds.bundleWarnKb\"\n [critKb]=\"thresholds.bundleCritKb\" />\n }\n @case ('render') {\n <perf-render-section\n [renderService]=\"renderService\"\n [warnMs]=\"thresholds.renderWarnMs\"\n [critMs]=\"thresholds.renderCritMs\" />\n }\n @case ('memory') {\n <perf-memory-section [memoryService]=\"memoryService\" />\n }\n }\n </div>\n</div>\n", styles: [":host {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.prism-perf-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.prism-subtabs {\n position: sticky;\n top: 0;\n z-index: 2;\n display: flex;\n gap: 2px;\n padding: 10px 20px 0;\n background: var(--prism-bg-elevated);\n border-bottom: 1px solid var(--prism-border);\n}\n\n.prism-st-tab {\n position: relative;\n display: flex;\n gap: 6px;\n align-items: center;\n padding: 7px 12px;\n font-family: var(--font-sans);\n font-size: 12px;\n font-weight: 500;\n color: var(--prism-text-muted);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 6px 6px 0 0;\n transition: color var(--dur-fast);\n}\n\n.prism-st-tab:hover {\n color: var(--prism-text-2);\n}\n\n.prism-st-tab--active {\n color: var(--prism-text);\n}\n\n.prism-st-tab--active::after {\n position: absolute;\n right: 8px;\n bottom: -1px;\n left: 8px;\n height: 2px;\n content: '';\n background: var(--prism-primary);\n border-radius: 1px;\n}\n\n.prism-subtabs-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n margin-left: auto;\n}\n\n.prism-perf-cd-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 24px;\n padding: 0 8px;\n font-family: var(--font-mono, 'JetBrains Mono', monospace);\n font-size: 11px;\n color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--prism-primary) 25%, transparent);\n border-radius: 5px;\n}\n\n.prism-tool-btn {\n display: flex;\n gap: 5px;\n align-items: center;\n height: 24px;\n padding: 0 9px;\n font-family: var(--font-sans);\n font-size: 11.5px;\n font-weight: 500;\n color: var(--prism-text-muted);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 5px;\n transition: all 0.12s;\n}\n\n.prism-tool-btn:hover {\n color: var(--prism-text);\n background: color-mix(in srgb, var(--prism-primary) 8%, transparent);\n}\n\n.prism-perf-status {\n display: flex;\n gap: 5px;\n align-items: center;\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.prism-perf-status-dot {\n display: inline-block;\n width: 5px;\n height: 5px;\n background: var(--prism-success);\n border-radius: 50%;\n box-shadow: 0 0 6px var(--prism-success);\n animation: prism-perf-pulse 2s ease-in-out infinite;\n}\n\n@keyframes prism-perf-pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0.4;\n }\n}\n\n.prism-perf-content {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n"] }]
|
|
230
145
|
}], null, { activeComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeComponent", required: false }] }] }); })();
|
|
231
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PerfPanelComponent, { className: "PerfPanelComponent", filePath: "perf-panel.component.ts", lineNumber:
|
|
146
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PerfPanelComponent, { className: "PerfPanelComponent", filePath: "perf-panel.component.ts", lineNumber: 20 }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-plugin.browser.d.ts","sourceRoot":"","sources":["../src/perf-plugin.browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"perf-plugin.browser.d.ts","sourceRoot":"","sources":["../src/perf-plugin.browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,aAAa,CActE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-plugin.d.ts","sourceRoot":"","sources":["../src/perf-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"perf-plugin.d.ts","sourceRoot":"","sources":["../src/perf-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa,CA4BrE"}
|
package/dist/perf-plugin.js
CHANGED
|
@@ -10,9 +10,9 @@ export function perfPlugin(options) {
|
|
|
10
10
|
...component.showcaseConfig,
|
|
11
11
|
meta: {
|
|
12
12
|
...component.showcaseConfig.meta,
|
|
13
|
-
perf: { bundle }
|
|
14
|
-
}
|
|
15
|
-
}
|
|
13
|
+
perf: { bundle }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
16
|
};
|
|
17
17
|
},
|
|
18
18
|
panels: [
|
|
@@ -20,8 +20,8 @@ export function perfPlugin(options) {
|
|
|
20
20
|
id: 'perf',
|
|
21
21
|
label: 'Performance',
|
|
22
22
|
loadComponent: () => import('./perf-panel.component.js').then((m) => m.PerfPanelComponent),
|
|
23
|
-
position: 'bottom'
|
|
24
|
-
}
|
|
25
|
-
]
|
|
23
|
+
position: 'bottom'
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
26
|
};
|
|
27
27
|
}
|
package/dist/perf.types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf.types.d.ts","sourceRoot":"","sources":["../src/perf.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;
|
|
1
|
+
{"version":3,"file":"perf.types.d.ts","sourceRoot":"","sources":["../src/perf.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE;QACL,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF,MAAM,CAAC,EAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,MAAM,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACL;AAED,eAAO,MAAM,kBAAkB,EAAE,cAOhC,CAAC"}
|
package/dist/perf.types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-render.service.d.ts","sourceRoot":"","sources":["../../src/render/perf-render.service.ts"],"names":[],"mappings":"AAIA,qBAAa,iBAAiB;
|
|
1
|
+
{"version":3,"file":"perf-render.service.d.ts","sourceRoot":"","sources":["../../src/render/perf-render.service.ts"],"names":[],"mappings":"AAIA,qBAAa,iBAAiB;IAC1B,MAAM,CAAC,WAAW,IAAI,iBAAiB;IAKvC,QAAQ,CAAC,WAAW,kDAAiB;IACrC,QAAQ,CAAC,aAAa,wDAA+B;IACrD,QAAQ,CAAC,SAAS,mDAAwB;IAC1C,QAAQ,CAAC,UAAU,iDAAa;IAEhC,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,UAAU,CAAM;IAExB,QAAQ,CAAC,WAAW,yCAKjB;IAEH,QAAQ,CAAC,WAAW,yCAQjB;IAEH,QAAQ,CAAC,WAAW,yCAKjB;IAEH,QAAQ,CAAC,YAAY,gDAIlB;IAEH,QAAQ,CAAC,WAAW,yCAA2C;IAE/D,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAInC,cAAc,IAAI,IAAI;IAsBtB,aAAa,IAAI,IAAI;IAMrB,KAAK,IAAI,IAAI;CAKhB"}
|
|
@@ -4,7 +4,7 @@ export declare class RenderSectionComponent {
|
|
|
4
4
|
readonly renderService: import("@angular/core").InputSignal<PerfRenderService>;
|
|
5
5
|
readonly warnMs: import("@angular/core").InputSignal<number>;
|
|
6
6
|
readonly critMs: import("@angular/core").InputSignal<number>;
|
|
7
|
-
readonly initialClass: import("@angular/core").Signal<"
|
|
7
|
+
readonly initialClass: import("@angular/core").Signal<"" | "crit" | "warn">;
|
|
8
8
|
formatMs(value: number | null): string;
|
|
9
9
|
colorFor(value: number | null): string;
|
|
10
10
|
static ɵfac: i0.ɵɵFactoryDeclaration<RenderSectionComponent, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-section.component.d.ts","sourceRoot":"","sources":["../../src/render/render-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;;AAGlE,
|
|
1
|
+
{"version":3,"file":"render-section.component.d.ts","sourceRoot":"","sources":["../../src/render/render-section.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;;AAGlE,qBAQa,sBAAsB;IAC/B,QAAQ,CAAC,aAAa,yDAAuC;IAC7D,QAAQ,CAAC,MAAM,8CAAY;IAC3B,QAAQ,CAAC,MAAM,8CAAa;IAE5B,QAAQ,CAAC,YAAY,uDAOlB;IAEH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAKtC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;yCAnB7B,sBAAsB;2CAAtB,sBAAsB;CAyBlC"}
|
|
@@ -146,57 +146,10 @@ export class RenderSectionComponent {
|
|
|
146
146
|
} if (rf & 2) {
|
|
147
147
|
let tmp_0_0;
|
|
148
148
|
i0.ɵɵconditional((tmp_0_0 = ctx.renderService()) ? 0 : -1, tmp_0_0);
|
|
149
|
-
} }, dependencies: [SparklineComponent], styles: [".perf-body[_ngcontent-%COMP%] {\n
|
|
149
|
+
} }, dependencies: [SparklineComponent], styles: [".perf-body[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-card[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--%NS%prism-bg-surface);\n border: 1px solid var(--%NS%prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block[_ngcontent-%COMP%] {\n display: block;\n}\n\n.perf-card-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--%NS%prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-val[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--%NS%prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-card-sub[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-detail[_ngcontent-%COMP%] {\n padding: 0 24px 20px;\n}\n\n.perf-sparkline-legend[_ngcontent-%COMP%] {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--%NS%prism-text-muted);\n}\n\n.perf-sparkline-hl[_ngcontent-%COMP%] {\n color: var(--%NS%prism-primary);\n}\n\n.perf-sparkline-wrap[_ngcontent-%COMP%] {\n position: relative;\n margin-top: 10px;\n}\n\n.perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--%NS%prism-text-ghost);\n}\n\n.perf-empty-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--%NS%prism-text-ghost);\n opacity: 0.6;\n}"] });
|
|
150
150
|
}
|
|
151
151
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RenderSectionComponent, [{
|
|
152
152
|
type: Component,
|
|
153
|
-
args: [{ selector: 'perf-render-section', standalone: true, imports: [SparklineComponent], changeDetection: ChangeDetectionStrategy.OnPush, template:
|
|
154
|
-
@if (renderService(); as svc) {
|
|
155
|
-
@if (svc.initialRender() !== null || svc.rerenders().length > 0) {
|
|
156
|
-
<div class="perf-body">
|
|
157
|
-
<div class="perf-card">
|
|
158
|
-
<div class="perf-card-head"><span class="perf-card-name">Initial Render</span></div>
|
|
159
|
-
<div class="perf-card-val" [style.color]="colorFor(svc.initialRender())">{{ formatMs(svc.initialRender()) }}<span>ms</span></div>
|
|
160
|
-
</div>
|
|
161
|
-
<div class="perf-card">
|
|
162
|
-
<div class="perf-card-head"><span class="perf-card-name">Avg Re-Render</span></div>
|
|
163
|
-
<div class="perf-card-val">{{ formatMs(svc.avgRerender()) }}<span>ms</span></div>
|
|
164
|
-
<div class="perf-card-sub">{{ svc.sampleCount() }} samples</div>
|
|
165
|
-
</div>
|
|
166
|
-
<div class="perf-card">
|
|
167
|
-
<div class="perf-card-head"><span class="perf-card-name">Slowest</span></div>
|
|
168
|
-
<div class="perf-card-val">{{ formatMs(svc.maxRerender()) }}<span>ms</span></div>
|
|
169
|
-
</div>
|
|
170
|
-
<div class="perf-card">
|
|
171
|
-
<div class="perf-card-head"><span class="perf-card-name">P95</span></div>
|
|
172
|
-
<div class="perf-card-val">{{ formatMs(svc.p95Rerender()) }}<span>ms</span></div>
|
|
173
|
-
</div>
|
|
174
|
-
<div class="perf-card">
|
|
175
|
-
<div class="perf-card-head"><span class="perf-card-name">Last Render</span></div>
|
|
176
|
-
<div class="perf-card-val">{{ formatMs(svc.lastRerender()) }}<span>ms</span></div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
@if (svc.rerenders().length > 1) {
|
|
181
|
-
<div class="perf-detail">
|
|
182
|
-
<div class="perf-card perf-card--block">
|
|
183
|
-
<div class="perf-card-head">
|
|
184
|
-
<span class="perf-card-name">Render Time Trace — Last {{ svc.sampleCount() }} Samples</span>
|
|
185
|
-
<span class="perf-sparkline-legend">avg <span class="perf-sparkline-hl">{{ formatMs(svc.avgRerender()) }} ms</span> · max <span class="perf-sparkline-hl">{{ formatMs(svc.maxRerender()) }} ms</span></span>
|
|
186
|
-
</div>
|
|
187
|
-
<div class="perf-sparkline-wrap">
|
|
188
|
-
<perf-sparkline [samples]="svc.rerenders()" [thresholdWarn]="warnMs()" [height]="80" />
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
|
-
</div>
|
|
192
|
-
}
|
|
193
|
-
} @else {
|
|
194
|
-
<div class="perf-empty">
|
|
195
|
-
<div class="perf-empty-text">No profiling data yet</div>
|
|
196
|
-
<div class="perf-empty-hint">Click Profile to start recording render times</div>
|
|
197
|
-
</div>
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
`, styles: ["\n .perf-body {\n padding: 20px 24px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n }\n\n .perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n }\n .perf-card--block { display: block; }\n .perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .perf-card-name {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n }\n .perf-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n display: flex;\n align-items: baseline;\n gap: 4px;\n }\n .perf-card-val span {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .perf-card-sub {\n font-size: 11px;\n color: var(--prism-text-muted);\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-detail { padding: 0 24px 20px; }\n\n .perf-sparkline-legend {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n }\n .perf-sparkline-hl { color: var(--prism-primary); }\n .perf-sparkline-wrap { margin-top: 10px; position: relative; }\n\n .perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .perf-empty-text { font-size: 12px; color: var(--prism-text-ghost); }\n .perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost); opacity: 0.6; }\n "] }]
|
|
153
|
+
args: [{ selector: 'perf-render-section', standalone: true, imports: [SparklineComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (renderService(); as svc) {\n @if (svc.initialRender() !== null || svc.rerenders().length > 0) {\n <div class=\"perf-body\">\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Initial Render</span></div>\n <div\n class=\"perf-card-val\"\n [style.color]=\"colorFor(svc.initialRender())\"\n >{{ formatMs(svc.initialRender()) }}<span>ms</span></div\n >\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Avg Re-Render</span></div>\n <div class=\"perf-card-val\">{{ formatMs(svc.avgRerender()) }}<span>ms</span></div>\n <div class=\"perf-card-sub\">{{ svc.sampleCount() }} samples</div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Slowest</span></div>\n <div class=\"perf-card-val\">{{ formatMs(svc.maxRerender()) }}<span>ms</span></div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">P95</span></div>\n <div class=\"perf-card-val\">{{ formatMs(svc.p95Rerender()) }}<span>ms</span></div>\n </div>\n <div class=\"perf-card\">\n <div class=\"perf-card-head\"><span class=\"perf-card-name\">Last Render</span></div>\n <div class=\"perf-card-val\">{{ formatMs(svc.lastRerender()) }}<span>ms</span></div>\n </div>\n </div>\n\n @if (svc.rerenders().length > 1) {\n <div class=\"perf-detail\">\n <div class=\"perf-card perf-card--block\">\n <div class=\"perf-card-head\">\n <span class=\"perf-card-name\">Render Time Trace — Last {{ svc.sampleCount() }} Samples</span>\n <span class=\"perf-sparkline-legend\"\n >avg <span class=\"perf-sparkline-hl\">{{ formatMs(svc.avgRerender()) }} ms</span> · max\n <span class=\"perf-sparkline-hl\">{{ formatMs(svc.maxRerender()) }} ms</span></span\n >\n </div>\n <div class=\"perf-sparkline-wrap\">\n <perf-sparkline\n [samples]=\"svc.rerenders()\"\n [thresholdWarn]=\"warnMs()\"\n [height]=\"80\" />\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"perf-empty\">\n <div class=\"perf-empty-text\">No profiling data yet</div>\n <div class=\"perf-empty-hint\">Click Profile to start recording render times</div>\n </div>\n }\n}\n", styles: [".perf-body {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n padding: 20px 24px;\n}\n\n.perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n}\n\n.perf-card--block {\n display: block;\n}\n\n.perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.perf-card-name {\n font-size: 11px;\n font-weight: 700;\n color: var(--prism-text-ghost);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.perf-card-val {\n display: flex;\n gap: 4px;\n align-items: baseline;\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n}\n\n.perf-card-val span {\n font-size: 13px;\n font-weight: 500;\n color: var(--prism-text-muted);\n}\n\n.perf-card-sub {\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.perf-detail {\n padding: 0 24px 20px;\n}\n\n.perf-sparkline-legend {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n}\n\n.perf-sparkline-hl {\n color: var(--prism-primary);\n}\n\n.perf-sparkline-wrap {\n position: relative;\n margin-top: 10px;\n}\n\n.perf-empty {\n display: flex;\n flex-direction: column;\n gap: 8px;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 180px;\n}\n\n.perf-empty-text {\n font-size: 12px;\n color: var(--prism-text-ghost);\n}\n\n.perf-empty-hint {\n font-size: 11px;\n color: var(--prism-text-ghost);\n opacity: 0.6;\n}\n"] }]
|
|
201
154
|
}], null, { renderService: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderService", required: true }] }], warnMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "warnMs", required: false }] }], critMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "critMs", required: false }] }] }); })();
|
|
202
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RenderSectionComponent, { className: "RenderSectionComponent", filePath: "render/render-section.component.ts", lineNumber:
|
|
155
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RenderSectionComponent, { className: "RenderSectionComponent", filePath: "render/render-section.component.ts", lineNumber: 13 }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../src/render/sparkline.component.ts"],"names":[],"mappings":";AAEA,
|
|
1
|
+
{"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../src/render/sparkline.component.ts"],"names":[],"mappings":";AAEA,qBAOa,kBAAkB;IAC3B,QAAQ,CAAC,OAAO,gDAAuB;IACvC,QAAQ,CAAC,aAAa,8CAAY;IAClC,QAAQ,CAAC,MAAM,8CAAa;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAcpB;IAEH,QAAQ,CAAC,QAAQ,yCAKd;IAEH,QAAQ,CAAC,QAAQ,yCAQd;IAEH,QAAQ,CAAC,KAAK,gDAQX;IAEH,QAAQ,CAAC,SAAS;;;;cAUf;IAEH,QAAQ,CAAC,YAAY;;;;cAIlB;yCAhEM,kBAAkB;2CAAlB,kBAAkB;CAiE9B"}
|
|
@@ -12,7 +12,7 @@ function SparklineComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
|
12
12
|
i0.ɵɵadvance();
|
|
13
13
|
i0.ɵɵattribute("x", 3)("y", ctx_r0.warnY() - 3);
|
|
14
14
|
i0.ɵɵadvance();
|
|
15
|
-
i0.ɵɵtextInterpolate1("", ctx_r0.thresholdWarn(), "ms");
|
|
15
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.thresholdWarn(), "ms ");
|
|
16
16
|
} }
|
|
17
17
|
function SparklineComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
18
18
|
i0.ɵɵnamespaceSVG();
|
|
@@ -49,8 +49,8 @@ export class SparklineComponent {
|
|
|
49
49
|
const step = data.length > 1 ? 600 / (data.length - 1) : 300;
|
|
50
50
|
return data.map((v, i) => ({
|
|
51
51
|
x: i * step,
|
|
52
|
-
y: h - 4 - (
|
|
53
|
-
value: v
|
|
52
|
+
y: h - 4 - (v / max) * (h - 8),
|
|
53
|
+
value: v
|
|
54
54
|
}));
|
|
55
55
|
}, /* @ts-ignore */
|
|
56
56
|
...(ngDevMode ? [{ debugName: "points" }] : /* istanbul ignore next */ []));
|
|
@@ -76,7 +76,7 @@ export class SparklineComponent {
|
|
|
76
76
|
if (data.length === 0)
|
|
77
77
|
return null;
|
|
78
78
|
const max = Math.max(...data, this.thresholdWarn() * 1.2);
|
|
79
|
-
return h - 4 - (
|
|
79
|
+
return h - 4 - (this.thresholdWarn() / max) * (h - 8);
|
|
80
80
|
}, /* @ts-ignore */
|
|
81
81
|
...(ngDevMode ? [{ debugName: "warnY" }] : /* istanbul ignore next */ []));
|
|
82
82
|
peakPoint = computed(() => {
|
|
@@ -128,47 +128,10 @@ export class SparklineComponent {
|
|
|
128
128
|
i0.ɵɵconditional((tmp_4_0 = ctx.peakPoint()) ? 14 : -1, tmp_4_0);
|
|
129
129
|
i0.ɵɵadvance();
|
|
130
130
|
i0.ɵɵconditional((tmp_5_0 = ctx.currentPoint()) ? 15 : -1, tmp_5_0);
|
|
131
|
-
} }, styles: [".prism-perf-sparkline-wrap[_ngcontent-%COMP%] {
|
|
131
|
+
} }, styles: [".prism-perf-sparkline-wrap[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.prism-perf-sparkline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 52px;\n}\n\n.sparkline-gradient-start[_ngcontent-%COMP%] {\n stop-color: var(--%NS%prism-primary);\n stop-opacity: 0.35;\n}\n\n.sparkline-gradient-end[_ngcontent-%COMP%] {\n stop-color: var(--%NS%prism-primary);\n stop-opacity: 0;\n}\n\n.sparkline-warn-line[_ngcontent-%COMP%] {\n opacity: 0.4;\n stroke: var(--%NS%prism-warn);\n stroke-width: 0.8;\n stroke-dasharray: 4 4;\n}\n\n.sparkline-warn-text[_ngcontent-%COMP%] {\n opacity: 0.5;\n fill: var(--%NS%prism-warn);\n}\n\n.sparkline-line[_ngcontent-%COMP%] {\n stroke: var(--%NS%prism-primary);\n}\n\n.sparkline-peak[_ngcontent-%COMP%] {\n fill: var(--%NS%prism-warn);\n}\n\n.sparkline-current[_ngcontent-%COMP%] {\n fill: var(--%NS%prism-primary);\n}\n\n.sparkline-current-pulse[_ngcontent-%COMP%] {\n opacity: 0.4;\n fill: none;\n stroke: var(--%NS%prism-primary);\n}"] });
|
|
132
132
|
}
|
|
133
133
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SparklineComponent, [{
|
|
134
134
|
type: Component,
|
|
135
|
-
args: [{ selector: 'perf-sparkline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template:
|
|
136
|
-
<div class="prism-perf-sparkline-wrap">
|
|
137
|
-
<svg class="prism-perf-sparkline-svg" [attr.viewBox]="'0 0 600 ' + height()" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
|
|
138
|
-
<defs>
|
|
139
|
-
<linearGradient id="perf-sparkg" x1="0" y1="0" x2="0" y2="1">
|
|
140
|
-
<stop offset="0%" class="sparkline-gradient-start"/>
|
|
141
|
-
<stop offset="100%" class="sparkline-gradient-end"/>
|
|
142
|
-
</linearGradient>
|
|
143
|
-
<filter id="perf-glow">
|
|
144
|
-
<feGaussianBlur stdDeviation="1.5" result="coloredBlur"/>
|
|
145
|
-
<feMerge><feMergeNode in="coloredBlur"/><feMergeNode in="SourceGraphic"/></feMerge>
|
|
146
|
-
</filter>
|
|
147
|
-
</defs>
|
|
148
|
-
|
|
149
|
-
@if (warnY() !== null) {
|
|
150
|
-
<line [attr.x1]="0" [attr.y1]="warnY()" [attr.x2]="600" [attr.y2]="warnY()"
|
|
151
|
-
class="sparkline-warn-line"/>
|
|
152
|
-
<text [attr.x]="3" [attr.y]="warnY()! - 3" font-size="8" class="sparkline-warn-text"
|
|
153
|
-
font-family="monospace">{{ thresholdWarn() }}ms</text>
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
<path [attr.d]="areaPath()" fill="url(#perf-sparkg)"/>
|
|
157
|
-
<path [attr.d]="linePath()" fill="none" class="sparkline-line" stroke-width="1.5" filter="url(#perf-glow)"/>
|
|
158
|
-
|
|
159
|
-
@if (peakPoint(); as peak) {
|
|
160
|
-
<circle [attr.cx]="peak.x" [attr.cy]="peak.y" r="3" class="sparkline-peak" filter="url(#perf-glow)"/>
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@if (currentPoint(); as current) {
|
|
164
|
-
<circle [attr.cx]="current.x" [attr.cy]="current.y" r="2.5" class="sparkline-current"/>
|
|
165
|
-
<circle [attr.cx]="current.x" [attr.cy]="current.y" r="5" class="sparkline-current-pulse" stroke-width="1">
|
|
166
|
-
<animate attributeName="r" values="3;7" dur="1.5s" repeatCount="indefinite"/>
|
|
167
|
-
<animate attributeName="opacity" values="0.4;0" dur="1.5s" repeatCount="indefinite"/>
|
|
168
|
-
</circle>
|
|
169
|
-
}
|
|
170
|
-
</svg>
|
|
171
|
-
</div>
|
|
172
|
-
`, styles: ["\n .prism-perf-sparkline-wrap { position: relative; }\n .prism-perf-sparkline-svg { width: 100%; height: 52px; }\n\n .sparkline-gradient-start { stop-color: var(--prism-primary); stop-opacity: 0.35; }\n .sparkline-gradient-end { stop-color: var(--prism-primary); stop-opacity: 0; }\n\n .sparkline-warn-line {\n stroke: var(--prism-warn);\n stroke-width: 0.8;\n stroke-dasharray: 4 4;\n opacity: 0.4;\n }\n .sparkline-warn-text { fill: var(--prism-warn); opacity: 0.5; }\n\n .sparkline-line { stroke: var(--prism-primary); }\n .sparkline-peak { fill: var(--prism-warn); }\n .sparkline-current { fill: var(--prism-primary); }\n .sparkline-current-pulse { fill: none; stroke: var(--prism-primary); opacity: 0.4; }\n "] }]
|
|
135
|
+
args: [{ selector: 'perf-sparkline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"prism-perf-sparkline-wrap\">\n <svg\n class=\"prism-perf-sparkline-svg\"\n [attr.viewBox]=\"'0 0 600 ' + height()\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <linearGradient\n id=\"perf-sparkg\"\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\">\n <stop\n offset=\"0%\"\n class=\"sparkline-gradient-start\" />\n <stop\n offset=\"100%\"\n class=\"sparkline-gradient-end\" />\n </linearGradient>\n <filter id=\"perf-glow\">\n <feGaussianBlur\n stdDeviation=\"1.5\"\n result=\"coloredBlur\" />\n <feMerge>\n <feMergeNode in=\"coloredBlur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n </defs>\n\n @if (warnY() !== null) {\n <line\n [attr.x1]=\"0\"\n [attr.y1]=\"warnY()\"\n [attr.x2]=\"600\"\n [attr.y2]=\"warnY()\"\n class=\"sparkline-warn-line\" />\n <text\n [attr.x]=\"3\"\n [attr.y]=\"warnY()! - 3\"\n font-size=\"8\"\n class=\"sparkline-warn-text\"\n font-family=\"monospace\">\n {{ thresholdWarn() }}ms\n </text>\n }\n\n <path\n [attr.d]=\"areaPath()\"\n fill=\"url(#perf-sparkg)\" />\n <path\n [attr.d]=\"linePath()\"\n fill=\"none\"\n class=\"sparkline-line\"\n stroke-width=\"1.5\"\n filter=\"url(#perf-glow)\" />\n\n @if (peakPoint(); as peak) {\n <circle\n [attr.cx]=\"peak.x\"\n [attr.cy]=\"peak.y\"\n r=\"3\"\n class=\"sparkline-peak\"\n filter=\"url(#perf-glow)\" />\n }\n\n @if (currentPoint(); as current) {\n <circle\n [attr.cx]=\"current.x\"\n [attr.cy]=\"current.y\"\n r=\"2.5\"\n class=\"sparkline-current\" />\n <circle\n [attr.cx]=\"current.x\"\n [attr.cy]=\"current.y\"\n r=\"5\"\n class=\"sparkline-current-pulse\"\n stroke-width=\"1\">\n <animate\n attributeName=\"r\"\n values=\"3;7\"\n dur=\"1.5s\"\n repeatCount=\"indefinite\" />\n <animate\n attributeName=\"opacity\"\n values=\"0.4;0\"\n dur=\"1.5s\"\n repeatCount=\"indefinite\" />\n </circle>\n }\n </svg>\n</div>\n", styles: [".prism-perf-sparkline-wrap {\n position: relative;\n}\n\n.prism-perf-sparkline-svg {\n width: 100%;\n height: 52px;\n}\n\n.sparkline-gradient-start {\n stop-color: var(--prism-primary);\n stop-opacity: 0.35;\n}\n\n.sparkline-gradient-end {\n stop-color: var(--prism-primary);\n stop-opacity: 0;\n}\n\n.sparkline-warn-line {\n opacity: 0.4;\n stroke: var(--prism-warn);\n stroke-width: 0.8;\n stroke-dasharray: 4 4;\n}\n\n.sparkline-warn-text {\n opacity: 0.5;\n fill: var(--prism-warn);\n}\n\n.sparkline-line {\n stroke: var(--prism-primary);\n}\n\n.sparkline-peak {\n fill: var(--prism-warn);\n}\n\n.sparkline-current {\n fill: var(--prism-primary);\n}\n\n.sparkline-current-pulse {\n opacity: 0.4;\n fill: none;\n stroke: var(--prism-primary);\n}\n"] }]
|
|
173
136
|
}], null, { samples: [{ type: i0.Input, args: [{ isSignal: true, alias: "samples", required: false }] }], thresholdWarn: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholdWarn", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }] }); })();
|
|
174
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SparklineComponent, { className: "SparklineComponent", filePath: "render/sparkline.component.ts", lineNumber:
|
|
137
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SparklineComponent, { className: "SparklineComponent", filePath: "render/sparkline.component.ts", lineNumber: 10 }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,IAAI,EAAoC,MAAM,4BAA4B,CAAC;AAEhG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAwBtD,wBAAgB,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEvD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chain
|
|
1
|
+
import { chain } from '@angular-devkit/schematics';
|
|
2
2
|
import { addPluginToConfig } from '@ng-prism/core/schematics/utils';
|
|
3
3
|
const PLUGIN_IMPORT_NAME = 'perfPlugin';
|
|
4
4
|
const PLUGIN_IMPORT_FROM = '@ng-prism/plugin-perf';
|
|
@@ -9,13 +9,13 @@ function injectPlugin(options) {
|
|
|
9
9
|
const changed = addPluginToConfig(tree, configPath, {
|
|
10
10
|
importName: PLUGIN_IMPORT_NAME,
|
|
11
11
|
importFrom: PLUGIN_IMPORT_FROM,
|
|
12
|
-
call: PLUGIN_CALL
|
|
12
|
+
call: PLUGIN_CALL
|
|
13
13
|
});
|
|
14
14
|
if (changed) {
|
|
15
|
-
context.logger.info(` ${PLUGIN_IMPORT_FROM}
|
|
15
|
+
context.logger.info(` ${PLUGIN_IMPORT_FROM} added to ${configPath}`);
|
|
16
16
|
}
|
|
17
17
|
else {
|
|
18
|
-
context.logger.info(` ${PLUGIN_IMPORT_FROM} already configured
|
|
18
|
+
context.logger.info(` ${PLUGIN_IMPORT_FROM} already configured, skipped`);
|
|
19
19
|
}
|
|
20
20
|
return tree;
|
|
21
21
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/schema.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/schema.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-prism/plugin-perf",
|
|
3
|
-
"version": "22.
|
|
4
|
-
"description": "Performance profiling panel for ng-prism
|
|
3
|
+
"version": "22.4.0",
|
|
4
|
+
"description": "Performance profiling panel for ng-prism: bundle size, render time, memory footprint.",
|
|
5
5
|
"ng-add": {
|
|
6
6
|
"save": "devDependencies"
|
|
7
7
|
},
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@angular/core": ">=20.0.0",
|
|
38
38
|
"typescript": ">=5.0.0",
|
|
39
|
-
"@ng-prism/core": "^22.
|
|
39
|
+
"@ng-prism/core": "^22.4.0-0",
|
|
40
|
+
"@angular-devkit/schematics": ">=20.0.0"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@ng-prism/core": "*"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
|
+
"schematics": {
|
|
4
|
+
"ng-add": {
|
|
5
|
+
"description": "Adds @ng-prism/plugin-perf to the ng-prism config",
|
|
6
|
+
"factory": "../dist/schematics/ng-add/index#ngAdd",
|
|
7
|
+
"schema": "./ng-add/schema.json"
|
|
8
|
+
}
|
|
8
9
|
}
|
|
9
|
-
}
|
|
10
10
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "NgPrismPluginPerfNgAdd",
|
|
4
|
+
"title": "Add @ng-prism/plugin-perf",
|
|
5
|
+
"description": "Registers @ng-prism/plugin-perf in ng-prism.config.ts",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"configPath": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Path to ng-prism.config.ts",
|
|
11
|
+
"default": "ng-prism.config.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": [],
|
|
15
|
+
"additionalProperties": false
|
|
16
16
|
}
|