omgkit 2.2.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/plugin/skills/databases/database-management/SKILL.md +288 -0
  4. package/plugin/skills/databases/database-migration/SKILL.md +285 -0
  5. package/plugin/skills/databases/database-schema-design/SKILL.md +195 -0
  6. package/plugin/skills/databases/mongodb/SKILL.md +60 -776
  7. package/plugin/skills/databases/prisma/SKILL.md +53 -744
  8. package/plugin/skills/databases/redis/SKILL.md +53 -860
  9. package/plugin/skills/databases/supabase/SKILL.md +283 -0
  10. package/plugin/skills/devops/aws/SKILL.md +68 -672
  11. package/plugin/skills/devops/github-actions/SKILL.md +54 -657
  12. package/plugin/skills/devops/kubernetes/SKILL.md +67 -602
  13. package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
  14. package/plugin/skills/frameworks/django/SKILL.md +87 -853
  15. package/plugin/skills/frameworks/express/SKILL.md +95 -1301
  16. package/plugin/skills/frameworks/fastapi/SKILL.md +90 -1198
  17. package/plugin/skills/frameworks/laravel/SKILL.md +87 -1187
  18. package/plugin/skills/frameworks/nestjs/SKILL.md +106 -973
  19. package/plugin/skills/frameworks/react/SKILL.md +94 -962
  20. package/plugin/skills/frameworks/vue/SKILL.md +95 -1242
  21. package/plugin/skills/frontend/accessibility/SKILL.md +91 -1056
  22. package/plugin/skills/frontend/frontend-design/SKILL.md +69 -1262
  23. package/plugin/skills/frontend/responsive/SKILL.md +76 -799
  24. package/plugin/skills/frontend/shadcn-ui/SKILL.md +73 -921
  25. package/plugin/skills/frontend/tailwindcss/SKILL.md +60 -788
  26. package/plugin/skills/frontend/threejs/SKILL.md +72 -1266
  27. package/plugin/skills/languages/javascript/SKILL.md +106 -849
  28. package/plugin/skills/methodology/brainstorming/SKILL.md +70 -576
  29. package/plugin/skills/methodology/defense-in-depth/SKILL.md +79 -831
  30. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +81 -654
  31. package/plugin/skills/methodology/executing-plans/SKILL.md +86 -529
  32. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +95 -586
  33. package/plugin/skills/methodology/problem-solving/SKILL.md +67 -681
  34. package/plugin/skills/methodology/receiving-code-review/SKILL.md +70 -533
  35. package/plugin/skills/methodology/requesting-code-review/SKILL.md +70 -610
  36. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +70 -646
  37. package/plugin/skills/methodology/sequential-thinking/SKILL.md +70 -478
  38. package/plugin/skills/methodology/systematic-debugging/SKILL.md +66 -559
  39. package/plugin/skills/methodology/test-driven-development/SKILL.md +91 -752
  40. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +78 -687
  41. package/plugin/skills/methodology/token-optimization/SKILL.md +72 -602
  42. package/plugin/skills/methodology/verification-before-completion/SKILL.md +108 -529
  43. package/plugin/skills/methodology/writing-plans/SKILL.md +79 -566
  44. package/plugin/skills/omega/omega-architecture/SKILL.md +91 -752
  45. package/plugin/skills/omega/omega-coding/SKILL.md +161 -552
  46. package/plugin/skills/omega/omega-sprint/SKILL.md +132 -777
  47. package/plugin/skills/omega/omega-testing/SKILL.md +157 -845
  48. package/plugin/skills/omega/omega-thinking/SKILL.md +165 -606
  49. package/plugin/skills/security/better-auth/SKILL.md +46 -1034
  50. package/plugin/skills/security/oauth/SKILL.md +80 -934
  51. package/plugin/skills/security/owasp/SKILL.md +78 -862
  52. package/plugin/skills/testing/playwright/SKILL.md +77 -700
  53. package/plugin/skills/testing/pytest/SKILL.md +73 -811
  54. package/plugin/skills/testing/vitest/SKILL.md +60 -920
  55. package/plugin/skills/tools/document-processing/SKILL.md +111 -838
  56. package/plugin/skills/tools/image-processing/SKILL.md +126 -659
  57. package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
  58. package/plugin/skills/tools/media-processing/SKILL.md +118 -735
  59. package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
  60. package/plugin/skills/SKILL_STANDARDS.md +0 -743
@@ -1,905 +1,101 @@
1
1
  ---
2
- name: performance-profiling
3
- description: Browser automation, Chrome DevTools Protocol, Lighthouse audits, and Core Web Vitals optimization
2
+ name: profiling-performance
3
+ description: Performs browser performance profiling with Lighthouse, Core Web Vitals, and DevTools analysis. Use when auditing page performance, optimizing Core Web Vitals, analyzing bundle sizes, or implementing performance budgets.
4
4
  category: devops
