find-bottleneck-perf 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/README.md +169 -0
- package/index.js +114 -0
- package/package.json +44 -0
- package/src/analyzer.js +432 -0
- package/src/extractor.js +302 -0
- package/src/reporter.js +249 -0
- package/src/thresholds.js +138 -0
- package/src/utils.js +103 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# find-bottleneck-perf π
|
|
2
|
+
|
|
3
|
+
**One command. One answer.** Who's slowing down your websiteβFrontend, Backend, or Infrastructure?
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx find-bottleneck-perf https://your-website.com
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why?
|
|
16
|
+
|
|
17
|
+
You've got a slow website. Lighthouse gives you 47 metrics. DevTools shows 200 network requests. Your PM asks: *"Is it the frontend team or the backend team?"*
|
|
18
|
+
|
|
19
|
+
**find-bottleneck-perf** answers that question in seconds.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Run directly (no install)
|
|
27
|
+
npx find-bottleneck-perf https://example.com
|
|
28
|
+
|
|
29
|
+
# Or install globally
|
|
30
|
+
npm install -g find-bottleneck-perf
|
|
31
|
+
find-bottleneck https://example.com
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Basic analysis
|
|
40
|
+
find-bottleneck https://example.com
|
|
41
|
+
|
|
42
|
+
# Simulate slow network (Slow 3G, Fast 3G, 4G, WiFi)
|
|
43
|
+
find-bottleneck https://example.com --network slow-3g
|
|
44
|
+
|
|
45
|
+
# Export full report to JSON
|
|
46
|
+
find-bottleneck https://example.com --export report.json
|
|
47
|
+
|
|
48
|
+
# Combine options
|
|
49
|
+
find-bottleneck https://example.com --network fast-3g --export report.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## What You Get
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
58
|
+
FIND-BOTTLENECK β Performance Analysis Report
|
|
59
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
60
|
+
|
|
61
|
+
ββ THE VERDICT
|
|
62
|
+
β
|
|
63
|
+
β π₯οΈ Primary Bottleneck: FRONTEND
|
|
64
|
+
β
|
|
65
|
+
β Scores: Frontend=19 Backend=5 Infra=2
|
|
66
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
67
|
+
|
|
68
|
+
ββ EVIDENCE
|
|
69
|
+
β
|
|
70
|
+
β [Frontend]
|
|
71
|
+
β βΈ Massive JS bundle (5.66 MB). Implement code splitting.
|
|
72
|
+
β βΈ 35 render-blocking resources. Use async/defer.
|
|
73
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
74
|
+
|
|
75
|
+
ββ RECOMMENDATIONS
|
|
76
|
+
β
|
|
77
|
+
β π Implement code splitting (dynamic imports) and tree shaking.
|
|
78
|
+
β π Profile JavaScript with Chrome DevTools Performance tab.
|
|
79
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Verdicts Explained
|
|
85
|
+
|
|
86
|
+
| Verdict | What It Means | Typical Causes |
|
|
87
|
+
|---------|---------------|----------------|
|
|
88
|
+
| **Frontend** | Browser is struggling | Large JS bundles, render-blocking resources, heavy images |
|
|
89
|
+
| **Backend** | Server is slow | Slow APIs, database queries, missing caching |
|
|
90
|
+
| **Infra** | Network is the problem | High latency, slow DNS, distant servers |
|
|
91
|
+
| **Mixed** | Multiple issues | Problems in more than one area |
|
|
92
|
+
| **Optimized** | You're good! | No significant issues detected |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Metrics Collected
|
|
97
|
+
|
|
98
|
+
| Category | Metrics |
|
|
99
|
+
|----------|---------|
|
|
100
|
+
| **Navigation** | DNS, TCP, TLS, TTFB, Server Processing |
|
|
101
|
+
| **Web Vitals** | FCP, LCP, Total Blocking Time |
|
|
102
|
+
| **Resources** | JS/CSS/Image sizes, Render-blocking count |
|
|
103
|
+
| **APIs** | Request count, Avg/Max latency, Failed requests |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Network Throttling
|
|
108
|
+
|
|
109
|
+
Test how your site performs on real-world connections:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
find-bottleneck https://example.com --network slow-3g
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| Preset | Speed | Latency | Use Case |
|
|
116
|
+
|--------|-------|---------|----------|
|
|
117
|
+
| `slow-3g` | 500 Kbps | 400ms | Worst-case mobile |
|
|
118
|
+
| `fast-3g` | 1.6 Mbps | 150ms | Typical mobile |
|
|
119
|
+
| `4g` | 4 Mbps | 20ms | Good mobile |
|
|
120
|
+
| `wifi` | 30 Mbps | 2ms | Office/Home WiFi |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## JSON Export
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
find-bottleneck https://example.com --export report.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"url": "https://example.com",
|
|
133
|
+
"verdict": {
|
|
134
|
+
"primary": "Frontend",
|
|
135
|
+
"scores": { "Frontend": 15, "Backend": 5, "Infra": 2 }
|
|
136
|
+
},
|
|
137
|
+
"metrics": { ... },
|
|
138
|
+
"evidence": [
|
|
139
|
+
{ "category": "Frontend", "message": "Massive JS bundle (5.15 MB)..." }
|
|
140
|
+
],
|
|
141
|
+
"recommendations": [
|
|
142
|
+
"Implement code splitting...",
|
|
143
|
+
"Profile database queries..."
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## How It Works
|
|
151
|
+
|
|
152
|
+
1. Launches **headless Chrome** via Puppeteer
|
|
153
|
+
2. Intercepts **all network requests** (APIs, JS, CSS, images)
|
|
154
|
+
3. Extracts **Navigation Timing API** and **PerformanceObserver** data
|
|
155
|
+
4. Applies **weighted heuristics** to score Frontend/Backend/Infra
|
|
156
|
+
5. Generates **evidence-based recommendations**
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Requirements
|
|
161
|
+
|
|
162
|
+
- Node.js 18+
|
|
163
|
+
- ~400MB disk space (for Chromium, installed automatically)
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
ISC Β© Karthik Sake
|
package/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* perf-blame-finder
|
|
5
|
+
*
|
|
6
|
+
* A pragmatic CLI tool for identifying web performance bottlenecks.
|
|
7
|
+
* Analyzes a live URL and determines if the issue is Frontend, Backend, or Infrastructure.
|
|
8
|
+
*
|
|
9
|
+
* Usage: perf-blame <url> [--export <path>] [--network <preset>]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { extractMetrics } = require('./src/extractor');
|
|
13
|
+
const { analyze } = require('./src/analyzer');
|
|
14
|
+
const { printReport, exportJson } = require('./src/reporter');
|
|
15
|
+
const { colorize } = require('./src/utils');
|
|
16
|
+
const { NETWORK_PRESETS } = require('./src/thresholds');
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
|
|
21
|
+
// --- Parse Arguments ---
|
|
22
|
+
let url = null;
|
|
23
|
+
let exportPath = null;
|
|
24
|
+
let networkPreset = null;
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < args.length; i++) {
|
|
27
|
+
if (args[i] === '--export' && args[i + 1]) {
|
|
28
|
+
exportPath = args[i + 1];
|
|
29
|
+
i++;
|
|
30
|
+
} else if (args[i] === '--network' && args[i + 1]) {
|
|
31
|
+
networkPreset = args[i + 1].toLowerCase();
|
|
32
|
+
i++;
|
|
33
|
+
} else if (args[i].startsWith('http')) {
|
|
34
|
+
url = args[i];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// --- Help / Validation ---
|
|
39
|
+
if (!url) {
|
|
40
|
+
const presetList = Object.keys(NETWORK_PRESETS).map(k => ` ${k.padEnd(12)} - ${NETWORK_PRESETS[k].name}`).join('\n');
|
|
41
|
+
|
|
42
|
+
console.log(`
|
|
43
|
+
${colorize('perf-blame-finder', 'bright')} - Identify web performance bottlenecks
|
|
44
|
+
|
|
45
|
+
${colorize('Usage:', 'yellow')}
|
|
46
|
+
perf-blame <url> [options]
|
|
47
|
+
|
|
48
|
+
${colorize('Options:', 'yellow')}
|
|
49
|
+
--export <path> Export full report to JSON file
|
|
50
|
+
--network <preset> Simulate network conditions
|
|
51
|
+
|
|
52
|
+
${colorize('Network Presets:', 'cyan')}
|
|
53
|
+
${presetList}
|
|
54
|
+
|
|
55
|
+
${colorize('Examples:', 'dim')}
|
|
56
|
+
perf-blame https://example.com
|
|
57
|
+
perf-blame https://example.com --network slow-3g
|
|
58
|
+
perf-blame https://example.com --network fast-3g --export report.json
|
|
59
|
+
|
|
60
|
+
${colorize('What it measures:', 'cyan')}
|
|
61
|
+
β’ Navigation Timing (DNS, TCP, TLS, TTFB)
|
|
62
|
+
β’ Core Web Vitals (FCP, LCP, TBT)
|
|
63
|
+
β’ Resource sizes (JS, CSS, Images)
|
|
64
|
+
β’ API performance (latency, count, failures)
|
|
65
|
+
β’ Derived metrics (server processing, client render time)
|
|
66
|
+
`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// --- Validate Network Preset ---
|
|
71
|
+
let networkCondition = null;
|
|
72
|
+
if (networkPreset) {
|
|
73
|
+
if (!NETWORK_PRESETS[networkPreset]) {
|
|
74
|
+
console.error(colorize(`\nβ Unknown network preset: ${networkPreset}`, 'red'));
|
|
75
|
+
console.log(`Available presets: ${Object.keys(NETWORK_PRESETS).join(', ')}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
networkCondition = NETWORK_PRESETS[networkPreset];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- Run Analysis ---
|
|
82
|
+
console.log(colorize(`\nπ Launching headless browser...`, 'cyan'));
|
|
83
|
+
console.log(colorize(` Target: ${url}`, 'dim'));
|
|
84
|
+
if (networkCondition) {
|
|
85
|
+
console.log(colorize(` Network: ${networkCondition.name}`, 'yellow'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// Step 1: Extract metrics (with optional network throttling)
|
|
90
|
+
const metrics = await extractMetrics(url, { networkCondition });
|
|
91
|
+
|
|
92
|
+
// Add network condition to metrics for export
|
|
93
|
+
if (networkPreset) {
|
|
94
|
+
metrics.networkCondition = networkPreset;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Step 2: Analyze metrics
|
|
98
|
+
const analysis = analyze(metrics);
|
|
99
|
+
|
|
100
|
+
// Step 3: Print report
|
|
101
|
+
printReport(analysis);
|
|
102
|
+
|
|
103
|
+
// Step 4: Export if requested
|
|
104
|
+
if (exportPath) {
|
|
105
|
+
exportJson(analysis, exportPath);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error(colorize(`\nβ Analysis failed: ${err.message}`, 'red'));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "find-bottleneck-perf",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool that analyzes web performance and tells you who to blame: Frontend, Backend, or Infrastructure",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"find-bottleneck": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"src/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "node index.js https://example.com"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"performance",
|
|
19
|
+
"bottleneck",
|
|
20
|
+
"web-vitals",
|
|
21
|
+
"lcp",
|
|
22
|
+
"ttfb",
|
|
23
|
+
"lighthouse",
|
|
24
|
+
"puppeteer",
|
|
25
|
+
"cli",
|
|
26
|
+
"frontend",
|
|
27
|
+
"backend",
|
|
28
|
+
"infrastructure",
|
|
29
|
+
"devtools",
|
|
30
|
+
"network-throttling"
|
|
31
|
+
],
|
|
32
|
+
"author": "Karthik Sake",
|
|
33
|
+
"license": "ISC",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/karthiksake/find-bottleneck-perf"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"puppeteer": "^23.0.0"
|
|
43
|
+
}
|
|
44
|
+
}
|