@coherent.js/devtools 1.1.2 → 2.0.0-rc.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 +16 -12
- package/dist/index.js +317 -206
- package/dist/index.js.map +3 -3
- package/dist/profiler.js +107 -39
- package/dist/profiler.js.map +2 -2
- package/package.json +2 -2
- package/types/index.d.ts +74 -12
package/dist/profiler.js
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
// src/profiler.js
|
|
2
|
+
var hasPerformanceTimeline = () => typeof performance !== "undefined" && typeof performance.mark === "function";
|
|
3
|
+
function now() {
|
|
4
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
5
|
+
}
|
|
6
|
+
function clearTimelineEntries(marks, measureName) {
|
|
7
|
+
if (!hasPerformanceTimeline()) return;
|
|
8
|
+
for (const mark of marks) {
|
|
9
|
+
performance.clearMarks?.(mark);
|
|
10
|
+
}
|
|
11
|
+
if (measureName) {
|
|
12
|
+
performance.clearMeasures?.(measureName);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function recordTimelineMeasure(name, startMark, endMark) {
|
|
16
|
+
if (!hasPerformanceTimeline()) return;
|
|
17
|
+
try {
|
|
18
|
+
performance.mark(endMark);
|
|
19
|
+
performance.measure?.(name, startMark, endMark);
|
|
20
|
+
} catch {
|
|
21
|
+
} finally {
|
|
22
|
+
clearTimelineEntries([startMark, endMark], name);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
2
25
|
var PerformanceProfiler = class {
|
|
3
26
|
constructor(options = {}) {
|
|
4
27
|
this.options = {
|
|
5
|
-
|
|
28
|
+
// Opt-in: a profiler that is merely constructed must cost nothing.
|
|
29
|
+
enabled: false,
|
|
6
30
|
sampleRate: 1,
|
|
7
31
|
// 1.0 = 100% sampling
|
|
8
32
|
slowThreshold: 16,
|
|
@@ -29,14 +53,14 @@ var PerformanceProfiler = class {
|
|
|
29
53
|
const session = {
|
|
30
54
|
id: this.generateId(),
|
|
31
55
|
name,
|
|
32
|
-
startTime:
|
|
56
|
+
startTime: now(),
|
|
33
57
|
measurements: [],
|
|
34
58
|
marks: [],
|
|
35
59
|
active: true
|
|
36
60
|
};
|
|
37
61
|
this.sessions.set(session.id, session);
|
|
38
62
|
this.currentSession = session;
|
|
39
|
-
if (
|
|
63
|
+
if (hasPerformanceTimeline()) {
|
|
40
64
|
performance.mark(`coherent-session-start-${session.id}`);
|
|
41
65
|
}
|
|
42
66
|
return session.id;
|
|
@@ -52,19 +76,18 @@ var PerformanceProfiler = class {
|
|
|
52
76
|
if (!session) {
|
|
53
77
|
return null;
|
|
54
78
|
}
|
|
55
|
-
session.endTime =
|
|
79
|
+
session.endTime = now();
|
|
56
80
|
session.duration = session.endTime - session.startTime;
|
|
57
81
|
session.active = false;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
recordTimelineMeasure(
|
|
83
|
+
`coherent-session-${session.id}`,
|
|
84
|
+
`coherent-session-start-${session.id}`,
|
|
85
|
+
`coherent-session-end-${session.id}`
|
|
86
|
+
);
|
|
61
87
|
if (this.currentSession === session) {
|
|
62
88
|
this.currentSession = null;
|
|
63
89
|
}
|
|
64
|
-
this.
|
|
65
|
-
if (this.measurements.length > this.options.maxSamples) {
|
|
66
|
-
this.measurements.shift();
|
|
67
|
-
}
|
|
90
|
+
this.addMeasurement(session);
|
|
68
91
|
return this.analyzeSession(session);
|
|
69
92
|
}
|
|
70
93
|
/**
|
|
@@ -78,12 +101,12 @@ var PerformanceProfiler = class {
|
|
|
78
101
|
id: measurementId,
|
|
79
102
|
componentName,
|
|
80
103
|
props,
|
|
81
|
-
startTime:
|
|
104
|
+
startTime: now(),
|
|
82
105
|
startMemory: this.getMemoryUsage(),
|
|
83
106
|
phase: "render"
|
|
84
107
|
};
|
|
85
108
|
this.marks.set(measurementId, measurement);
|
|
86
|
-
if (
|
|
109
|
+
if (hasPerformanceTimeline()) {
|
|
87
110
|
performance.mark(`coherent-render-start-${measurementId}`);
|
|
88
111
|
}
|
|
89
112
|
return measurementId;
|
|
@@ -94,28 +117,21 @@ var PerformanceProfiler = class {
|
|
|
94
117
|
endRender(measurementId, result = {}) {
|
|
95
118
|
if (!measurementId || !this.marks.has(measurementId)) return null;
|
|
96
119
|
const measurement = this.marks.get(measurementId);
|
|
97
|
-
measurement.endTime =
|
|
120
|
+
measurement.endTime = now();
|
|
98
121
|
measurement.duration = measurement.endTime - measurement.startTime;
|
|
99
122
|
measurement.endMemory = this.getMemoryUsage();
|
|
100
|
-
measurement.memoryDelta = measurement.endMemory - measurement.startMemory;
|
|
123
|
+
measurement.memoryDelta = measurement.startMemory && measurement.endMemory ? measurement.endMemory.used - measurement.startMemory.used : null;
|
|
101
124
|
measurement.result = result;
|
|
102
125
|
measurement.slow = measurement.duration > this.options.slowThreshold;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
`coherent-render-start-${measurementId}`,
|
|
110
|
-
`coherent-render-end-${measurementId}`
|
|
111
|
-
);
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
this.measurements.push(measurement);
|
|
126
|
+
recordTimelineMeasure(
|
|
127
|
+
`coherent-render-${measurementId}`,
|
|
128
|
+
`coherent-render-start-${measurementId}`,
|
|
129
|
+
`coherent-render-end-${measurementId}`
|
|
130
|
+
);
|
|
131
|
+
this.addMeasurement(measurement);
|
|
117
132
|
if (this.currentSession) {
|
|
118
133
|
this.currentSession.measurements.push(measurement);
|
|
134
|
+
this.trim(this.currentSession.measurements);
|
|
119
135
|
}
|
|
120
136
|
this.marks.delete(measurementId);
|
|
121
137
|
return measurement;
|
|
@@ -126,15 +142,13 @@ var PerformanceProfiler = class {
|
|
|
126
142
|
mark(name, data = {}) {
|
|
127
143
|
const mark = {
|
|
128
144
|
name,
|
|
129
|
-
timestamp:
|
|
145
|
+
timestamp: now(),
|
|
130
146
|
data,
|
|
131
147
|
memory: this.getMemoryUsage()
|
|
132
148
|
};
|
|
133
149
|
if (this.currentSession) {
|
|
134
150
|
this.currentSession.marks.push(mark);
|
|
135
|
-
|
|
136
|
-
if (typeof performance !== "undefined" && performance.mark) {
|
|
137
|
-
performance.mark(`coherent-mark-${name}`);
|
|
151
|
+
this.trim(this.currentSession.marks);
|
|
138
152
|
}
|
|
139
153
|
return mark;
|
|
140
154
|
}
|
|
@@ -153,6 +167,22 @@ var PerformanceProfiler = class {
|
|
|
153
167
|
endMark: end.name
|
|
154
168
|
};
|
|
155
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Append a measurement, dropping the oldest beyond `maxSamples`.
|
|
172
|
+
*/
|
|
173
|
+
addMeasurement(measurement) {
|
|
174
|
+
this.measurements.push(measurement);
|
|
175
|
+
this.trim(this.measurements);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Drop the oldest entries of `list` beyond `maxSamples`.
|
|
179
|
+
*/
|
|
180
|
+
trim(list) {
|
|
181
|
+
const max = Math.max(1, Number(this.options.maxSamples) || 1e3);
|
|
182
|
+
if (list.length > max) {
|
|
183
|
+
list.splice(0, list.length - max);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
156
186
|
/**
|
|
157
187
|
* Get memory usage
|
|
158
188
|
*/
|
|
@@ -447,6 +477,10 @@ var PerformanceProfiler = class {
|
|
|
447
477
|
* Clear all data
|
|
448
478
|
*/
|
|
449
479
|
clear() {
|
|
480
|
+
clearTimelineEntries([
|
|
481
|
+
...[...this.marks.keys()].map((id) => `coherent-render-start-${id}`),
|
|
482
|
+
...[...this.sessions.values()].filter((session) => session.active).map((session) => `coherent-session-start-${session.id}`)
|
|
483
|
+
]);
|
|
450
484
|
this.measurements = [];
|
|
451
485
|
this.sessions.clear();
|
|
452
486
|
this.currentSession = null;
|
|
@@ -486,7 +520,7 @@ function createProfiler(options = {}) {
|
|
|
486
520
|
return new PerformanceProfiler(options);
|
|
487
521
|
}
|
|
488
522
|
async function measure(name, fn, profiler = null) {
|
|
489
|
-
const prof = profiler || new PerformanceProfiler();
|
|
523
|
+
const prof = profiler || new PerformanceProfiler({ enabled: true });
|
|
490
524
|
const sessionId = prof.start(name);
|
|
491
525
|
try {
|
|
492
526
|
const value = await fn();
|
|
@@ -494,14 +528,48 @@ async function measure(name, fn, profiler = null) {
|
|
|
494
528
|
return { value, duration: result?.duration || 0 };
|
|
495
529
|
} catch (error) {
|
|
496
530
|
const result = prof.stop(sessionId);
|
|
497
|
-
|
|
531
|
+
const failure = error instanceof Error ? error : new Error(`${name} failed: ${String(error)}`, { cause: error });
|
|
532
|
+
try {
|
|
533
|
+
failure.duration = result?.duration || 0;
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
throw failure;
|
|
498
537
|
}
|
|
499
538
|
}
|
|
500
|
-
function profile(fn) {
|
|
501
|
-
|
|
502
|
-
|
|
539
|
+
function profile(fn, options = {}) {
|
|
540
|
+
if (typeof fn !== "function") {
|
|
541
|
+
throw new TypeError("profile() expects a function");
|
|
542
|
+
}
|
|
543
|
+
const opts = options instanceof PerformanceProfiler ? { profiler: options } : options;
|
|
544
|
+
const profiler = opts.profiler || new PerformanceProfiler({ enabled: true });
|
|
545
|
+
const name = opts.name || fn.name || "anonymous";
|
|
546
|
+
function profiled(...args) {
|
|
547
|
+
const id = profiler.startRender(name);
|
|
548
|
+
let result;
|
|
549
|
+
try {
|
|
550
|
+
result = fn.apply(this, args);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
profiler.endRender(id, { error: true });
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
if (result && typeof result.then === "function") {
|
|
556
|
+
return Promise.resolve(result).then(
|
|
557
|
+
(value) => {
|
|
558
|
+
profiler.endRender(id);
|
|
559
|
+
return value;
|
|
560
|
+
},
|
|
561
|
+
(error) => {
|
|
562
|
+
profiler.endRender(id, { error: true });
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
profiler.endRender(id);
|
|
503
568
|
return result;
|
|
504
|
-
}
|
|
569
|
+
}
|
|
570
|
+
Object.defineProperty(profiled, "name", { value: name });
|
|
571
|
+
profiled.profiler = profiler;
|
|
572
|
+
return profiled;
|
|
505
573
|
}
|
|
506
574
|
var profiler_default = {
|
|
507
575
|
PerformanceProfiler,
|
package/dist/profiler.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/profiler.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Coherent.js Performance Profiler\n * \n * Tracks and analyzes rendering performance\n * \n * @module devtools/profiler\n */\n\n/**\n * Performance Profiler\n * Measures and analyzes component rendering performance\n */\nexport class PerformanceProfiler {\n constructor(options = {}) {\n this.options = {\n enabled: true,\n sampleRate: 1.0, // 1.0 = 100% sampling\n slowThreshold: 16, // 16ms = 60fps\n trackMemory: typeof performance !== 'undefined' && performance.memory,\n maxSamples: options.maxSamples || 1000,\n ...options\n };\n \n this.measurements = [];\n this.sessions = new Map();\n this.currentSession = null;\n this.marks = new Map();\n }\n\n /**\n * Start a profiling session\n */\n start(name = 'default') {\n if (!this.options.enabled) {\n return null;\n }\n\n // Apply sampling\n if (this.options.sampleRate < 1.0 && Math.random() > this.options.sampleRate) {\n return null;\n }\n\n const session = {\n id: this.generateId(),\n name,\n startTime: Date.now(),\n measurements: [],\n marks: [],\n active: true\n };\n\n this.sessions.set(session.id, session);\n this.currentSession = session;\n\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(`coherent-session-start-${session.id}`);\n }\n\n return session.id;\n }\n\n /**\n * Stop a profiling session\n */\n stop(sessionId) {\n if (!sessionId) {\n return null;\n }\n\n const session = this.sessions.get(sessionId);\n\n if (!session) {\n return null; // Gracefully handle non-existent sessions\n }\n\n session.endTime = Date.now();\n session.duration = session.endTime - session.startTime;\n session.active = false;\n\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(`coherent-session-end-${session.id}`);\n }\n\n if (this.currentSession === session) {\n this.currentSession = null;\n }\n\n // Store measurement\n this.measurements.push(session);\n \n // Limit measurements (maxSamples)\n if (this.measurements.length > this.options.maxSamples) {\n this.measurements.shift();\n }\n\n return this.analyzeSession(session);\n }\n\n /**\n * Start measuring a render\n */\n startRender(componentName, props = {}) {\n if (!this.options.enabled) return null;\n \n // Sample rate check\n if (Math.random() > this.options.sampleRate) return null;\n\n const measurementId = this.generateId();\n const measurement = {\n id: measurementId,\n componentName,\n props,\n startTime: Date.now(),\n startMemory: this.getMemoryUsage(),\n phase: 'render'\n };\n\n this.marks.set(measurementId, measurement);\n\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(`coherent-render-start-${measurementId}`);\n }\n\n return measurementId;\n }\n\n /**\n * End measuring a render\n */\n endRender(measurementId, result = {}) {\n if (!measurementId || !this.marks.has(measurementId)) return null;\n\n const measurement = this.marks.get(measurementId);\n measurement.endTime = Date.now();\n measurement.duration = measurement.endTime - measurement.startTime;\n measurement.endMemory = this.getMemoryUsage();\n measurement.memoryDelta = measurement.endMemory - measurement.startMemory;\n measurement.result = result;\n measurement.slow = measurement.duration > this.options.slowThreshold;\n\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(`coherent-render-end-${measurementId}`);\n \n if (performance.measure) {\n try {\n performance.measure(\n `coherent-render-${measurementId}`,\n `coherent-render-start-${measurementId}`,\n `coherent-render-end-${measurementId}`\n );\n } catch {\n // Ignore measure errors\n }\n }\n }\n\n // Add to measurements\n this.measurements.push(measurement);\n \n // Add to current session\n if (this.currentSession) {\n this.currentSession.measurements.push(measurement);\n }\n\n // Clean up\n this.marks.delete(measurementId);\n\n return measurement;\n }\n\n /**\n * Mark a point in time\n */\n mark(name, data = {}) {\n const mark = {\n name,\n timestamp: Date.now(),\n data,\n memory: this.getMemoryUsage()\n };\n\n if (this.currentSession) {\n this.currentSession.marks.push(mark);\n }\n\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(`coherent-mark-${name}`);\n }\n\n return mark;\n }\n\n /**\n * Measure time between two marks\n */\n measure(startMark, endMark) {\n const start = this.findMark(startMark);\n const end = this.findMark(endMark);\n\n if (!start || !end) {\n throw new Error('Mark not found');\n }\n\n return {\n duration: end.timestamp - start.timestamp,\n startMark: start.name,\n endMark: end.name\n };\n }\n\n /**\n * Get memory usage\n */\n getMemoryUsage() {\n if (typeof performance !== 'undefined' && performance.memory) {\n return {\n used: performance.memory.usedJSHeapSize,\n total: performance.memory.totalJSHeapSize,\n limit: performance.memory.jsHeapSizeLimit\n };\n }\n return null;\n }\n\n /**\n * Find a mark by name\n */\n findMark(name) {\n if (!this.currentSession) return null;\n return this.currentSession.marks.find(m => m.name === name);\n }\n\n /**\n * Get all measurements\n */\n getMeasurements(filter = {}) {\n let results = [...this.measurements];\n\n if (filter.componentName) {\n results = results.filter(m => m.componentName === filter.componentName);\n }\n\n if (filter.slow) {\n results = results.filter(m => m.slow);\n }\n\n if (filter.minDuration) {\n results = results.filter(m => m.duration >= filter.minDuration);\n }\n\n if (filter.limit) {\n results = results.slice(0, filter.limit);\n }\n\n return results;\n }\n\n /**\n * Analyze a session\n */\n analyzeSession(session) {\n const measurements = session.measurements;\n\n if (measurements.length === 0) {\n return {\n session: session.id,\n duration: session.duration,\n measurements: 0,\n analysis: null\n };\n }\n\n const durations = measurements.map(m => m.duration);\n const sorted = [...durations].sort((a, b) => a - b);\n\n return {\n session: session.id,\n name: session.name,\n duration: session.duration,\n measurements: measurements.length,\n analysis: {\n total: durations.reduce((a, b) => a + b, 0),\n average: durations.reduce((a, b) => a + b, 0) / durations.length,\n median: sorted[Math.floor(sorted.length / 2)],\n min: Math.min(...durations),\n max: Math.max(...durations),\n p95: sorted[Math.floor(sorted.length * 0.95)],\n p99: sorted[Math.floor(sorted.length * 0.99)],\n slowRenders: measurements.filter(m => m.slow).length,\n slowPercentage: (measurements.filter(m => m.slow).length / measurements.length) * 100\n },\n byComponent: this.groupByComponent(measurements),\n slowest: measurements\n .sort((a, b) => b.duration - a.duration)\n .slice(0, 10)\n .map(m => ({\n component: m.componentName,\n duration: m.duration,\n timestamp: m.startTime\n }))\n };\n }\n\n /**\n * Group measurements by component\n */\n groupByComponent(measurements) {\n const groups = {};\n\n measurements.forEach(m => {\n if (!groups[m.componentName]) {\n groups[m.componentName] = {\n count: 0,\n totalDuration: 0,\n durations: []\n };\n }\n\n groups[m.componentName].count++;\n groups[m.componentName].totalDuration += m.duration;\n groups[m.componentName].durations.push(m.duration);\n });\n\n // Calculate stats for each component\n Object.keys(groups).forEach(name => {\n const group = groups[name];\n group.average = group.totalDuration / group.count;\n group.min = Math.min(...group.durations);\n group.max = Math.max(...group.durations);\n });\n\n return groups;\n }\n\n /**\n * Get performance summary\n */\n getSummary() {\n const allMeasurements = this.measurements;\n\n if (allMeasurements.length === 0) {\n return {\n totalMeasurements: 0,\n totalSessions: this.sessions.size,\n analysis: null\n };\n }\n\n const durations = allMeasurements.map(m => m.duration);\n\n return {\n totalMeasurements: allMeasurements.length,\n totalSessions: this.sessions.size,\n slowRenders: allMeasurements.filter(m => m.slow).length,\n analysis: {\n average: durations.reduce((a, b) => a + b, 0) / durations.length,\n min: Math.min(...durations),\n max: Math.max(...durations),\n slowPercentage: (allMeasurements.filter(m => m.slow).length / allMeasurements.length) * 100\n },\n byComponent: this.groupByComponent(allMeasurements),\n recentSlow: allMeasurements\n .filter(m => m.slow)\n .slice(-10)\n .map(m => ({\n component: m.componentName,\n duration: m.duration,\n timestamp: m.startTime\n }))\n };\n }\n\n /**\n * Get statistics\n */\n getStatistics() {\n if (this.measurements.length === 0) {\n return { mean: 0, median: 0, min: 0, max: 0, stdDev: 0 };\n }\n\n const durations = this.measurements.map(m => m.duration);\n const sum = durations.reduce((a, b) => a + b, 0);\n const mean = sum / durations.length;\n \n const sorted = [...durations].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)];\n \n const variance = durations.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / durations.length;\n const stdDev = Math.sqrt(variance);\n\n return {\n mean,\n median,\n min: Math.min(...durations),\n max: Math.max(...durations),\n stdDev\n };\n }\n\n /**\n * Get bottlenecks\n */\n getBottlenecks(threshold = null) {\n const slowThreshold = threshold || this.options.slowThreshold;\n return this.measurements\n .filter(m => m.duration > slowThreshold)\n .sort((a, b) => b.duration - a.duration)\n .map(m => ({\n name: m.name,\n duration: m.duration,\n timestamp: m.startTime\n }));\n }\n\n /**\n * Get metrics\n */\n getMetrics() {\n const operationCounts = {};\n this.measurements.forEach(m => {\n operationCounts[m.name] = (operationCounts[m.name] || 0) + 1;\n });\n\n const totalDuration = this.measurements.reduce((sum, m) => sum + m.duration, 0);\n\n return {\n totalOperations: this.measurements.length,\n totalDuration,\n operationCounts,\n averageDuration: this.measurements.length > 0 ? totalDuration / this.measurements.length : 0,\n memoryUsage: this.options.trackMemory && typeof performance !== 'undefined' && performance.memory\n ? performance.memory.usedJSHeapSize\n : null\n };\n }\n\n /**\n * Generate report\n */\n generateReport() {\n const stats = this.getStatistics();\n const metrics = this.getMetrics();\n const bottlenecks = this.getBottlenecks();\n const recommendations = this.getRecommendations();\n\n return {\n summary: {\n totalOperations: metrics.totalOperations,\n averageDuration: metrics.averageDuration,\n slowOperations: bottlenecks.length\n },\n statistics: stats,\n operations: this.measurements.map(m => ({\n name: m.name,\n duration: m.duration,\n timestamp: m.startTime\n })),\n bottlenecks: bottlenecks.slice(0, 10),\n recommendations,\n timestamp: Date.now()\n };\n }\n\n /**\n * Export profiling data\n */\n export() {\n return {\n sessions: Array.from(this.sessions.values()),\n measurements: this.measurements,\n metrics: this.getMetrics(),\n statistics: this.getStatistics(),\n exportedAt: Date.now()\n };\n }\n\n /**\n * Format metrics for display\n */\n formatMetrics() {\n const metrics = this.getMetrics();\n const stats = this.getStatistics();\n \n let output = `Performance Metrics\\n`;\n output += `==================\\n`;\n output += `Total Operations: ${metrics.totalOperations}\\n`;\n output += `Average Duration: ${metrics.averageDuration.toFixed(2)}ms\\n`;\n output += `Mean: ${stats.mean.toFixed(2)}ms\\n`;\n output += `Median: ${stats.median.toFixed(2)}ms\\n`;\n output += `Min: ${stats.min.toFixed(2)}ms\\n`;\n output += `Max: ${stats.max.toFixed(2)}ms\\n`;\n \n return output;\n }\n\n /**\n * Compare two profiles\n */\n compare(profileId1, profileId2) {\n const session1 = this.sessions.get(profileId1);\n const session2 = this.sessions.get(profileId2);\n\n if (!session1 || !session2) {\n return null;\n }\n\n return {\n difference: session2.duration - session1.duration,\n percentChange: ((session2.duration - session1.duration) / session1.duration) * 100,\n profile1: { name: session1.name, duration: session1.duration },\n profile2: { name: session2.name, duration: session2.duration }\n };\n }\n\n /**\n * Get performance recommendations\n */\n getRecommendations() {\n const recommendations = [];\n const bottlenecks = this.getBottlenecks();\n const stats = this.getStatistics();\n\n if (bottlenecks.length > 0) {\n bottlenecks.slice(0, 5).forEach(bottleneck => {\n recommendations.push({\n type: 'bottleneck',\n operation: bottleneck.name,\n suggestion: `Optimize ${bottleneck.name} - duration: ${bottleneck.duration.toFixed(2)}ms exceeds threshold`,\n severity: 'high',\n message: `Found slow operation exceeding ${this.options.slowThreshold}ms`\n });\n });\n }\n\n if (stats.max > this.options.slowThreshold * 2) {\n recommendations.push({\n type: 'performance',\n operation: 'general',\n suggestion: `Review operations with high duration`,\n message: `Maximum duration (${stats.max.toFixed(2)}ms) is significantly high`,\n severity: 'medium'\n });\n }\n\n return recommendations;\n }\n\n /**\n * Clear all data\n */\n clear() {\n this.measurements = [];\n this.sessions.clear();\n this.currentSession = null;\n this.marks.clear();\n }\n\n /**\n * Enable profiler\n */\n enable() {\n this.options.enabled = true;\n }\n\n /**\n * Disable profiler\n */\n disable() {\n this.options.enabled = false;\n }\n\n /**\n * Generate unique ID.\n *\n * Uses crypto.getRandomValues rather than Math.random: the ids key the\n * session and measurement maps, so a predictable suffix lets one caller\n * guess or collide with another's entry. getRandomValues is available in\n * Node 19+ and in browsers without requiring a secure context, unlike\n * randomUUID.\n *\n * @returns {string} A unique profiling id\n */\n generateId() {\n const bytes = new Uint8Array(8);\n globalThis.crypto.getRandomValues(bytes);\n const suffix = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');\n return `prof-${Date.now()}-${suffix}`;\n }\n}\n\n/**\n * Create a performance profiler\n */\nexport function createProfiler(options = {}) {\n return new PerformanceProfiler(options);\n}\n\n/**\n * Measure a function execution\n */\nexport async function measure(name, fn, profiler = null) {\n const prof = profiler || new PerformanceProfiler();\n const sessionId = prof.start(name);\n \n try {\n const value = await fn();\n const result = prof.stop(sessionId);\n return { value, duration: result?.duration || 0 };\n } catch (error) {\n const result = prof.stop(sessionId);\n throw { error, duration: result?.duration || 0 };\n }\n}\n\n/**\n * Create a profiling decorator\n */\nexport function profile(fn) {\n return function(...args) {\n const result = fn(...args);\n return result;\n };\n}\n\nexport default {\n PerformanceProfiler,\n createProfiler,\n measure,\n profile\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Performance Profiler\n *\n * Tracks and analyzes rendering performance\n *\n * Timings come from performance.now() (sub-millisecond, monotonic), so\n * `startTime` / `endTime` are relative to the time origin, not epoch\n * milliseconds. A profiler records nothing until enabled.\n *\n * @module devtools/profiler\n */\n\nconst hasPerformanceTimeline = () =>\n typeof performance !== 'undefined' && typeof performance.mark === 'function';\n\n/** Monotonic high-resolution clock in milliseconds. */\nfunction now() {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now();\n}\n\n/** Remove entries this profiler added to the global performance timeline. */\nfunction clearTimelineEntries(marks, measureName) {\n if (!hasPerformanceTimeline()) return;\n for (const mark of marks) {\n performance.clearMarks?.(mark);\n }\n if (measureName) {\n performance.clearMeasures?.(measureName);\n }\n}\n\n/**\n * Add a performance.measure() for DevTools timelines, then clear it and its\n * marks so a long-running process does not accumulate timeline entries.\n */\nfunction recordTimelineMeasure(name, startMark, endMark) {\n if (!hasPerformanceTimeline()) return;\n try {\n performance.mark(endMark);\n performance.measure?.(name, startMark, endMark);\n } catch {\n // Ignore measure errors (e.g. the start mark was already cleared)\n } finally {\n clearTimelineEntries([startMark, endMark], name);\n }\n}\n\n/**\n * Performance Profiler\n * Measures and analyzes component rendering performance\n */\nexport class PerformanceProfiler {\n constructor(options = {}) {\n this.options = {\n // Opt-in: a profiler that is merely constructed must cost nothing.\n enabled: false,\n sampleRate: 1.0, // 1.0 = 100% sampling\n slowThreshold: 16, // 16ms = 60fps\n trackMemory: typeof performance !== 'undefined' && performance.memory,\n maxSamples: options.maxSamples || 1000,\n ...options\n };\n \n this.measurements = [];\n this.sessions = new Map();\n this.currentSession = null;\n this.marks = new Map();\n }\n\n /**\n * Start a profiling session\n */\n start(name = 'default') {\n if (!this.options.enabled) {\n return null;\n }\n\n // Apply sampling\n if (this.options.sampleRate < 1.0 && Math.random() > this.options.sampleRate) {\n return null;\n }\n\n const session = {\n id: this.generateId(),\n name,\n startTime: now(),\n measurements: [],\n marks: [],\n active: true\n };\n\n this.sessions.set(session.id, session);\n this.currentSession = session;\n\n if (hasPerformanceTimeline()) {\n performance.mark(`coherent-session-start-${session.id}`);\n }\n\n return session.id;\n }\n\n /**\n * Stop a profiling session\n */\n stop(sessionId) {\n if (!sessionId) {\n return null;\n }\n\n const session = this.sessions.get(sessionId);\n\n if (!session) {\n return null; // Gracefully handle non-existent sessions\n }\n\n session.endTime = now();\n session.duration = session.endTime - session.startTime;\n session.active = false;\n\n recordTimelineMeasure(\n `coherent-session-${session.id}`,\n `coherent-session-start-${session.id}`,\n `coherent-session-end-${session.id}`\n );\n\n if (this.currentSession === session) {\n this.currentSession = null;\n }\n\n // Store measurement\n this.addMeasurement(session);\n\n return this.analyzeSession(session);\n }\n\n /**\n * Start measuring a render\n */\n startRender(componentName, props = {}) {\n if (!this.options.enabled) return null;\n \n // Sample rate check\n if (Math.random() > this.options.sampleRate) return null;\n\n const measurementId = this.generateId();\n const measurement = {\n id: measurementId,\n componentName,\n props,\n startTime: now(),\n startMemory: this.getMemoryUsage(),\n phase: 'render'\n };\n\n this.marks.set(measurementId, measurement);\n\n if (hasPerformanceTimeline()) {\n performance.mark(`coherent-render-start-${measurementId}`);\n }\n\n return measurementId;\n }\n\n /**\n * End measuring a render\n */\n endRender(measurementId, result = {}) {\n if (!measurementId || !this.marks.has(measurementId)) return null;\n\n const measurement = this.marks.get(measurementId);\n measurement.endTime = now();\n measurement.duration = measurement.endTime - measurement.startTime;\n measurement.endMemory = this.getMemoryUsage();\n measurement.memoryDelta = measurement.startMemory && measurement.endMemory\n ? measurement.endMemory.used - measurement.startMemory.used\n : null;\n measurement.result = result;\n measurement.slow = measurement.duration > this.options.slowThreshold;\n\n recordTimelineMeasure(\n `coherent-render-${measurementId}`,\n `coherent-render-start-${measurementId}`,\n `coherent-render-end-${measurementId}`\n );\n\n // Add to measurements (bounded by maxSamples)\n this.addMeasurement(measurement);\n\n // Add to current session\n if (this.currentSession) {\n this.currentSession.measurements.push(measurement);\n this.trim(this.currentSession.measurements);\n }\n\n // Clean up\n this.marks.delete(measurementId);\n\n return measurement;\n }\n\n /**\n * Mark a point in time\n */\n mark(name, data = {}) {\n const mark = {\n name,\n timestamp: now(),\n data,\n memory: this.getMemoryUsage()\n };\n\n if (this.currentSession) {\n this.currentSession.marks.push(mark);\n this.trim(this.currentSession.marks);\n }\n\n return mark;\n }\n\n /**\n * Measure time between two marks\n */\n measure(startMark, endMark) {\n const start = this.findMark(startMark);\n const end = this.findMark(endMark);\n\n if (!start || !end) {\n throw new Error('Mark not found');\n }\n\n return {\n duration: end.timestamp - start.timestamp,\n startMark: start.name,\n endMark: end.name\n };\n }\n\n /**\n * Append a measurement, dropping the oldest beyond `maxSamples`.\n */\n addMeasurement(measurement) {\n this.measurements.push(measurement);\n this.trim(this.measurements);\n }\n\n /**\n * Drop the oldest entries of `list` beyond `maxSamples`.\n */\n trim(list) {\n const max = Math.max(1, Number(this.options.maxSamples) || 1000);\n if (list.length > max) {\n list.splice(0, list.length - max);\n }\n }\n\n /**\n * Get memory usage\n */\n getMemoryUsage() {\n if (typeof performance !== 'undefined' && performance.memory) {\n return {\n used: performance.memory.usedJSHeapSize,\n total: performance.memory.totalJSHeapSize,\n limit: performance.memory.jsHeapSizeLimit\n };\n }\n return null;\n }\n\n /**\n * Find a mark by name\n */\n findMark(name) {\n if (!this.currentSession) return null;\n return this.currentSession.marks.find(m => m.name === name);\n }\n\n /**\n * Get all measurements\n */\n getMeasurements(filter = {}) {\n let results = [...this.measurements];\n\n if (filter.componentName) {\n results = results.filter(m => m.componentName === filter.componentName);\n }\n\n if (filter.slow) {\n results = results.filter(m => m.slow);\n }\n\n if (filter.minDuration) {\n results = results.filter(m => m.duration >= filter.minDuration);\n }\n\n if (filter.limit) {\n results = results.slice(0, filter.limit);\n }\n\n return results;\n }\n\n /**\n * Analyze a session\n */\n analyzeSession(session) {\n const measurements = session.measurements;\n\n if (measurements.length === 0) {\n return {\n session: session.id,\n duration: session.duration,\n measurements: 0,\n analysis: null\n };\n }\n\n const durations = measurements.map(m => m.duration);\n const sorted = [...durations].sort((a, b) => a - b);\n\n return {\n session: session.id,\n name: session.name,\n duration: session.duration,\n measurements: measurements.length,\n analysis: {\n total: durations.reduce((a, b) => a + b, 0),\n average: durations.reduce((a, b) => a + b, 0) / durations.length,\n median: sorted[Math.floor(sorted.length / 2)],\n min: Math.min(...durations),\n max: Math.max(...durations),\n p95: sorted[Math.floor(sorted.length * 0.95)],\n p99: sorted[Math.floor(sorted.length * 0.99)],\n slowRenders: measurements.filter(m => m.slow).length,\n slowPercentage: (measurements.filter(m => m.slow).length / measurements.length) * 100\n },\n byComponent: this.groupByComponent(measurements),\n slowest: measurements\n .sort((a, b) => b.duration - a.duration)\n .slice(0, 10)\n .map(m => ({\n component: m.componentName,\n duration: m.duration,\n timestamp: m.startTime\n }))\n };\n }\n\n /**\n * Group measurements by component\n */\n groupByComponent(measurements) {\n const groups = {};\n\n measurements.forEach(m => {\n if (!groups[m.componentName]) {\n groups[m.componentName] = {\n count: 0,\n totalDuration: 0,\n durations: []\n };\n }\n\n groups[m.componentName].count++;\n groups[m.componentName].totalDuration += m.duration;\n groups[m.componentName].durations.push(m.duration);\n });\n\n // Calculate stats for each component\n Object.keys(groups).forEach(name => {\n const group = groups[name];\n group.average = group.totalDuration / group.count;\n group.min = Math.min(...group.durations);\n group.max = Math.max(...group.durations);\n });\n\n return groups;\n }\n\n /**\n * Get performance summary\n */\n getSummary() {\n const allMeasurements = this.measurements;\n\n if (allMeasurements.length === 0) {\n return {\n totalMeasurements: 0,\n totalSessions: this.sessions.size,\n analysis: null\n };\n }\n\n const durations = allMeasurements.map(m => m.duration);\n\n return {\n totalMeasurements: allMeasurements.length,\n totalSessions: this.sessions.size,\n slowRenders: allMeasurements.filter(m => m.slow).length,\n analysis: {\n average: durations.reduce((a, b) => a + b, 0) / durations.length,\n min: Math.min(...durations),\n max: Math.max(...durations),\n slowPercentage: (allMeasurements.filter(m => m.slow).length / allMeasurements.length) * 100\n },\n byComponent: this.groupByComponent(allMeasurements),\n recentSlow: allMeasurements\n .filter(m => m.slow)\n .slice(-10)\n .map(m => ({\n component: m.componentName,\n duration: m.duration,\n timestamp: m.startTime\n }))\n };\n }\n\n /**\n * Get statistics\n */\n getStatistics() {\n if (this.measurements.length === 0) {\n return { mean: 0, median: 0, min: 0, max: 0, stdDev: 0 };\n }\n\n const durations = this.measurements.map(m => m.duration);\n const sum = durations.reduce((a, b) => a + b, 0);\n const mean = sum / durations.length;\n \n const sorted = [...durations].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)];\n \n const variance = durations.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / durations.length;\n const stdDev = Math.sqrt(variance);\n\n return {\n mean,\n median,\n min: Math.min(...durations),\n max: Math.max(...durations),\n stdDev\n };\n }\n\n /**\n * Get bottlenecks\n */\n getBottlenecks(threshold = null) {\n const slowThreshold = threshold || this.options.slowThreshold;\n return this.measurements\n .filter(m => m.duration > slowThreshold)\n .sort((a, b) => b.duration - a.duration)\n .map(m => ({\n name: m.name,\n duration: m.duration,\n timestamp: m.startTime\n }));\n }\n\n /**\n * Get metrics\n */\n getMetrics() {\n const operationCounts = {};\n this.measurements.forEach(m => {\n operationCounts[m.name] = (operationCounts[m.name] || 0) + 1;\n });\n\n const totalDuration = this.measurements.reduce((sum, m) => sum + m.duration, 0);\n\n return {\n totalOperations: this.measurements.length,\n totalDuration,\n operationCounts,\n averageDuration: this.measurements.length > 0 ? totalDuration / this.measurements.length : 0,\n memoryUsage: this.options.trackMemory && typeof performance !== 'undefined' && performance.memory\n ? performance.memory.usedJSHeapSize\n : null\n };\n }\n\n /**\n * Generate report\n */\n generateReport() {\n const stats = this.getStatistics();\n const metrics = this.getMetrics();\n const bottlenecks = this.getBottlenecks();\n const recommendations = this.getRecommendations();\n\n return {\n summary: {\n totalOperations: metrics.totalOperations,\n averageDuration: metrics.averageDuration,\n slowOperations: bottlenecks.length\n },\n statistics: stats,\n operations: this.measurements.map(m => ({\n name: m.name,\n duration: m.duration,\n timestamp: m.startTime\n })),\n bottlenecks: bottlenecks.slice(0, 10),\n recommendations,\n timestamp: Date.now()\n };\n }\n\n /**\n * Export profiling data\n */\n export() {\n return {\n sessions: Array.from(this.sessions.values()),\n measurements: this.measurements,\n metrics: this.getMetrics(),\n statistics: this.getStatistics(),\n exportedAt: Date.now()\n };\n }\n\n /**\n * Format metrics for display\n */\n formatMetrics() {\n const metrics = this.getMetrics();\n const stats = this.getStatistics();\n \n let output = `Performance Metrics\\n`;\n output += `==================\\n`;\n output += `Total Operations: ${metrics.totalOperations}\\n`;\n output += `Average Duration: ${metrics.averageDuration.toFixed(2)}ms\\n`;\n output += `Mean: ${stats.mean.toFixed(2)}ms\\n`;\n output += `Median: ${stats.median.toFixed(2)}ms\\n`;\n output += `Min: ${stats.min.toFixed(2)}ms\\n`;\n output += `Max: ${stats.max.toFixed(2)}ms\\n`;\n \n return output;\n }\n\n /**\n * Compare two profiles\n */\n compare(profileId1, profileId2) {\n const session1 = this.sessions.get(profileId1);\n const session2 = this.sessions.get(profileId2);\n\n if (!session1 || !session2) {\n return null;\n }\n\n return {\n difference: session2.duration - session1.duration,\n percentChange: ((session2.duration - session1.duration) / session1.duration) * 100,\n profile1: { name: session1.name, duration: session1.duration },\n profile2: { name: session2.name, duration: session2.duration }\n };\n }\n\n /**\n * Get performance recommendations\n */\n getRecommendations() {\n const recommendations = [];\n const bottlenecks = this.getBottlenecks();\n const stats = this.getStatistics();\n\n if (bottlenecks.length > 0) {\n bottlenecks.slice(0, 5).forEach(bottleneck => {\n recommendations.push({\n type: 'bottleneck',\n operation: bottleneck.name,\n suggestion: `Optimize ${bottleneck.name} - duration: ${bottleneck.duration.toFixed(2)}ms exceeds threshold`,\n severity: 'high',\n message: `Found slow operation exceeding ${this.options.slowThreshold}ms`\n });\n });\n }\n\n if (stats.max > this.options.slowThreshold * 2) {\n recommendations.push({\n type: 'performance',\n operation: 'general',\n suggestion: `Review operations with high duration`,\n message: `Maximum duration (${stats.max.toFixed(2)}ms) is significantly high`,\n severity: 'medium'\n });\n }\n\n return recommendations;\n }\n\n /**\n * Clear all data\n */\n clear() {\n clearTimelineEntries([\n ...[...this.marks.keys()].map((id) => `coherent-render-start-${id}`),\n ...[...this.sessions.values()]\n .filter((session) => session.active)\n .map((session) => `coherent-session-start-${session.id}`)\n ]);\n this.measurements = [];\n this.sessions.clear();\n this.currentSession = null;\n this.marks.clear();\n }\n\n /**\n * Enable profiler\n */\n enable() {\n this.options.enabled = true;\n }\n\n /**\n * Disable profiler\n */\n disable() {\n this.options.enabled = false;\n }\n\n /**\n * Generate unique ID.\n *\n * Uses crypto.getRandomValues rather than Math.random: the ids key the\n * session and measurement maps, so a predictable suffix lets one caller\n * guess or collide with another's entry. getRandomValues is available in\n * Node 19+ and in browsers without requiring a secure context, unlike\n * randomUUID.\n *\n * @returns {string} A unique profiling id\n */\n generateId() {\n const bytes = new Uint8Array(8);\n globalThis.crypto.getRandomValues(bytes);\n const suffix = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');\n return `prof-${Date.now()}-${suffix}`;\n }\n}\n\n/**\n * Create a performance profiler\n */\nexport function createProfiler(options = {}) {\n return new PerformanceProfiler(options);\n}\n\n/**\n * Measure a function execution.\n *\n * Resolves with `{ value, duration }`. When `fn` throws, rejects with that\n * error (an Error \u2014 non-Error values are wrapped, with the original as\n * `cause`) carrying a `duration` property.\n */\nexport async function measure(name, fn, profiler = null) {\n // Measuring is the whole point of the call, so an ad-hoc profiler is enabled.\n const prof = profiler || new PerformanceProfiler({ enabled: true });\n const sessionId = prof.start(name);\n\n try {\n const value = await fn();\n const result = prof.stop(sessionId);\n return { value, duration: result?.duration || 0 };\n } catch (error) {\n const result = prof.stop(sessionId);\n const failure = error instanceof Error\n ? error\n : new Error(`${name} failed: ${String(error)}`, { cause: error });\n try {\n failure.duration = result?.duration || 0;\n } catch {\n // frozen error object: rethrow it as is\n }\n throw failure;\n }\n}\n\n/**\n * Wrap a function so every call is recorded as a render measurement.\n *\n * @param {Function} fn - Function to profile (sync or async).\n * @param {PerformanceProfiler|Object} [options] - A profiler, or\n * `{ profiler, name }`. Without a profiler an enabled one is created;\n * either way it is exposed as `wrapped.profiler`.\n * @returns {Function} The wrapper; it returns what `fn` returns.\n */\nexport function profile(fn, options = {}) {\n if (typeof fn !== 'function') {\n throw new TypeError('profile() expects a function');\n }\n const opts = options instanceof PerformanceProfiler ? { profiler: options } : options;\n const profiler = opts.profiler || new PerformanceProfiler({ enabled: true });\n const name = opts.name || fn.name || 'anonymous';\n\n function profiled(...args) {\n const id = profiler.startRender(name);\n let result;\n try {\n result = fn.apply(this, args);\n } catch (error) {\n profiler.endRender(id, { error: true });\n throw error;\n }\n if (result && typeof result.then === 'function') {\n return Promise.resolve(result).then(\n (value) => {\n profiler.endRender(id);\n return value;\n },\n (error) => {\n profiler.endRender(id, { error: true });\n throw error;\n }\n );\n }\n profiler.endRender(id);\n return result;\n }\n\n Object.defineProperty(profiled, 'name', { value: name });\n profiled.profiler = profiler;\n return profiled;\n}\n\nexport default {\n PerformanceProfiler,\n createProfiler,\n measure,\n profile\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/devtools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-rc.0",
|
|
4
4
|
"description": "Developer tools for Coherent.js applications - tree-shakable modular exports",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"author": "Coherent.js Team",
|
|
63
63
|
"license": "MIT",
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"@coherent.js/core": "^
|
|
65
|
+
"@coherent.js/core": "^2.0.0-rc.0"
|
|
66
66
|
},
|
|
67
67
|
"repository": {
|
|
68
68
|
"type": "git",
|
package/types/index.d.ts
CHANGED
|
@@ -288,7 +288,7 @@ export function validateComponent(component: unknown): boolean;
|
|
|
288
288
|
// ============================================================================
|
|
289
289
|
|
|
290
290
|
export interface ProfilerOptions {
|
|
291
|
-
/** Record anything at all; defaults to `
|
|
291
|
+
/** Record anything at all; defaults to `false` (opt in) */
|
|
292
292
|
enabled?: boolean;
|
|
293
293
|
/** Fraction of sessions and renders to record, 0 to 1; defaults to `1.0` */
|
|
294
294
|
sampleRate?: number;
|
|
@@ -307,7 +307,10 @@ export interface MemoryUsage {
|
|
|
307
307
|
limit: number;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
/**
|
|
310
|
+
/**
|
|
311
|
+
* One recorded render. Times are `performance.now()` milliseconds
|
|
312
|
+
* (sub-millisecond, relative to the time origin), not epoch timestamps.
|
|
313
|
+
*/
|
|
311
314
|
export interface RenderMeasurement {
|
|
312
315
|
id: string;
|
|
313
316
|
componentName: string;
|
|
@@ -317,7 +320,8 @@ export interface RenderMeasurement {
|
|
|
317
320
|
duration?: number;
|
|
318
321
|
startMemory: MemoryUsage | null;
|
|
319
322
|
endMemory?: MemoryUsage | null;
|
|
320
|
-
|
|
323
|
+
/** Change in used heap bytes, or `null` where heap usage is unavailable */
|
|
324
|
+
memoryDelta?: number | null;
|
|
321
325
|
phase: string;
|
|
322
326
|
result?: Record<string, unknown>;
|
|
323
327
|
/** Whether `duration` exceeded `slowThreshold` */
|
|
@@ -452,6 +456,9 @@ export class PerformanceProfiler {
|
|
|
452
456
|
/** Suggestions derived from the recorded measurements */
|
|
453
457
|
getRecommendations(): unknown[];
|
|
454
458
|
|
|
459
|
+
/** Append a measurement, dropping the oldest beyond `maxSamples` */
|
|
460
|
+
addMeasurement(measurement: RenderMeasurement | Record<string, unknown>): void;
|
|
461
|
+
|
|
455
462
|
/** Drop measurements, sessions and marks */
|
|
456
463
|
clear(): void;
|
|
457
464
|
|
|
@@ -465,7 +472,9 @@ export class PerformanceProfiler {
|
|
|
465
472
|
export function createProfiler(options?: ProfilerOptions): PerformanceProfiler;
|
|
466
473
|
|
|
467
474
|
/**
|
|
468
|
-
* Time
|
|
475
|
+
* Time a (possibly async) function with `profiler`, or an enabled ad-hoc one.
|
|
476
|
+
* When `fn` throws, rejects with that Error (non-Error values are wrapped,
|
|
477
|
+
* the original kept as `cause`) carrying a `duration` property.
|
|
469
478
|
*/
|
|
470
479
|
export function measure<T>(
|
|
471
480
|
name: string,
|
|
@@ -473,24 +482,65 @@ export function measure<T>(
|
|
|
473
482
|
profiler?: PerformanceProfiler | null
|
|
474
483
|
): Promise<{ value: T; duration: number }>;
|
|
475
484
|
|
|
476
|
-
|
|
477
|
-
|
|
485
|
+
export interface ProfileOptions {
|
|
486
|
+
/** Profiler to record into; an enabled one is created when omitted */
|
|
487
|
+
profiler?: PerformanceProfiler;
|
|
488
|
+
/** Measurement name; defaults to the function's name */
|
|
489
|
+
name?: string;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Wrap a function so every call (sync or async) is recorded as a render
|
|
494
|
+
* measurement on `wrapped.profiler`.
|
|
495
|
+
*/
|
|
496
|
+
export function profile<F extends (...args: never[]) => unknown>(
|
|
497
|
+
fn: F,
|
|
498
|
+
options?: PerformanceProfiler | ProfileOptions
|
|
499
|
+
): F & { profiler: PerformanceProfiler };
|
|
478
500
|
|
|
479
501
|
// ============================================================================
|
|
480
502
|
// DevTools
|
|
481
503
|
// ============================================================================
|
|
482
504
|
|
|
505
|
+
export interface DevToolsOptions {
|
|
506
|
+
/** Force on or off; defaults to `shouldEnable()` */
|
|
507
|
+
enabled?: boolean;
|
|
508
|
+
/** Cap on retained warnings and errors each; defaults to `100` */
|
|
509
|
+
maxEntries?: number;
|
|
510
|
+
/** Record console.error calls; defaults to `true` */
|
|
511
|
+
captureConsoleErrors?: boolean;
|
|
512
|
+
/**
|
|
513
|
+
* Record unhandled promise rejections (Node). They still crash the process
|
|
514
|
+
* as they would without DevTools. Defaults to `false`.
|
|
515
|
+
*/
|
|
516
|
+
trackUnhandledRejections?: boolean;
|
|
517
|
+
/** Browser only: hot-reload WebSocket URL; no connection is made without it */
|
|
518
|
+
hotReloadUrl?: string | null;
|
|
519
|
+
/** Expose `$inspect`, `$history`, … on `globalThis`; defaults to `true` */
|
|
520
|
+
globalHelpers?: boolean;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** The part of a Coherent instance DevTools uses, e.g. `import * as coherent from '@coherent.js/core'`. */
|
|
524
|
+
export interface DevToolsTarget {
|
|
525
|
+
render?: (component: unknown, context?: Record<string, unknown>, options?: Record<string, unknown>) => string;
|
|
526
|
+
createComponent?: (config: Record<string, unknown>) => unknown;
|
|
527
|
+
cache?: unknown;
|
|
528
|
+
}
|
|
529
|
+
|
|
483
530
|
/**
|
|
484
|
-
* Development-only instrumentation: render
|
|
531
|
+
* Development-only instrumentation: render timing, validation, optional hot
|
|
485
532
|
* reload and a browser panel.
|
|
486
533
|
*
|
|
487
|
-
* Enabled
|
|
488
|
-
*
|
|
534
|
+
* Enabled when `NODE_ENV=development`, or on a localhost page in a browser;
|
|
535
|
+
* anything else needs `{ enabled: true }`. It never mutates the instance it
|
|
536
|
+
* wraps — render through {@link DevTools.render}. `isEnabled` is a property,
|
|
537
|
+
* not a method.
|
|
489
538
|
*/
|
|
490
539
|
export class DevTools {
|
|
491
|
-
constructor(coherentInstance?:
|
|
540
|
+
constructor(coherentInstance?: DevToolsTarget | null, options?: DevToolsOptions);
|
|
492
541
|
|
|
493
|
-
coherent:
|
|
542
|
+
coherent: DevToolsTarget | null;
|
|
543
|
+
options: Required<Omit<DevToolsOptions, 'enabled' | 'hotReloadUrl'>> & DevToolsOptions;
|
|
494
544
|
/** Whether instrumentation is active in this environment */
|
|
495
545
|
isEnabled: boolean;
|
|
496
546
|
renderHistory: unknown[];
|
|
@@ -505,6 +555,18 @@ export class DevTools {
|
|
|
505
555
|
/** Install every hook; called by the constructor when enabled */
|
|
506
556
|
initialize(): void;
|
|
507
557
|
|
|
558
|
+
/** Remove everything `initialize()` installed */
|
|
559
|
+
destroy(): void;
|
|
560
|
+
|
|
561
|
+
/** Append to a bounded list (warnings, errors), dropping the oldest */
|
|
562
|
+
record<T>(list: T[], entry: T): T;
|
|
563
|
+
|
|
564
|
+
/** Render through the wrapped instance, recording timing and warnings */
|
|
565
|
+
render(component: unknown, context?: Record<string, unknown>, options?: Record<string, unknown>): string;
|
|
566
|
+
|
|
567
|
+
/** The wrapped instance's `createComponent()`, registering the result */
|
|
568
|
+
createComponent(config: Record<string, unknown>): unknown;
|
|
569
|
+
|
|
508
570
|
/** Report a component's type, structure and props */
|
|
509
571
|
inspectComponent(component: unknown): Record<string, unknown>;
|
|
510
572
|
|
|
@@ -537,7 +599,7 @@ export class DevTools {
|
|
|
537
599
|
}
|
|
538
600
|
|
|
539
601
|
/** Create a {@link DevTools} instance bound to a Coherent instance. */
|
|
540
|
-
export function createDevTools(coherentInstance?:
|
|
602
|
+
export function createDevTools(coherentInstance?: DevToolsTarget | null, options?: DevToolsOptions): DevTools;
|
|
541
603
|
|
|
542
604
|
// ============================================================================
|
|
543
605
|
// Component Visualizer
|