5
5
  triggers:
6
- - performance profiling
7
- - lighthouse audit
6
+ - performance
7
+ - lighthouse
8
8
  - core web vitals
9
- - page speed
10
- - chrome devtools
11
- - performance optimization
12
- - bundle analysis
9
+ - bundle size
10
+ - profiling
13
11
  ---
14
12
 
15
- # Performance Profiling
13
+ # Profiling Performance
16
14
 
17
- Master **browser performance profiling** using Chrome DevTools Protocol, Lighthouse, and Core Web Vitals monitoring. This skill enables automated performance audits, bottleneck identification, and optimization guidance.
18
-
19
- ## Purpose
20
-
21
- Performance directly impacts user experience and business metrics:
22
-
23
- - Run automated Lighthouse audits with detailed analysis
24
- - Monitor Core Web Vitals (LCP, FID, CLS, INP)
25
- - Identify JavaScript performance bottlenecks
26
- - Analyze network waterfalls and resource loading
27
- - Detect memory leaks and optimize memory usage
28
- - Create performance budgets and regression testing
29
-
30
- ## Features
31
-
32
- ### 1. Lighthouse Automation
15
+ ## Quick Start
33
16
 
34
17
  ```typescript
18
+ // Run Lighthouse audit
35
19
  import lighthouse from 'lighthouse';
36
20
  import * as chromeLauncher from 'chrome-launcher';
37
21
 
38
- interface LighthouseConfig {
39
- url: string;
40
- categories?: ('performance' | 'accessibility' | 'best-practices' | 'seo')[];
41
- device?: 'mobile' | 'desktop';
42
- throttling?: ThrottlingConfig;
43
- }
44
-
45
- interface LighthouseResult {
46
- scores: Record<string, number>;
47
- metrics: PerformanceMetrics;
48
- opportunities: Opportunity[];
49
- diagnostics: Diagnostic[];
50
- }
51
-
52
- // Run Lighthouse audit
53
- async function runLighthouseAudit(config: LighthouseConfig): Promise<LighthouseResult> {
22
+ async function audit(url: string) {
54
23
  const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });
55
-
56
- try {
57
- const options = {
58
- port: chrome.port,
59
- output: 'json',
60
- onlyCategories: config.categories || ['performance'],
61
- formFactor: config.device || 'mobile',
62
- throttling: config.throttling || {
63
- rttMs: 150,
64
- throughputKbps: 1638,
65
- cpuSlowdownMultiplier: 4,
66
- },
67
- };
68
-
69
- const result = await lighthouse(config.url, options);
70
- const lhr = result?.lhr;
71
-
72
- if (!lhr) throw new Error('Lighthouse failed to generate report');
73
-
74
- return {
75
- scores: {
76
- performance: lhr.categories.performance?.score ?? 0,
77
- accessibility: lhr.categories.accessibility?.score ?? 0,
78
- bestPractices: lhr.categories['best-practices']?.score ?? 0,
79
- seo: lhr.categories.seo?.score ?? 0,
80
- },
81
- metrics: extractMetrics(lhr),
82
- opportunities: extractOpportunities(lhr),
83
- diagnostics: extractDiagnostics(lhr),
84
- };
85
- } finally {
86
- await chrome.kill();
87
- }
88
- }
89
-
90
- // Extract key metrics
91
- function extractMetrics(lhr: LH.Result): PerformanceMetrics {
92
- const audits = lhr.audits;
93
-
94
- return {
95
- // Core Web Vitals
96
- lcp: {
97
- value: audits['largest-contentful-paint']?.numericValue ?? 0,
98
- score: audits['largest-contentful-paint']?.score ?? 0,
99
- displayValue: audits['largest-contentful-paint']?.displayValue ?? '',
100
- },
101
- fid: {
102
- value: audits['max-potential-fid']?.numericValue ?? 0,
103
- score: audits['max-potential-fid']?.score ?? 0,
104
- displayValue: audits['max-potential-fid']?.displayValue ?? '',
105
- },
106
- cls: {
107
- value: audits['cumulative-layout-shift']?.numericValue ?? 0,
108
- score: audits['cumulative-layout-shift']?.score ?? 0,
109
- displayValue: audits['cumulative-layout-shift']?.displayValue ?? '',
110
- },
111
-
112
- // Additional metrics
113
- fcp: audits['first-contentful-paint']?.numericValue ?? 0,
114
- ttfb: audits['server-response-time']?.numericValue ?? 0,
115
- tti: audits['interactive']?.numericValue ?? 0,
116
- tbt: audits['total-blocking-time']?.numericValue ?? 0,
117
- speedIndex: audits['speed-index']?.numericValue ?? 0,
118
- };
119
- }
120
-
121
- // Extract optimization opportunities
122
- function extractOpportunities(lhr: LH.Result): Opportunity[] {
123
- const opportunityAudits = [
124
- 'render-blocking-resources',
125
- 'unused-css-rules',
126
- 'unused-javascript',
127
- 'modern-image-formats',
128
- 'offscreen-images',
129
- 'unminified-css',
130
- 'unminified-javascript',
131
- 'efficient-animated-content',
132
- 'duplicated-javascript',
133
- ];
134
-
135
- return opportunityAudits
136
- .map(id => lhr.audits[id])
137
- .filter(audit => audit && audit.score !== null && audit.score < 1)
138
- .map(audit => ({
139
- id: audit.id,
140
- title: audit.title,
141
- description: audit.description,
142
- savings: audit.details?.overallSavingsMs ?? 0,
143
- items: audit.details?.items ?? [],
144
- }))
145
- .sort((a, b) => b.savings - a.savings);
24
+ const result = await lighthouse(url, { port: chrome.port, onlyCategories: ['performance'] });
25
+ await chrome.kill();
26
+ return result?.lhr;
146
27
  }
147
28
  ```
