@sc4rfurryx/proteusjs 1.0.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/API.md +438 -0
- package/FEATURES.md +286 -0
- package/LICENSE +21 -0
- package/README.md +645 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/proteus.cjs.js +16014 -0
- package/dist/proteus.cjs.js.map +1 -0
- package/dist/proteus.d.ts +3018 -0
- package/dist/proteus.esm.js +16005 -0
- package/dist/proteus.esm.js.map +1 -0
- package/dist/proteus.esm.min.js +8 -0
- package/dist/proteus.esm.min.js.map +1 -0
- package/dist/proteus.js +16020 -0
- package/dist/proteus.js.map +1 -0
- package/dist/proteus.min.js +8 -0
- package/dist/proteus.min.js.map +1 -0
- package/package.json +98 -0
- package/src/__tests__/mvp-integration.test.ts +518 -0
- package/src/accessibility/AccessibilityEngine.ts +2106 -0
- package/src/accessibility/ScreenReaderSupport.ts +444 -0
- package/src/accessibility/__tests__/ScreenReaderSupport.test.ts +435 -0
- package/src/animations/FLIPAnimationSystem.ts +491 -0
- package/src/compatibility/BrowserCompatibility.ts +1076 -0
- package/src/containers/BreakpointSystem.ts +347 -0
- package/src/containers/ContainerBreakpoints.ts +726 -0
- package/src/containers/ContainerManager.ts +370 -0
- package/src/containers/ContainerUnits.ts +336 -0
- package/src/containers/ContextIsolation.ts +394 -0
- package/src/containers/ElementQueries.ts +411 -0
- package/src/containers/SmartContainer.ts +536 -0
- package/src/containers/SmartContainers.ts +376 -0
- package/src/containers/__tests__/ContainerBreakpoints.test.ts +411 -0
- package/src/containers/__tests__/SmartContainers.test.ts +281 -0
- package/src/content/ResponsiveImages.ts +570 -0
- package/src/core/EventSystem.ts +147 -0
- package/src/core/MemoryManager.ts +321 -0
- package/src/core/PerformanceMonitor.ts +238 -0
- package/src/core/PluginSystem.ts +275 -0
- package/src/core/ProteusJS.test.ts +164 -0
- package/src/core/ProteusJS.ts +962 -0
- package/src/developer/PerformanceProfiler.ts +567 -0
- package/src/developer/VisualDebuggingTools.ts +656 -0
- package/src/developer/ZeroConfigSystem.ts +593 -0
- package/src/index.ts +35 -0
- package/src/integration.test.ts +227 -0
- package/src/layout/AdaptiveGrid.ts +429 -0
- package/src/layout/ContentReordering.ts +532 -0
- package/src/layout/FlexboxEnhancer.ts +406 -0
- package/src/layout/FlowLayout.ts +545 -0
- package/src/layout/SpacingSystem.ts +512 -0
- package/src/observers/IntersectionObserverPolyfill.ts +289 -0
- package/src/observers/ObserverManager.ts +299 -0
- package/src/observers/ResizeObserverPolyfill.ts +179 -0
- package/src/performance/BatchDOMOperations.ts +519 -0
- package/src/performance/CSSOptimizationEngine.ts +646 -0
- package/src/performance/CacheOptimizationSystem.ts +601 -0
- package/src/performance/EfficientEventHandler.ts +740 -0
- package/src/performance/LazyEvaluationSystem.ts +532 -0
- package/src/performance/MemoryManagementSystem.ts +497 -0
- package/src/performance/PerformanceMonitor.ts +931 -0
- package/src/performance/__tests__/BatchDOMOperations.test.ts +309 -0
- package/src/performance/__tests__/EfficientEventHandler.test.ts +268 -0
- package/src/performance/__tests__/PerformanceMonitor.test.ts +422 -0
- package/src/polyfills/BrowserPolyfills.ts +586 -0
- package/src/polyfills/__tests__/BrowserPolyfills.test.ts +328 -0
- package/src/test/setup.ts +115 -0
- package/src/theming/SmartThemeSystem.ts +591 -0
- package/src/types/index.ts +134 -0
- package/src/typography/ClampScaling.ts +356 -0
- package/src/typography/FluidTypography.ts +759 -0
- package/src/typography/LineHeightOptimization.ts +430 -0
- package/src/typography/LineHeightOptimizer.ts +326 -0
- package/src/typography/TextFitting.ts +355 -0
- package/src/typography/TypographicScale.ts +428 -0
- package/src/typography/VerticalRhythm.ts +369 -0
- package/src/typography/__tests__/FluidTypography.test.ts +432 -0
- package/src/typography/__tests__/LineHeightOptimization.test.ts +436 -0
- package/src/utils/Logger.ts +173 -0
- package/src/utils/debounce.ts +259 -0
- package/src/utils/performance.ts +371 -0
- package/src/utils/support.ts +106 -0
- package/src/utils/version.ts +24 -0
@@ -0,0 +1,567 @@
|
|
1
|
+
/**
|
2
|
+
* Performance Profiler for ProteusJS
|
3
|
+
* Real-time performance monitoring with bottleneck detection and optimization suggestions
|
4
|
+
*/
|
5
|
+
|
6
|
+
export interface ProfilerConfig {
|
7
|
+
enableRealTimeMonitoring: boolean;
|
8
|
+
frameRateTarget: number;
|
9
|
+
memoryThreshold: number;
|
10
|
+
enableBottleneckDetection: boolean;
|
11
|
+
enableOptimizationSuggestions: boolean;
|
12
|
+
reportingInterval: number;
|
13
|
+
}
|
14
|
+
|
15
|
+
export interface PerformanceReport {
|
16
|
+
timestamp: number;
|
17
|
+
frameRate: FrameRateMetrics;
|
18
|
+
memory: MemoryMetrics;
|
19
|
+
timing: TimingMetrics;
|
20
|
+
bottlenecks: Bottleneck[];
|
21
|
+
suggestions: OptimizationSuggestion[];
|
22
|
+
score: number;
|
23
|
+
}
|
24
|
+
|
25
|
+
export interface FrameRateMetrics {
|
26
|
+
current: number;
|
27
|
+
average: number;
|
28
|
+
min: number;
|
29
|
+
max: number;
|
30
|
+
droppedFrames: number;
|
31
|
+
jankEvents: number;
|
32
|
+
}
|
33
|
+
|
34
|
+
export interface MemoryMetrics {
|
35
|
+
used: number;
|
36
|
+
total: number;
|
37
|
+
peak: number;
|
38
|
+
leaks: MemoryLeak[];
|
39
|
+
gcEvents: number;
|
40
|
+
}
|
41
|
+
|
42
|
+
export interface TimingMetrics {
|
43
|
+
domContentLoaded: number;
|
44
|
+
firstPaint: number;
|
45
|
+
firstContentfulPaint: number;
|
46
|
+
largestContentfulPaint: number;
|
47
|
+
cumulativeLayoutShift: number;
|
48
|
+
firstInputDelay: number;
|
49
|
+
}
|
50
|
+
|
51
|
+
export interface Bottleneck {
|
52
|
+
type: 'layout' | 'paint' | 'script' | 'memory' | 'network';
|
53
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
54
|
+
description: string;
|
55
|
+
element?: Element;
|
56
|
+
impact: number;
|
57
|
+
timestamp: number;
|
58
|
+
}
|
59
|
+
|
60
|
+
export interface OptimizationSuggestion {
|
61
|
+
category: 'performance' | 'memory' | 'accessibility' | 'best-practice';
|
62
|
+
priority: 'low' | 'medium' | 'high';
|
63
|
+
title: string;
|
64
|
+
description: string;
|
65
|
+
implementation: string;
|
66
|
+
estimatedImpact: number;
|
67
|
+
}
|
68
|
+
|
69
|
+
export interface MemoryLeak {
|
70
|
+
type: 'listener' | 'observer' | 'timer' | 'reference';
|
71
|
+
element?: Element;
|
72
|
+
description: string;
|
73
|
+
size: number;
|
74
|
+
}
|
75
|
+
|
76
|
+
export class PerformanceProfiler {
|
77
|
+
private config: Required<ProfilerConfig>;
|
78
|
+
private isActive: boolean = false;
|
79
|
+
private frameRateMonitor: FrameRateMonitor;
|
80
|
+
private memoryMonitor: MemoryMonitor;
|
81
|
+
private timingMonitor: TimingMonitor;
|
82
|
+
private bottleneckDetector: BottleneckDetector;
|
83
|
+
private optimizationEngine: OptimizationEngine;
|
84
|
+
private reportHistory: PerformanceReport[] = [];
|
85
|
+
|
86
|
+
constructor(config: Partial<ProfilerConfig> = {}) {
|
87
|
+
this.config = {
|
88
|
+
enableRealTimeMonitoring: true,
|
89
|
+
frameRateTarget: 60,
|
90
|
+
memoryThreshold: 100 * 1024 * 1024, // 100MB
|
91
|
+
enableBottleneckDetection: true,
|
92
|
+
enableOptimizationSuggestions: true,
|
93
|
+
reportingInterval: 5000, // 5 seconds
|
94
|
+
...config
|
95
|
+
};
|
96
|
+
|
97
|
+
this.frameRateMonitor = new FrameRateMonitor(this.config.frameRateTarget);
|
98
|
+
this.memoryMonitor = new MemoryMonitor(this.config.memoryThreshold);
|
99
|
+
this.timingMonitor = new TimingMonitor();
|
100
|
+
this.bottleneckDetector = new BottleneckDetector();
|
101
|
+
this.optimizationEngine = new OptimizationEngine();
|
102
|
+
}
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Start performance profiling
|
106
|
+
*/
|
107
|
+
public start(): void {
|
108
|
+
if (this.isActive) return;
|
109
|
+
|
110
|
+
this.isActive = true;
|
111
|
+
this.frameRateMonitor.start();
|
112
|
+
this.memoryMonitor.start();
|
113
|
+
this.timingMonitor.start();
|
114
|
+
|
115
|
+
if (this.config.enableBottleneckDetection) {
|
116
|
+
this.bottleneckDetector.start();
|
117
|
+
}
|
118
|
+
|
119
|
+
if (this.config.enableRealTimeMonitoring) {
|
120
|
+
this.startRealTimeReporting();
|
121
|
+
}
|
122
|
+
|
123
|
+
console.log('🔍 ProteusJS Performance Profiler Started');
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Stop performance profiling
|
128
|
+
*/
|
129
|
+
public stop(): void {
|
130
|
+
if (!this.isActive) return;
|
131
|
+
|
132
|
+
this.isActive = false;
|
133
|
+
this.frameRateMonitor.stop();
|
134
|
+
this.memoryMonitor.stop();
|
135
|
+
this.timingMonitor.stop();
|
136
|
+
this.bottleneckDetector.stop();
|
137
|
+
|
138
|
+
console.log('🔍 ProteusJS Performance Profiler Stopped');
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Generate performance report
|
143
|
+
*/
|
144
|
+
public generateReport(): PerformanceReport {
|
145
|
+
const report: PerformanceReport = {
|
146
|
+
timestamp: Date.now(),
|
147
|
+
frameRate: this.frameRateMonitor.getMetrics(),
|
148
|
+
memory: this.memoryMonitor.getMetrics(),
|
149
|
+
timing: this.timingMonitor.getMetrics(),
|
150
|
+
bottlenecks: this.bottleneckDetector.getBottlenecks(),
|
151
|
+
suggestions: this.optimizationEngine.getSuggestions(),
|
152
|
+
score: this.calculatePerformanceScore()
|
153
|
+
};
|
154
|
+
|
155
|
+
this.reportHistory.push(report);
|
156
|
+
|
157
|
+
// Keep only last 10 reports
|
158
|
+
if (this.reportHistory.length > 10) {
|
159
|
+
this.reportHistory.shift();
|
160
|
+
}
|
161
|
+
|
162
|
+
return report;
|
163
|
+
}
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Get optimization suggestions
|
167
|
+
*/
|
168
|
+
public getOptimizationSuggestions(): OptimizationSuggestion[] {
|
169
|
+
return this.optimizationEngine.getSuggestions();
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Start frame rate monitoring (alias for start)
|
174
|
+
*/
|
175
|
+
public startFrameRateMonitoring(): void {
|
176
|
+
this.start();
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Measure operation performance
|
181
|
+
*/
|
182
|
+
public async measureOperation<T>(name: string, operation: () => T | Promise<T>): Promise<{ result: T; duration: number; name: string }> {
|
183
|
+
const startTime = performance.now();
|
184
|
+
|
185
|
+
try {
|
186
|
+
const result = await operation();
|
187
|
+
const endTime = performance.now();
|
188
|
+
const duration = endTime - startTime;
|
189
|
+
|
190
|
+
return {
|
191
|
+
result,
|
192
|
+
duration,
|
193
|
+
name
|
194
|
+
};
|
195
|
+
} catch (error) {
|
196
|
+
const endTime = performance.now();
|
197
|
+
const duration = endTime - startTime;
|
198
|
+
|
199
|
+
// Still return timing info even if operation failed
|
200
|
+
throw {
|
201
|
+
error,
|
202
|
+
duration,
|
203
|
+
name
|
204
|
+
};
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Detect performance bottlenecks
|
210
|
+
*/
|
211
|
+
public detectBottlenecks(): Bottleneck[] {
|
212
|
+
return this.bottleneckDetector.getBottlenecks();
|
213
|
+
}
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Clean up resources
|
217
|
+
*/
|
218
|
+
public destroy(): void {
|
219
|
+
this.stop();
|
220
|
+
this.reportHistory = [];
|
221
|
+
}
|
222
|
+
|
223
|
+
/**
|
224
|
+
* Export detailed performance data
|
225
|
+
*/
|
226
|
+
public exportData(): string {
|
227
|
+
const data = {
|
228
|
+
config: this.config,
|
229
|
+
reports: this.reportHistory,
|
230
|
+
timestamp: Date.now(),
|
231
|
+
userAgent: navigator.userAgent,
|
232
|
+
viewport: {
|
233
|
+
width: window.innerWidth,
|
234
|
+
height: window.innerHeight
|
235
|
+
}
|
236
|
+
};
|
237
|
+
|
238
|
+
return JSON.stringify(data, null, 2);
|
239
|
+
}
|
240
|
+
|
241
|
+
/**
|
242
|
+
* Calculate overall performance score
|
243
|
+
*/
|
244
|
+
private calculatePerformanceScore(): number {
|
245
|
+
const frameRate = this.frameRateMonitor.getMetrics();
|
246
|
+
const memory = this.memoryMonitor.getMetrics();
|
247
|
+
const timing = this.timingMonitor.getMetrics();
|
248
|
+
const bottlenecks = this.bottleneckDetector.getBottlenecks();
|
249
|
+
|
250
|
+
let score = 100;
|
251
|
+
|
252
|
+
// Frame rate impact (40% of score)
|
253
|
+
const frameRateRatio = frameRate.average / this.config.frameRateTarget;
|
254
|
+
score -= (1 - Math.min(frameRateRatio, 1)) * 40;
|
255
|
+
|
256
|
+
// Memory impact (20% of score)
|
257
|
+
const memoryRatio = memory.used / this.config.memoryThreshold;
|
258
|
+
score -= Math.max(0, memoryRatio - 0.8) * 20;
|
259
|
+
|
260
|
+
// Timing impact (20% of score)
|
261
|
+
if (timing.largestContentfulPaint > 2500) score -= 10;
|
262
|
+
if (timing.cumulativeLayoutShift > 0.1) score -= 10;
|
263
|
+
|
264
|
+
// Bottlenecks impact (20% of score)
|
265
|
+
bottlenecks.forEach(bottleneck => {
|
266
|
+
const impact = {
|
267
|
+
low: 1,
|
268
|
+
medium: 3,
|
269
|
+
high: 5,
|
270
|
+
critical: 10
|
271
|
+
}[bottleneck.severity];
|
272
|
+
score -= impact;
|
273
|
+
});
|
274
|
+
|
275
|
+
return Math.max(0, Math.round(score));
|
276
|
+
}
|
277
|
+
|
278
|
+
/**
|
279
|
+
* Start real-time reporting
|
280
|
+
*/
|
281
|
+
private startRealTimeReporting(): void {
|
282
|
+
setInterval(() => {
|
283
|
+
if (this.isActive) {
|
284
|
+
const report = this.generateReport();
|
285
|
+
this.emitPerformanceUpdate(report);
|
286
|
+
}
|
287
|
+
}, this.config.reportingInterval);
|
288
|
+
}
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Emit performance update event
|
292
|
+
*/
|
293
|
+
private emitPerformanceUpdate(report: PerformanceReport): void {
|
294
|
+
const event = new CustomEvent('proteus:performance-update', {
|
295
|
+
detail: report
|
296
|
+
});
|
297
|
+
document.dispatchEvent(event);
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
/**
|
302
|
+
* Frame Rate Monitor
|
303
|
+
*/
|
304
|
+
class FrameRateMonitor {
|
305
|
+
private target: number;
|
306
|
+
private frames: number[] = [];
|
307
|
+
private lastTime: number = 0;
|
308
|
+
private rafId: number | null = null;
|
309
|
+
|
310
|
+
constructor(target: number) {
|
311
|
+
this.target = target;
|
312
|
+
}
|
313
|
+
|
314
|
+
start(): void {
|
315
|
+
this.lastTime = performance.now();
|
316
|
+
this.tick();
|
317
|
+
}
|
318
|
+
|
319
|
+
stop(): void {
|
320
|
+
if (this.rafId) {
|
321
|
+
cancelAnimationFrame(this.rafId);
|
322
|
+
this.rafId = null;
|
323
|
+
}
|
324
|
+
}
|
325
|
+
|
326
|
+
getMetrics(): FrameRateMetrics {
|
327
|
+
const current = this.frames.length > 0 ? this.frames[this.frames.length - 1]! : 0;
|
328
|
+
const average = this.frames.length > 0 ?
|
329
|
+
this.frames.reduce((a, b) => a + b, 0) / this.frames.length : 0;
|
330
|
+
const min = this.frames.length > 0 ? Math.min(...this.frames) : 0;
|
331
|
+
const max = this.frames.length > 0 ? Math.max(...this.frames) : 0;
|
332
|
+
const droppedFrames = this.frames.filter(fps => fps < this.target * 0.9).length;
|
333
|
+
const jankEvents = this.frames.filter(fps => fps < this.target * 0.5).length;
|
334
|
+
|
335
|
+
return { current, average, min, max, droppedFrames, jankEvents };
|
336
|
+
}
|
337
|
+
|
338
|
+
private tick = (): void => {
|
339
|
+
const currentTime = performance.now();
|
340
|
+
const deltaTime = currentTime - this.lastTime;
|
341
|
+
const fps = 1000 / deltaTime;
|
342
|
+
|
343
|
+
this.frames.push(fps);
|
344
|
+
|
345
|
+
// Keep only last 60 frames
|
346
|
+
if (this.frames.length > 60) {
|
347
|
+
this.frames.shift();
|
348
|
+
}
|
349
|
+
|
350
|
+
this.lastTime = currentTime;
|
351
|
+
this.rafId = requestAnimationFrame(this.tick);
|
352
|
+
};
|
353
|
+
}
|
354
|
+
|
355
|
+
/**
|
356
|
+
* Memory Monitor
|
357
|
+
*/
|
358
|
+
class MemoryMonitor {
|
359
|
+
private threshold: number;
|
360
|
+
private samples: number[] = [];
|
361
|
+
|
362
|
+
constructor(threshold: number) {
|
363
|
+
this.threshold = threshold;
|
364
|
+
}
|
365
|
+
|
366
|
+
start(): void {
|
367
|
+
setInterval(() => {
|
368
|
+
this.takeSample();
|
369
|
+
}, 1000);
|
370
|
+
}
|
371
|
+
|
372
|
+
stop(): void {
|
373
|
+
// Cleanup if needed
|
374
|
+
}
|
375
|
+
|
376
|
+
getMetrics(): MemoryMetrics {
|
377
|
+
const current = this.getCurrentMemoryUsage();
|
378
|
+
const peak = this.samples.length > 0 ? Math.max(...this.samples) : 0;
|
379
|
+
const leaks = this.detectMemoryLeaks();
|
380
|
+
|
381
|
+
return {
|
382
|
+
used: current,
|
383
|
+
total: this.threshold,
|
384
|
+
peak,
|
385
|
+
leaks,
|
386
|
+
gcEvents: 0 // Would need to be tracked separately
|
387
|
+
};
|
388
|
+
}
|
389
|
+
|
390
|
+
private takeSample(): void {
|
391
|
+
const usage = this.getCurrentMemoryUsage();
|
392
|
+
this.samples.push(usage);
|
393
|
+
|
394
|
+
// Keep only last 60 samples
|
395
|
+
if (this.samples.length > 60) {
|
396
|
+
this.samples.shift();
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
private getCurrentMemoryUsage(): number {
|
401
|
+
if ('memory' in performance) {
|
402
|
+
return (performance as any).memory.usedJSHeapSize;
|
403
|
+
}
|
404
|
+
return 0;
|
405
|
+
}
|
406
|
+
|
407
|
+
private detectMemoryLeaks(): MemoryLeak[] {
|
408
|
+
const leaks: MemoryLeak[] = [];
|
409
|
+
|
410
|
+
// Check for excessive event listeners
|
411
|
+
const elements = document.querySelectorAll('*');
|
412
|
+
elements.forEach(element => {
|
413
|
+
const listeners = (element as any)._listeners;
|
414
|
+
if (listeners && Object.keys(listeners).length > 10) {
|
415
|
+
leaks.push({
|
416
|
+
type: 'listener',
|
417
|
+
element,
|
418
|
+
description: `Element has ${Object.keys(listeners).length} event listeners`,
|
419
|
+
size: Object.keys(listeners).length * 100 // Estimate
|
420
|
+
});
|
421
|
+
}
|
422
|
+
});
|
423
|
+
|
424
|
+
return leaks;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
/**
|
429
|
+
* Timing Monitor
|
430
|
+
*/
|
431
|
+
class TimingMonitor {
|
432
|
+
start(): void {
|
433
|
+
// Monitor performance timing
|
434
|
+
}
|
435
|
+
|
436
|
+
stop(): void {
|
437
|
+
// Cleanup
|
438
|
+
}
|
439
|
+
|
440
|
+
getMetrics(): TimingMetrics {
|
441
|
+
const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
|
442
|
+
const paint = performance.getEntriesByType('paint');
|
443
|
+
|
444
|
+
return {
|
445
|
+
domContentLoaded: navigation?.domContentLoadedEventEnd - navigation?.domContentLoadedEventStart || 0,
|
446
|
+
firstPaint: paint.find(entry => entry.name === 'first-paint')?.startTime || 0,
|
447
|
+
firstContentfulPaint: paint.find(entry => entry.name === 'first-contentful-paint')?.startTime || 0,
|
448
|
+
largestContentfulPaint: 0, // Would need LCP observer
|
449
|
+
cumulativeLayoutShift: 0, // Would need CLS observer
|
450
|
+
firstInputDelay: 0 // Would need FID observer
|
451
|
+
};
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Bottleneck Detector
|
457
|
+
*/
|
458
|
+
class BottleneckDetector {
|
459
|
+
private bottlenecks: Bottleneck[] = [];
|
460
|
+
|
461
|
+
start(): void {
|
462
|
+
this.detectLayoutBottlenecks();
|
463
|
+
this.detectScriptBottlenecks();
|
464
|
+
this.detectMemoryBottlenecks();
|
465
|
+
}
|
466
|
+
|
467
|
+
stop(): void {
|
468
|
+
// Cleanup
|
469
|
+
}
|
470
|
+
|
471
|
+
getBottlenecks(): Bottleneck[] {
|
472
|
+
return [...this.bottlenecks];
|
473
|
+
}
|
474
|
+
|
475
|
+
private detectLayoutBottlenecks(): void {
|
476
|
+
// Detect elements that cause layout thrashing
|
477
|
+
const elements = document.querySelectorAll('*');
|
478
|
+
elements.forEach(element => {
|
479
|
+
const styles = window.getComputedStyle(element);
|
480
|
+
|
481
|
+
if (styles.position === 'fixed' && styles.transform !== 'none') {
|
482
|
+
this.bottlenecks.push({
|
483
|
+
type: 'layout',
|
484
|
+
severity: 'medium',
|
485
|
+
description: 'Fixed positioned element with transform may cause performance issues',
|
486
|
+
element,
|
487
|
+
impact: 3,
|
488
|
+
timestamp: Date.now()
|
489
|
+
});
|
490
|
+
}
|
491
|
+
});
|
492
|
+
}
|
493
|
+
|
494
|
+
private detectScriptBottlenecks(): void {
|
495
|
+
// Detect long-running scripts
|
496
|
+
const longTasks = performance.getEntriesByType('longtask');
|
497
|
+
longTasks.forEach(task => {
|
498
|
+
const duration = task.duration || 0;
|
499
|
+
if (duration > 50) {
|
500
|
+
this.bottlenecks.push({
|
501
|
+
type: 'script',
|
502
|
+
severity: duration > 100 ? 'high' : 'medium',
|
503
|
+
description: `Long task detected: ${duration.toFixed(2)}ms`,
|
504
|
+
impact: Math.round(duration / 10),
|
505
|
+
timestamp: Date.now()
|
506
|
+
});
|
507
|
+
}
|
508
|
+
});
|
509
|
+
}
|
510
|
+
|
511
|
+
private detectMemoryBottlenecks(): void {
|
512
|
+
// Detect memory-intensive operations
|
513
|
+
if ('memory' in performance) {
|
514
|
+
const memory = (performance as any).memory;
|
515
|
+
const usage = memory.usedJSHeapSize / memory.jsHeapSizeLimit;
|
516
|
+
|
517
|
+
if (usage > 0.8) {
|
518
|
+
this.bottlenecks.push({
|
519
|
+
type: 'memory',
|
520
|
+
severity: usage > 0.9 ? 'critical' : 'high',
|
521
|
+
description: `High memory usage: ${(usage * 100).toFixed(1)}%`,
|
522
|
+
impact: Math.round(usage * 10),
|
523
|
+
timestamp: Date.now()
|
524
|
+
});
|
525
|
+
}
|
526
|
+
}
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
/**
|
531
|
+
* Optimization Engine
|
532
|
+
*/
|
533
|
+
class OptimizationEngine {
|
534
|
+
getSuggestions(): OptimizationSuggestion[] {
|
535
|
+
const suggestions: OptimizationSuggestion[] = [];
|
536
|
+
|
537
|
+
// Analyze current performance and suggest optimizations
|
538
|
+
suggestions.push({
|
539
|
+
category: 'performance',
|
540
|
+
priority: 'high',
|
541
|
+
title: 'Enable will-change for animated elements',
|
542
|
+
description: 'Add will-change CSS property to elements that will be animated',
|
543
|
+
implementation: 'element.style.willChange = "transform";',
|
544
|
+
estimatedImpact: 15
|
545
|
+
});
|
546
|
+
|
547
|
+
suggestions.push({
|
548
|
+
category: 'memory',
|
549
|
+
priority: 'medium',
|
550
|
+
title: 'Implement lazy loading for images',
|
551
|
+
description: 'Add loading="lazy" to images below the fold',
|
552
|
+
implementation: 'img.setAttribute("loading", "lazy");',
|
553
|
+
estimatedImpact: 10
|
554
|
+
});
|
555
|
+
|
556
|
+
suggestions.push({
|
557
|
+
category: 'accessibility',
|
558
|
+
priority: 'high',
|
559
|
+
title: 'Add missing ARIA labels',
|
560
|
+
description: 'Ensure all interactive elements have proper ARIA labels',
|
561
|
+
implementation: 'button.setAttribute("aria-label", "Description");',
|
562
|
+
estimatedImpact: 5
|
563
|
+
});
|
564
|
+
|
565
|
+
return suggestions;
|
566
|
+
}
|
567
|
+
}
|