@ng-prism/plugin-perf 22.2.1 → 22.3.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 +6 -6
- package/dist/bundle/bundle-scanner.d.ts.map +1 -1
- package/dist/bundle/bundle-scanner.js +11 -7
- 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 +2 -2
- package/dist/schematics/ng-add/schema.d.ts.map +1 -1
- package/package.json +3 -2
- package/schematics/collection.json +7 -7
- package/schematics/ng-add/schema.json +14 -14
package/README.md
CHANGED
|
@@ -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
|
});
|
|
@@ -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,7 +9,7 @@ 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
15
|
context.logger.info(` ${PLUGIN_IMPORT_FROM} → added to ${configPath}`);
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-prism/plugin-perf",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.3.0",
|
|
4
4
|
"description": "Performance profiling panel for ng-prism — bundle size, render time, memory footprint.",
|
|
5
5
|
"ng-add": {
|
|
6
6
|
"save": "devDependencies"
|
|
@@ -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.3.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
|
}
|