148
29
 
149
- ### 2. Core Web Vitals Monitoring
150
-
151
- ```typescript
152
- import { onLCP, onFID, onCLS, onINP, onTTFB } from 'web-vitals';
153
-
154
- interface WebVitalsReport {
155
- lcp: VitalMetric;
156
- fid: VitalMetric;
157
- cls: VitalMetric;
158
- inp: VitalMetric;
159
- ttfb: VitalMetric;
160
- }
161
-
162
- interface VitalMetric {
163
- value: number;
164
- rating: 'good' | 'needs-improvement' | 'poor';
165
- entries: PerformanceEntry[];
166
- }
167
-
168
- // Real User Monitoring (RUM) setup
169
- function initWebVitalsMonitoring(onReport: (report: WebVitalsReport) => void): void {
170
- const metrics: Partial<WebVitalsReport> = {};
171
-
172
- const reportIfComplete = () => {
173
- if (metrics.lcp && metrics.fid && metrics.cls && metrics.inp && metrics.ttfb) {
174
- onReport(metrics as WebVitalsReport);
175
- }
176
- };
177
-
178
- onLCP((metric) => {
179
- metrics.lcp = {
180
- value: metric.value,
181
- rating: metric.rating,
182
- entries: metric.entries,
183
- };
184
- reportIfComplete();
185
- });
186
-
187
- onFID((metric) => {
188
- metrics.fid = {
189
- value: metric.value,
190
- rating: metric.rating,
191
- entries: metric.entries,
192
- };
193
- reportIfComplete();
194
- });
195
-
196
- onCLS((metric) => {
197
- metrics.cls = {
198
- value: metric.value,
199
- rating: metric.rating,
200
- entries: metric.entries,
201
- };
202
- reportIfComplete();
203
- });
204
-
205
- onINP((metric) => {
206
- metrics.inp = {
207
- value: metric.value,
208
- rating: metric.rating,
209
- entries: metric.entries,
210
- };
211
- reportIfComplete();
212
- });
213
-
214
- onTTFB((metric) => {
215
- metrics.ttfb = {
216
- value: metric.value,
217
- rating: metric.rating,
218
- entries: metric.entries,
219
- };
220
- reportIfComplete();
221
- });
222
- }
223
-
224
- // Web Vitals thresholds
225
- const WEB_VITALS_THRESHOLDS = {
226
- LCP: { good: 2500, poor: 4000 }, // milliseconds
227
- FID: { good: 100, poor: 300 }, // milliseconds
228
- CLS: { good: 0.1, poor: 0.25 }, // score
229
- INP: { good: 200, poor: 500 }, // milliseconds
230
- TTFB: { good: 800, poor: 1800 }, // milliseconds
231
- };
232
-
233
- // Analyze and provide recommendations
234
- function analyzeWebVitals(report: WebVitalsReport): VitalsAnalysis {
235
- const issues: VitalIssue[] = [];
236
-
237
- // LCP analysis
238
- if (report.lcp.rating !== 'good') {
239
- const lcpElement = report.lcp.entries[0]?.element;
240
- issues.push({
241
- metric: 'LCP',
242
- value: report.lcp.value,
243
- rating: report.lcp.rating,
244
- element: lcpElement,
245
- recommendations: getLCPRecommendations(report.lcp, lcpElement),
246
- });
247
- }
248
-
249
- // CLS analysis
250
- if (report.cls.rating !== 'good') {
251
- const clsSources = report.cls.entries.flatMap(
252
- entry => (entry as LayoutShift).sources || []
253
- );
254
- issues.push({
255
- metric: 'CLS',
256
- value: report.cls.value,
257
- rating: report.cls.rating,
258
- sources: clsSources,
259
- recommendations: getCLSRecommendations(clsSources),
260
- });
261
- }
262
-
263
- // INP analysis
264
- if (report.inp.rating !== 'good') {
265
- issues.push({
266
- metric: 'INP',
267
- value: report.inp.value,
268
- rating: report.inp.rating,
269
- recommendations: getINPRecommendations(report.inp),
270
- });
271
- }
272
-
273
- return {
274
- overallRating: calculateOverallRating(report),
275
- issues,
276
- score: calculateVitalsScore(report),
277
- };
278
- }
279
-
280
- // LCP optimization recommendations
281
- function getLCPRecommendations(metric: VitalMetric, element?: Element): string[] {
282
- const recommendations: string[] = [];
283
-
284
- if (element?.tagName === 'IMG') {
285
- recommendations.push(
286
- 'Add fetchpriority="high" to the LCP image',
287
- 'Preload the LCP image: <link rel="preload" as="image" href="...">',
288
- 'Use modern image formats (WebP, AVIF)',
289
- 'Ensure image is properly sized (no layout shift)',
290
- );
291
- }
292
-
293
- if (metric.value > 4000) {
294
- recommendations.push(
295
- 'Reduce server response time (TTFB)',
296
- 'Eliminate render-blocking resources',
297
- 'Consider server-side rendering for critical content',
298
- );
299
- }
300
-
301
- recommendations.push(
302
- 'Minimize critical CSS',
303
- 'Use efficient cache policy for static assets',
304
- 'Consider using a CDN',
305
- );
306
-
307
- return recommendations;
308
- }
30
+ ```bash
31
+ # CLI audit
32
+ npx lighthouse https://example.com --output=json --output-path=./report.json
309
33
  ```
310
34
 
311
- ### 3. Chrome DevTools Protocol
312
-
313
- ```typescript
314
- import CDP from 'chrome-remote-interface';
315
-
316
- interface PerformanceTrace {
317
- timelineEvents: TimelineEvent[];
318
- networkRequests: NetworkRequest[];
319
- jsProfile: CPUProfile;
320
- heapSnapshot: HeapSnapshot;
321
- }
322
-
323
- // Connect to Chrome DevTools
324
- async function connectToDevTools(port: number = 9222): Promise<CDP.Client> {
325
- const client = await CDP({ port });
326
-
327
- // Enable required domains
328
- await Promise.all([
329
- client.Page.enable(),
330
- client.Network.enable(),
331
- client.Performance.enable(),
332
- client.Profiler.enable(),
333
- client.HeapProfiler.enable(),
334
- ]);
335
-
336
- return client;
337
- }
338
-
339
- // Capture performance trace
340
- async function capturePerformanceTrace(
341
- client: CDP.Client,
342
- url: string
343
- ): Promise<PerformanceTrace> {
344
- const networkRequests: NetworkRequest[] = [];
345
- const timelineEvents: TimelineEvent[] = [];
346
-
347
- // Collect network requests
348
- client.Network.requestWillBeSent(params => {
349
- networkRequests.push({
350
- requestId: params.requestId,
351
- url: params.request.url,
352
- method: params.request.method,
353
- timestamp: params.timestamp,
354
- type: params.type,
355
- });
356
- });
357
-
358
- client.Network.responseReceived(params => {
359
- const request = networkRequests.find(r => r.requestId === params.requestId);
360
- if (request) {
361
- request.status = params.response.status;
362
- request.mimeType = params.response.mimeType;
363
- request.encodedDataLength = params.response.encodedDataLength;
364
- }
365
- });
366
-
367
- // Start tracing
368
- await client.Tracing.start({
369
- categories: [
370
- 'devtools.timeline',
371
- 'v8.execute',
372
- 'blink.user_timing',
373
- 'loading',
374
- 'painting',
375
- ].join(','),
376
- });
377
-
378
- // Navigate to page
379
- await client.Page.navigate({ url });
380
- await client.Page.loadEventFired();
381
-
382
- // Wait for network idle
383
- await waitForNetworkIdle(client);
384
-
385
- // Stop tracing
386
- const { value: traceData } = await client.Tracing.tracingComplete();
387
-
388
- // Capture JS profile
389
- await client.Profiler.start();
390
- await new Promise(r => setTimeout(r, 2000)); // Profile for 2 seconds
391
- const { profile: jsProfile } = await client.Profiler.stop();
392
-
393
- // Capture heap snapshot
394
- const heapChunks: string[] = [];
395
- client.HeapProfiler.addHeapSnapshotChunk(({ chunk }) => heapChunks.push(chunk));
396
- await client.HeapProfiler.takeHeapSnapshot();
397
- const heapSnapshot = JSON.parse(heapChunks.join(''));
398
-
399
- return {
400
- timelineEvents: parseTraceData(traceData),
401
- networkRequests,
402
- jsProfile,
403
- heapSnapshot,
404
- };
405
- }
406
-
407
- // Analyze network waterfall
408
- function analyzeNetworkWaterfall(requests: NetworkRequest[]): WaterfallAnalysis {
409
- const sorted = [...requests].sort((a, b) => a.timestamp - b.timestamp);
410
- const totalTime = sorted[sorted.length - 1]?.endTime - sorted[0]?.timestamp;
411
-
412
- // Identify critical path
413
- const criticalPath = sorted.filter(r =>
414
- r.type === 'Document' ||
415
- (r.type === 'Script' && !r.url.includes('async')) ||
416
- r.type === 'Stylesheet'
417
- );
418
-
419
- // Find blocking resources
420
- const blockingResources = sorted.filter(r =>
421
- r.renderBlocking ||
422
- (r.type === 'Script' && !r.async && !r.defer)
423
- );
424
-
425
- // Calculate metrics
426
- return {
427
- totalRequests: requests.length,
428
- totalTime,
429
- totalSize: requests.reduce((sum, r) => sum + (r.encodedDataLength || 0), 0),
430
- criticalPath,
431
- blockingResources,
432
- byType: groupByType(requests),
433
- recommendations: generateWaterfallRecommendations(requests),
434
- };
435
- }
436
-
437
- // Memory leak detection
438
- async function detectMemoryLeaks(
439
- client: CDP.Client,
440
- actions: () => Promise<void>,
441
- iterations: number = 3
442
- ): Promise<MemoryLeakReport> {
443
- const snapshots: HeapSnapshot[] = [];
444
-
445
- // Take initial snapshot
446
- snapshots.push(await takeHeapSnapshot(client));
35
+ ## Features
447
36
 
448
- // Perform actions multiple times
449
- for (let i = 0; i < iterations; i++) {
450
- await actions();
451
- await client.HeapProfiler.collectGarbage();
452
- await new Promise(r => setTimeout(r, 100));
453
- snapshots.push(await takeHeapSnapshot(client));
454
- }
37
+ | Feature | Description | Guide |
38
+ |---------|-------------|-------|
39
+ | Lighthouse Audits | Automated performance scoring | Run in CI/CD, track scores over time |
40
+ | Core Web Vitals | LCP, FID, CLS, INP metrics | Monitor with web-vitals library |
41
+ | Bundle Analysis | JavaScript bundle size inspection | Use webpack-bundle-analyzer or rollup-plugin-visualizer |
42
+ | Network Waterfall | Request timing and blocking analysis | Identify render-blocking resources |
43
+ | Memory Profiling | Heap snapshots and leak detection | Compare snapshots before/after operations |
44
+ | Performance Budgets | Automated regression prevention | Set thresholds in CI pipeline |
455
45
 
456
- // Analyze heap growth
457
- const heapGrowth = analyzeHeapGrowth(snapshots);
458
- const retainedObjects = findRetainedObjects(snapshots);
46
+ ## Common Patterns
459
47
 
460
- return {
461
- hasLeak: heapGrowth.trend === 'increasing',
462
- heapGrowth,
463
- retainedObjects,
464
- recommendations: generateMemoryRecommendations(retainedObjects),
465
- };
466
- }
467
- ```
468
-
469
- ### 4. Bundle Analysis
48
+ ### Core Web Vitals Monitoring
470
49
 
471
50
  ```typescript
472
- import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
473
- import { visualizer } from 'rollup-plugin-visualizer';
474
-
475
- interface BundleAnalysis {
476
- totalSize: number;
477
- gzipSize: number;
478
- modules: ModuleInfo[];
479
- duplicates: DuplicateModule[];
480
- largestModules: ModuleInfo[];
481
- recommendations: string[];
482
- }
483
-
484
- // Webpack bundle analysis
485
- function createBundleAnalyzerConfig(): BundleAnalyzerPlugin {
486
- return new BundleAnalyzerPlugin({
487
- analyzerMode: 'json',
488
- reportFilename: 'bundle-report.json',
489
- generateStatsFile: true,
490
- statsFilename: 'bundle-stats.json',
491
- });
492
- }
493
-
494
- // Analyze bundle stats
495
- async function analyzeBundleStats(statsPath: string): Promise<BundleAnalysis> {
496
- const stats = JSON.parse(await fs.readFile(statsPath, 'utf-8'));
497
-
498
- const modules = flattenModules(stats.modules);
499
- const duplicates = findDuplicates(modules);
51
+ import { onLCP, onFID, onCLS, onINP } from 'web-vitals';
500
52
 
501
- // Calculate sizes
502
- const totalSize = modules.reduce((sum, m) => sum + m.size, 0);
503
- const gzipSize = await calculateGzipSize(statsPath);
504
-
505
- // Sort by size
506
- const largestModules = [...modules]
507
- .sort((a, b) => b.size - a.size)
508
- .slice(0, 20);
509
-
510
- return {
511
- totalSize,
512
- gzipSize,
513
- modules,
514
- duplicates,
515
- largestModules,
516
- recommendations: generateBundleRecommendations({
517
- totalSize,
518
- duplicates,
519
- largestModules,
520
- }),
521
- };
522
- }
523
-
524
- // Find duplicate modules
525
- function findDuplicates(modules: ModuleInfo[]): DuplicateModule[] {
526
- const modulesByName = new Map<string, ModuleInfo[]>();
527
-
528
- for (const module of modules) {
529
- const name = getModuleName(module.identifier);
530
- const existing = modulesByName.get(name) || [];
531
- existing.push(module);
532
- modulesByName.set(name, existing);
533
- }
534
-
535
- return Array.from(modulesByName.entries())
536
- .filter(([_, instances]) => instances.length > 1)
537
- .map(([name, instances]) => ({
538
- name,
539
- instances: instances.length,
540
- totalSize: instances.reduce((sum, m) => sum + m.size, 0),
541
- versions: [...new Set(instances.map(m => getModuleVersion(m.identifier)))],
542
- }))
543
- .sort((a, b) => b.totalSize - a.totalSize);
53
+ function sendToAnalytics(metric: { name: string; value: number; rating: string }) {
54
+ analytics.track('web_vital', metric);
544
55
  }
545
56
 
546
- // Generate bundle recommendations
547
- function generateBundleRecommendations(analysis: {
548
- totalSize: number;
549
- duplicates: DuplicateModule[];
550
- largestModules: ModuleInfo[];
551
- }): string[] {
552
- const recommendations: string[] = [];
553
-
554
- // Size recommendations
555
- if (analysis.totalSize > 500 * 1024) {
556
- recommendations.push(
557
- 'Consider code splitting to reduce initial bundle size',
558
- 'Use dynamic imports for routes and large components',
559
- );
560
- }
561
-
562
- // Duplicate recommendations
563
- if (analysis.duplicates.length > 0) {
564
- recommendations.push(
565
- `Found ${analysis.duplicates.length} duplicate packages - dedupe with npm/yarn`,
566
- 'Consider using webpack.optimize.ModuleConcatenationPlugin',
567
- );
568
-
569
- const biggestDupe = analysis.duplicates[0];
570
- if (biggestDupe) {
571
- recommendations.push(
572
- `Largest duplicate: ${biggestDupe.name} (${formatBytes(biggestDupe.totalSize)})`,
573
- );
574
- }
575
- }
576
-
577
- // Large module recommendations
578
- const veryLargeModules = analysis.largestModules.filter(m => m.size > 100 * 1024);
579
- if (veryLargeModules.length > 0) {
580
- recommendations.push(
581
- 'Large modules detected - consider lazy loading:',
582
- ...veryLargeModules.slice(0, 3).map(m =>
583
- ` - ${m.name}: ${formatBytes(m.size)}`
584
- ),
585
- );
586
- }
587
-
588
- return recommendations;
589
- }
57
+ onLCP(sendToAnalytics); // Target: < 2.5s
58
+ onFID(sendToAnalytics); // Target: < 100ms
59
+ onCLS(sendToAnalytics); // Target: < 0.1
60
+ onINP(sendToAnalytics); // Target: < 200ms
590
61
  ```
591
62
 
592
- ### 5. Performance Budget
63
+ ### Performance Budget Check
593
64
 
594
65
  ```typescript
595
- interface PerformanceBudget {
596
- metrics: MetricBudget[];
597
- resources: ResourceBudget[];
598
- }
599
-
600
- interface MetricBudget {
601
- metric: string;
602
- budget: number;
603
- unit: 'ms' | 'score' | 'bytes';
604
- }
605
-
606
- interface ResourceBudget {
607
- type: string;
608
- budget: number;
609
- count?: number;
610
- }
611
-
612
- // Default performance budget
613
- const DEFAULT_BUDGET: PerformanceBudget = {
614
- metrics: [
615
- { metric: 'LCP', budget: 2500, unit: 'ms' },
616
- { metric: 'FID', budget: 100, unit: 'ms' },
617
- { metric: 'CLS', budget: 0.1, unit: 'score' },
618
- { metric: 'TTI', budget: 3800, unit: 'ms' },
619
- { metric: 'TBT', budget: 200, unit: 'ms' },
620
- ],
621
- resources: [
622
- { type: 'script', budget: 300 * 1024 },
623
- { type: 'stylesheet', budget: 50 * 1024 },
624
- { type: 'image', budget: 500 * 1024 },
625
- { type: 'font', budget: 100 * 1024 },
626
- { type: 'total', budget: 1000 * 1024 },
627
- ],
66
+ const BUDGET = {
67
+ lcp: 2500, fid: 100, cls: 0.1, tti: 3800, tbt: 200,
68
+ jsSize: 300 * 1024, cssSize: 50 * 1024, totalSize: 1000 * 1024,
628
69
  };
629
70
 
630
- // Check budget violations
631
- function checkPerformanceBudget(
632
- metrics: PerformanceMetrics,
633
- resources: ResourceMetrics,
634
- budget: PerformanceBudget = DEFAULT_BUDGET
635
- ): BudgetReport {
636
- const violations: BudgetViolation[] = [];
637
-
638
- // Check metric budgets
639
- for (const { metric, budget: limit, unit } of budget.metrics) {
640
- const actual = metrics[metric.toLowerCase()];
641
- if (actual > limit) {
642
- violations.push({
643
- type: 'metric',
644
- name: metric,
645
- budget: limit,
646
- actual,
647
- unit,
648
- overBy: ((actual - limit) / limit * 100).toFixed(1) + '%',
649
- });
650
- }
651
- }
652
-
653
- // Check resource budgets
654
- for (const { type, budget: limit, count } of budget.resources) {
655
- const resource = resources[type];
656
- if (resource.size > limit) {
657
- violations.push({
658
- type: 'resource',
659
- name: type,
660
- budget: limit,
661
- actual: resource.size,
662
- unit: 'bytes',
663
- overBy: formatBytes(resource.size - limit),
664
- });
665
- }
666
- if (count && resource.count > count) {
667
- violations.push({
668
- type: 'resource-count',
669
- name: `${type} count`,
670
- budget: count,
671
- actual: resource.count,
672
- unit: 'requests',
673
- });
674
- }
675
- }
676
-
677
- return {
678
- passed: violations.length === 0,
679
- violations,
680
- summary: generateBudgetSummary(violations),
681
- };
682
- }
683
-
684
- // Performance regression test
685
- async function runPerformanceRegression(
686
- url: string,
687
- baseline: PerformanceMetrics,
688
- threshold: number = 0.1 // 10% regression threshold
689
- ): Promise<RegressionReport> {
690
- const current = await runLighthouseAudit({ url });
691
- const regressions: Regression[] = [];
692
-
693
- for (const [metric, baselineValue] of Object.entries(baseline)) {
694
- const currentValue = current.metrics[metric];
695
- const change = (currentValue - baselineValue) / baselineValue;
696
-
697
- if (change > threshold) {
698
- regressions.push({
699
- metric,
700
- baseline: baselineValue,
701
- current: currentValue,
702
- change: `+${(change * 100).toFixed(1)}%`,
703
- severity: change > 0.25 ? 'critical' : 'warning',
704
- });
705
- }
706
- }
707
-
708
- return {
709
- passed: regressions.length === 0,
710
- regressions,
711
- metrics: current.metrics,
712
- comparison: generateComparison(baseline, current.metrics),
713
- };
71
+ function checkBudget(metrics: Record<string, number>) {
72
+ const violations = Object.entries(BUDGET)
73
+ .filter(([key, limit]) => metrics[key] > limit)
74
+ .map(([key, limit]) => ({ metric: key, limit, actual: metrics[key] }));
75
+ return { passed: violations.length === 0, violations };
714
76
  }
715
77
  ```
716
78
 
717
- ### 6. Automated Performance CI/CD
79
+ ### CI/CD Integration
718
80
 
719
81
  ```yaml
720
82
  # .github/workflows/performance.yml
721
- name: Performance Audit
722
-
723
- on:
724
- pull_request:
725
- branches: [main]
726
- push:
727
- branches: [main]
728
-
729
- jobs:
730
- lighthouse:
731
- runs-on: ubuntu-latest
732
- steps:
733
- - uses: actions/checkout@v4
734
-
735
- - name: Setup Node.js
736
- uses: actions/setup-node@v4
737
- with:
738
- node-version: '20'
739
-
740
- - name: Install dependencies
741
- run: npm ci
742
-
743
- - name: Build
744
- run: npm run build
745
-
746
- - name: Start server
747
- run: npm run start &
748
-
749
- - name: Run Lighthouse
750
- uses: treosh/lighthouse-ci-action@v10
751
- with:
752
- urls: |
753
- http://localhost:3000
754
- http://localhost:3000/products
755
- budgetPath: ./performance-budget.json
756
- uploadArtifacts: true
757
-
758
- - name: Check performance budget
759
- run: |
760
- node scripts/check-performance-budget.js \
761
- --budget ./performance-budget.json \
762
- --results .lighthouseci/*.json
763
- ```
764
-
765
- ## Use Cases
766
-
767
- ### 1. E-commerce Performance Optimization
768
-
769
- ```typescript
770
- // E-commerce specific performance audit
771
- async function auditEcommerceSite(baseUrl: string): Promise<EcommerceAudit> {
772
- const pages = [
773
- { name: 'Home', path: '/' },
774
- { name: 'Category', path: '/products' },
775
- { name: 'Product', path: '/products/1' },
776
- { name: 'Cart', path: '/cart' },
777
- { name: 'Checkout', path: '/checkout' },
778
- ];
779
-
780
- const results = await Promise.all(
781
- pages.map(async page => ({
782
- ...page,
783
- audit: await runLighthouseAudit({
784
- url: `${baseUrl}${page.path}`,
785
- device: 'mobile',
786
- }),
787
- }))
788
- );
789
-
790
- return {
791
- pages: results,
792
- criticalPath: identifyCriticalPath(results),
793
- conversionImpact: estimateConversionImpact(results),
794
- recommendations: prioritizeRecommendations(results),
795
- };
796
- }
797
- ```
798
-
799
- ### 2. SPA Performance Monitoring
800
-
801
- ```typescript
802
- // Single Page App performance monitoring
803
- function initSPAPerformanceMonitoring(): void {
804
- // Track route changes
805
- let routeStartTime: number;
806
-
807
- router.beforeEach(() => {
808
- routeStartTime = performance.now();
809
- });
810
-
811
- router.afterEach((to) => {
812
- const routeTime = performance.now() - routeStartTime;
813
-
814
- // Track custom metric
815
- performance.measure(`route-${to.name}`, {
816
- start: routeStartTime,
817
- duration: routeTime,
818
- });
819
-
820
- // Report to analytics
821
- analytics.track('route_performance', {
822
- route: to.name,
823
- duration: routeTime,
824
- timestamp: Date.now(),
825
- });
826
- });
827
-
828
- // Monitor long tasks
829
- const observer = new PerformanceObserver((list) => {
830
- for (const entry of list.getEntries()) {
831
- if (entry.duration > 50) {
832
- console.warn('Long task detected:', entry.duration, 'ms');
833
- analytics.track('long_task', {
834
- duration: entry.duration,
835
- startTime: entry.startTime,
836
- });
837
- }
838
- }
839
- });
840
-
841
- observer.observe({ entryTypes: ['longtask'] });
842
- }
83
+ - name: Lighthouse CI
84
+ uses: treosh/lighthouse-ci-action@v10
85
+ with:
86
+ urls: http://localhost:3000
87
+ budgetPath: ./performance-budget.json
88
+ uploadArtifacts: true
843
89
  ```
844
90
 
845
91
  ## Best Practices
846
92
 
847
- ### Do's
848
-
849
- - **Test in production-like conditions** - Use throttling and real device testing
850
- - **Monitor continuously** - Set up RUM for ongoing performance tracking
851
- - **Focus on user-centric metrics** - Prioritize Core Web Vitals
852
- - **Automate testing** - Include performance tests in CI/CD
853
- - **Set budgets** - Define and enforce performance budgets
854
- - **Profile incrementally** - Test before and after changes
855
-
856
- ### Don'ts
857
-
858
- - Don't test only on fast connections
859
- - Don't ignore mobile performance
860
- - Don't optimize prematurely without data
861
- - Don't rely solely on synthetic testing
862
- - Don't forget about third-party scripts
863
- - Don't ignore cumulative layout shift
864
-
865
- ### Performance Checklist
866
-
867
- ```markdown
868
- ## Pre-Launch Performance Checklist
869
-
870
- ### Core Web Vitals
871
- - [ ] LCP < 2.5s on mobile
872
- - [ ] FID < 100ms
873
- - [ ] CLS < 0.1
874
- - [ ] INP < 200ms
875
-
876
- ### Resource Optimization
877
- - [ ] Images optimized (WebP/AVIF, lazy loaded)
878
- - [ ] JavaScript bundled and minified
879
- - [ ] CSS optimized and critical CSS inlined
880
- - [ ] Fonts optimized (preload, font-display)
881
-
882
- ### Caching
883
- - [ ] Proper cache headers set
884
- - [ ] Service worker for offline support
885
- - [ ] CDN configured
886
-
887
- ### Monitoring
888
- - [ ] RUM implemented
889
- - [ ] Performance budget defined
890
- - [ ] CI/CD performance tests
891
- ```
892
-
893
- ## Related Skills
894
-
895
- - **frontend-design** - UI performance considerations
896
- - **devops** - Infrastructure optimization
897
- - **docker** - Container performance
898
- - **kubernetes** - Scaling for performance
899
-
900
- ## Reference Resources
901
-
902
- - [Web Vitals](https://web.dev/vitals/)
903
- - [Lighthouse Documentation](https://developer.chrome.com/docs/lighthouse/)
904
- - [Chrome DevTools Performance](https://developer.chrome.com/docs/devtools/performance/)
905
- - [web.dev Performance](https://web.dev/learn/performance/)
93
+ | Do | Avoid |
94
+ |----|-------|
95
+ | Test with throttled network and CPU | Testing only on fast connections |
96
+ | Monitor real user metrics (RUM) | Relying solely on synthetic tests |
97
+ | Set and enforce performance budgets | Optimizing without baseline data |
98
+ | Preload LCP images with fetchpriority | Ignoring mobile performance |
99
+ | Lazy load below-fold content | Loading all JS upfront |
100
+ | Use modern image formats (WebP, AVIF) | Ignoring third-party script impact |
101
+ | Profile before and after changes | Skipping cumulative layout shift fixes |