@perfonext/build-mcp 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +34 -1
  2. package/dist/index.js +9 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/parser/analysis.d.ts +8 -1
  5. package/dist/parser/analysis.d.ts.map +1 -1
  6. package/dist/parser/analysis.js +238 -8
  7. package/dist/parser/analysis.js.map +1 -1
  8. package/dist/parser/types.d.ts +86 -0
  9. package/dist/parser/types.d.ts.map +1 -1
  10. package/dist/parser/webpack-stats.d.ts +15 -0
  11. package/dist/parser/webpack-stats.d.ts.map +1 -0
  12. package/dist/parser/webpack-stats.js +195 -0
  13. package/dist/parser/webpack-stats.js.map +1 -0
  14. package/dist/store.d.ts +3 -1
  15. package/dist/store.d.ts.map +1 -1
  16. package/dist/store.js +7 -0
  17. package/dist/store.js.map +1 -1
  18. package/dist/tools/explain-growth.d.ts +3 -0
  19. package/dist/tools/explain-growth.d.ts.map +1 -0
  20. package/dist/tools/explain-growth.js +97 -0
  21. package/dist/tools/explain-growth.js.map +1 -0
  22. package/dist/tools/how-to-collect-stats.d.ts +3 -0
  23. package/dist/tools/how-to-collect-stats.d.ts.map +1 -0
  24. package/dist/tools/how-to-collect-stats.js +137 -0
  25. package/dist/tools/how-to-collect-stats.js.map +1 -0
  26. package/dist/tools/load-webpack-stats.d.ts +3 -0
  27. package/dist/tools/load-webpack-stats.d.ts.map +1 -0
  28. package/dist/tools/load-webpack-stats.js +49 -0
  29. package/dist/tools/load-webpack-stats.js.map +1 -0
  30. package/dist/tools/trace-import.d.ts +3 -0
  31. package/dist/tools/trace-import.d.ts.map +1 -0
  32. package/dist/tools/trace-import.js +41 -0
  33. package/dist/tools/trace-import.js.map +1 -0
  34. package/dist/tools/webpack-shared.d.ts +21 -0
  35. package/dist/tools/webpack-shared.d.ts.map +1 -0
  36. package/dist/tools/webpack-shared.js +33 -0
  37. package/dist/tools/webpack-shared.js.map +1 -0
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -9,17 +9,26 @@
9
9
  - loads Next.js build artifacts from a `.next` directory
10
10
  - ranks the largest user-facing routes by emitted bundle footprint
11
11
  - identifies the heaviest shared chunks that affect multiple routes
12
+ - compares two builds and explains which routes and chunks drove bundle growth, with
13
+ severity-ranked, evidence-backed fix suggestions
14
+ - matches chunks across builds even though Next.js fingerprints filenames with content hashes
15
+ - traces why a given module or npm package is bundled (import chain entry → module) when an
16
+ optional webpack stats file is collected
12
17
  - keeps loaded build snapshots in memory so an MCP client can inspect them without re-reading the same build
13
18
 
14
19
  ## Inputs
15
20
 
16
- The MVP reads build artifacts developers already have after running `next build`:
21
+ The core tools read build artifacts developers already have after running `next build`:
17
22
 
18
23
  - `.next/build-manifest.json`
19
24
  - `.next/prerender-manifest.json` when present
20
25
  - `.next/app-build-manifest.json` when present
21
26
  - optional captured `next build` output text to derive build duration
22
27
 
28
+ Import-level attribution (`trace_import`) additionally needs a webpack module-stats file at
29
+ `.next/stats.json`. A stock `next build` does not emit one; `how_to_collect_stats` returns the recipe
30
+ to generate it. The manifest tools above never read it, so they work with or without it.
31
+
23
32
  ## Tools
24
33
 
25
34
  | Tool | Description |
@@ -28,9 +37,30 @@ The MVP reads build artifacts developers already have after running `next build`
28
37
  | `get_largest_routes` | Rank the heaviest user-facing routes by total emitted chunk bytes |
29
38
  | `get_shared_chunks` | Rank shared chunks by size and show which routes depend on them |
30
39
  | `compare_builds` | Compare a baseline and current build snapshot to show which routes and chunks grew or shrank |
40
+ | `explain_growth` | Severity-rank which routes and chunks drove bundle growth between two builds, with evidence-backed fix suggestions |
41
+ | `how_to_collect_stats` | Return the recipe (manual) or an action plan (automatic) to generate `.next/stats.json` |
42
+ | `load_webpack_stats` | Parse `.next/stats.json` and link it to a loaded build; required before `trace_import` |
43
+ | `trace_import` | Explain why a module or npm package is bundled by walking its import chain to the entry |
31
44
 
32
45
  The output stays machine-readable and includes raw byte counts so Copilot can explain regressions, prioritise fixes, and suggest concrete dependency or import-level follow-up.
33
46
 
47
+ Because Next.js content-hashes emitted filenames (`framework-<hash>.js`, and CSS files named purely by hash), `compare_builds` and `explain_growth` match chunks across builds by a hash-normalized identity. This prevents a rehashed-but-unchanged chunk from being misreported as removed-and-recreated, while still flagging genuinely new chunks.
48
+
49
+ ### Deep bundle attribution (optional)
50
+
51
+ The manifest tools work with zero setup. To answer "why is this package bundled?", collect a webpack
52
+ stats file first:
53
+
54
+ 1. Call `how_to_collect_stats({ method: 'manual' | 'automatic' })` and apply the returned steps — it
55
+ adds `webpack-stats-plugin`, gates a `next.config` hook behind `ANALYZE=true`, and rebuilds.
56
+ 2. Call `load_build_stats({ buildDir })` to get a `buildId`.
57
+ 3. Call `load_webpack_stats({ buildId })` to parse the generated `.next/stats.json`.
58
+ 4. Call `trace_import({ buildId, moduleName })` to see the import chain that pulls a module in.
59
+
60
+ If the app builds with Turbopack there is no webpack module graph, so `how_to_collect_stats` says so
61
+ and points back to the manifest-only tools. `trace_import` degrades gracefully with a breadcrumb when
62
+ no stats file is loaded — it is never an error.
63
+
34
64
  ## Install
35
65
 
36
66
  Run directly with `npx`:
@@ -70,6 +100,9 @@ Add this server to VS Code settings:
70
100
  - "Which shared chunks are affecting the most routes in this build?"
71
101
  - "Summarize the build footprint and tell me which routes ship the most JavaScript."
72
102
  - "Compare my baseline and current `.next` builds and show me which routes or shared chunks grew the most."
103
+ - "Explain what grew between my baseline and current `.next` builds and what I should fix first."
104
+ - "Set up webpack stats collection so I can see why a package is bundled."
105
+ - "Why is `axios` in my bundle? Trace its import chain."
73
106
 
74
107
  ## Development
75
108
 
package/dist/index.js CHANGED
@@ -5,14 +5,22 @@ import { registerLoadBuildStats } from './tools/load-build-stats.js';
5
5
  import { registerGetLargestRoutes } from './tools/get-largest-routes.js';
6
6
  import { registerGetSharedChunks } from './tools/get-shared-chunks.js';
7
7
  import { registerCompareBuilds } from './tools/compare-builds.js';
8
+ import { registerExplainGrowth } from './tools/explain-growth.js';
9
+ import { registerHowToCollectStats } from './tools/how-to-collect-stats.js';
10
+ import { registerLoadWebpackStats } from './tools/load-webpack-stats.js';
11
+ import { registerTraceImport } from './tools/trace-import.js';
8
12
  const server = new McpServer({
9
13
  name: 'perfonext-build-mcp',
10
- version: '0.1.0',
14
+ version: '0.3.0',
11
15
  });
12
16
  registerLoadBuildStats(server);
13
17
  registerGetLargestRoutes(server);
14
18
  registerGetSharedChunks(server);
15
19
  registerCompareBuilds(server);
20
+ registerExplainGrowth(server);
21
+ registerHowToCollectStats(server);
22
+ registerLoadWebpackStats(server);
23
+ registerTraceImport(server);
16
24
  const transport = new StdioServerTransport();
17
25
  await server.connect(transport);
18
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAClC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAE5B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -1,4 +1,10 @@
1
- import type { BuildComparison, ParsedBuildStats, RouteSummaryEntry, SharedChunkSummaryEntry } from './types.js';
1
+ import type { BuildComparison, GrowthExplanation, ParsedBuildStats, RouteSummaryEntry, SharedChunkSummaryEntry } from './types.js';
2
+ /**
3
+ * Strip Next.js content-hash suffixes (`framework-<hash>.js` → `framework.js`) so the same
4
+ * chunk matches across builds. Pure-hash basenames (e.g. CSS `4c7ae03ab6df2350.css`) have no
5
+ * stable prefix and are left untouched — their hash is already a content-stable identity.
6
+ */
7
+ export declare function normalizeChunkKey(chunkPath: string): string;
2
8
  export declare function getBuildSummary(build: ParsedBuildStats): {
3
9
  buildId: string;
4
10
  buildDir: string;
@@ -12,4 +18,5 @@ export declare function getBuildSummary(build: ParsedBuildStats): {
12
18
  export declare function getLargestRoutes(build: ParsedBuildStats, limit: number): RouteSummaryEntry[];
13
19
  export declare function getSharedChunks(build: ParsedBuildStats, limit: number): SharedChunkSummaryEntry[];
14
20
  export declare function compareBuilds(baseline: ParsedBuildStats, current: ParsedBuildStats, limit: number): BuildComparison;
21
+ export declare function explainGrowth(baseline: ParsedBuildStats, current: ParsedBuildStats, limit: number): GrowthExplanation;
15
22
  //# sourceMappingURL=analysis.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/parser/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,gBAAgB,EAEhB,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAUpB,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAWA;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAc5F;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAWjG;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,GACZ,eAAe,CAqEjB"}
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/parser/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAGf,iBAAiB,EAGjB,gBAAgB,EAGhB,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAUpB;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAe3D;AAyCD,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAWA;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAc5F;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAWjG;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,GACZ,eAAe,CAqEjB;AAsID,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,GACZ,iBAAiB,CA+FnB"}
@@ -4,6 +4,53 @@ function calculateDeltaRatio(baseline, current) {
4
4
  }
5
5
  return (current - baseline) / baseline;
6
6
  }
7
+ /**
8
+ * Strip Next.js content-hash suffixes (`framework-<hash>.js` → `framework.js`) so the same
9
+ * chunk matches across builds. Pure-hash basenames (e.g. CSS `4c7ae03ab6df2350.css`) have no
10
+ * stable prefix and are left untouched — their hash is already a content-stable identity.
11
+ */
12
+ export function normalizeChunkKey(chunkPath) {
13
+ const clean = chunkPath.replace(/^\//, '');
14
+ const lastSlash = clean.lastIndexOf('/');
15
+ const dir = lastSlash >= 0 ? clean.slice(0, lastSlash + 1) : '';
16
+ const file = lastSlash >= 0 ? clean.slice(lastSlash + 1) : clean;
17
+ const lastDot = file.lastIndexOf('.');
18
+ const base = lastDot >= 0 ? file.slice(0, lastDot) : file;
19
+ const ext = lastDot >= 0 ? file.slice(lastDot) : '';
20
+ // Strip a trailing "-<contenthash>" segment. Pure-hash basenames have no dash and are left
21
+ // as-is, preserving their content-stable identity.
22
+ const normalizedBase = base.replace(/-[0-9a-f]{8,}$/i, '');
23
+ return `${dir}${normalizedBase}${ext}`;
24
+ }
25
+ /**
26
+ * Collapse a build's chunks into hash-normalized buckets so they can be matched across builds.
27
+ * Distinct chunks that normalize to the same key are summed and their routes unioned.
28
+ */
29
+ function aggregateChunksByKey(build) {
30
+ const map = new Map();
31
+ for (const chunk of build.chunks) {
32
+ const key = normalizeChunkKey(chunk.chunkPath);
33
+ const existing = map.get(key);
34
+ if (existing) {
35
+ existing.sizeBytes += chunk.sizeBytes;
36
+ for (const route of chunk.sharedByRoutes) {
37
+ existing.routeSet.add(route);
38
+ }
39
+ }
40
+ else {
41
+ map.set(key, {
42
+ displayPath: chunk.chunkPath,
43
+ sizeBytes: chunk.sizeBytes,
44
+ routeCount: chunk.routeCount,
45
+ routeSet: new Set(chunk.sharedByRoutes),
46
+ });
47
+ }
48
+ }
49
+ for (const entry of map.values()) {
50
+ entry.routeCount = entry.routeSet.size;
51
+ }
52
+ return map;
53
+ }
7
54
  export function getBuildSummary(build) {
8
55
  return {
9
56
  buildId: build.id,
@@ -63,17 +110,17 @@ export function compareBuilds(baseline, current, limit) {
63
110
  })
64
111
  .sort((left, right) => Math.abs(right.deltaBytes) - Math.abs(left.deltaBytes))
65
112
  .slice(0, limit);
66
- const baselineChunks = new Map(baseline.chunks.map(chunk => [chunk.chunkPath, chunk]));
67
- const currentChunks = new Map(current.chunks.map(chunk => [chunk.chunkPath, chunk]));
68
- const allChunkPaths = Array.from(new Set([...baselineChunks.keys(), ...currentChunks.keys()]));
69
- const chunkDeltas = allChunkPaths
70
- .map(chunkPath => {
71
- const baselineChunk = baselineChunks.get(chunkPath);
72
- const currentChunk = currentChunks.get(chunkPath);
113
+ const baselineChunks = aggregateChunksByKey(baseline);
114
+ const currentChunks = aggregateChunksByKey(current);
115
+ const allChunkKeys = Array.from(new Set([...baselineChunks.keys(), ...currentChunks.keys()]));
116
+ const chunkDeltas = allChunkKeys
117
+ .map(key => {
118
+ const baselineChunk = baselineChunks.get(key);
119
+ const currentChunk = currentChunks.get(key);
73
120
  const baselineBytes = baselineChunk?.sizeBytes ?? 0;
74
121
  const currentBytes = currentChunk?.sizeBytes ?? 0;
75
122
  return {
76
- chunkPath,
123
+ chunkPath: currentChunk?.displayPath ?? baselineChunk?.displayPath ?? key,
77
124
  baselineBytes,
78
125
  currentBytes,
79
126
  deltaBytes: currentBytes - baselineBytes,
@@ -107,4 +154,187 @@ export function compareBuilds(baseline, current, limit) {
107
154
  chunkDeltas,
108
155
  };
109
156
  }
157
+ const SEVERITY_CRITICAL_BYTES = 50 * 1024;
158
+ const SEVERITY_WARNING_BYTES = 10 * 1024;
159
+ const SEVERITY_CRITICAL_RATIO = 0.2;
160
+ const SEVERITY_WARNING_RATIO = 0.05;
161
+ function classifySeverity(deltaBytes, deltaRatio) {
162
+ if (deltaBytes >= SEVERITY_CRITICAL_BYTES ||
163
+ (deltaRatio !== null && deltaRatio >= SEVERITY_CRITICAL_RATIO)) {
164
+ return 'critical';
165
+ }
166
+ if (deltaBytes >= SEVERITY_WARNING_BYTES ||
167
+ (deltaRatio !== null && deltaRatio >= SEVERITY_WARNING_RATIO)) {
168
+ return 'warning';
169
+ }
170
+ return 'info';
171
+ }
172
+ const SEVERITY_RANK = {
173
+ info: 0,
174
+ warning: 1,
175
+ critical: 2,
176
+ };
177
+ function buildGrowthSuggestions(chunkContributions, routeFindings, limit) {
178
+ const suggestions = [];
179
+ const explainedChunks = new Set();
180
+ for (const chunk of chunkContributions) {
181
+ const severity = classifySeverity(chunk.deltaBytes, chunk.deltaRatio);
182
+ if (severity === 'info') {
183
+ continue;
184
+ }
185
+ if (chunk.isNew) {
186
+ explainedChunks.add(chunk.chunkPath);
187
+ suggestions.push({
188
+ kind: 'new-chunk',
189
+ severity,
190
+ chunkPath: chunk.chunkPath,
191
+ routePath: null,
192
+ deltaBytes: chunk.deltaBytes,
193
+ deltaRatio: chunk.deltaRatio,
194
+ affectedRouteCount: chunk.affectedRouteCount,
195
+ message: `New chunk ${chunk.chunkPath} appeared in the current build and is loaded by ` +
196
+ `${chunk.affectedRouteCount} route(s).`,
197
+ recommendedAction: chunk.isShared
198
+ ? 'Confirm the dependency that introduced it. If it is only needed on some routes, load it with a dynamic import so it stays out of the shared bundle.'
199
+ : 'Confirm the dependency that introduced it and consider a dynamic import if it is not required on initial load.',
200
+ });
201
+ continue;
202
+ }
203
+ if (chunk.isShared) {
204
+ explainedChunks.add(chunk.chunkPath);
205
+ suggestions.push({
206
+ kind: 'shared-chunk-growth',
207
+ severity,
208
+ chunkPath: chunk.chunkPath,
209
+ routePath: null,
210
+ deltaBytes: chunk.deltaBytes,
211
+ deltaRatio: chunk.deltaRatio,
212
+ affectedRouteCount: chunk.affectedRouteCount,
213
+ message: `Shared chunk ${chunk.chunkPath} grew and is loaded by ${chunk.affectedRouteCount} routes, ` +
214
+ 'so the regression multiplies across the app.',
215
+ recommendedAction: 'Identify the package driving the growth and move it out of the shared chunk (route-level or dynamic import) so only the routes that need it pay the cost.',
216
+ });
217
+ continue;
218
+ }
219
+ explainedChunks.add(chunk.chunkPath);
220
+ suggestions.push({
221
+ kind: 'chunk-growth',
222
+ severity,
223
+ chunkPath: chunk.chunkPath,
224
+ routePath: null,
225
+ deltaBytes: chunk.deltaBytes,
226
+ deltaRatio: chunk.deltaRatio,
227
+ affectedRouteCount: chunk.affectedRouteCount,
228
+ message: `Chunk ${chunk.chunkPath} grew and is exclusive to ${chunk.affectedRouteCount} route(s).`,
229
+ recommendedAction: 'Inspect the import chain for this chunk and split or lazy-load heavy dependencies that are not needed on initial render.',
230
+ });
231
+ }
232
+ for (const route of routeFindings) {
233
+ if (route.severity !== 'critical') {
234
+ continue;
235
+ }
236
+ const topChunk = route.topContributingChunks[0];
237
+ if (topChunk && explainedChunks.has(topChunk.chunkPath)) {
238
+ continue;
239
+ }
240
+ suggestions.push({
241
+ kind: 'route-regression',
242
+ severity: route.severity,
243
+ chunkPath: topChunk?.chunkPath ?? null,
244
+ routePath: route.path,
245
+ deltaBytes: route.deltaBytes,
246
+ deltaRatio: route.deltaRatio,
247
+ affectedRouteCount: null,
248
+ message: topChunk
249
+ ? `Route ${route.path} regressed critically; its largest contributor is ${topChunk.chunkPath}.`
250
+ : `Route ${route.path} regressed critically.`,
251
+ recommendedAction: "Compare this route's chunk list against the baseline and inspect the import chain of its largest contributor.",
252
+ });
253
+ }
254
+ return suggestions
255
+ .sort((left, right) => SEVERITY_RANK[right.severity] - SEVERITY_RANK[left.severity] ||
256
+ right.deltaBytes - left.deltaBytes)
257
+ .slice(0, limit);
258
+ }
259
+ export function explainGrowth(baseline, current, limit) {
260
+ const baselineChunks = aggregateChunksByKey(baseline);
261
+ const currentChunks = aggregateChunksByKey(current);
262
+ const allChunkKeys = Array.from(new Set([...baselineChunks.keys(), ...currentChunks.keys()]));
263
+ const chunkContributions = allChunkKeys
264
+ .map(key => {
265
+ const baselineChunk = baselineChunks.get(key);
266
+ const currentChunk = currentChunks.get(key);
267
+ const baselineBytes = baselineChunk?.sizeBytes ?? 0;
268
+ const currentBytes = currentChunk?.sizeBytes ?? 0;
269
+ const deltaBytes = currentBytes - baselineBytes;
270
+ return {
271
+ key,
272
+ chunkPath: currentChunk?.displayPath ?? baselineChunk?.displayPath ?? key,
273
+ deltaBytes,
274
+ deltaRatio: calculateDeltaRatio(baselineBytes, currentBytes),
275
+ isNew: baselineChunk === undefined,
276
+ isShared: (currentChunk?.routeCount ?? baselineChunk?.routeCount ?? 0) > 1,
277
+ affectedRouteCount: currentChunk?.routeCount ?? baselineChunk?.routeCount ?? 0,
278
+ };
279
+ })
280
+ .filter(entry => entry.deltaBytes > 0)
281
+ .sort((left, right) => right.deltaBytes - left.deltaBytes);
282
+ const topGrowingChunks = chunkContributions
283
+ .slice(0, limit)
284
+ .map(({ key: _key, ...rest }) => rest);
285
+ const baselineRoutes = new Map(baseline.routes.map(route => [route.path, route]));
286
+ const currentRoutes = new Map(current.routes.map(route => [route.path, route]));
287
+ const allRoutePaths = Array.from(new Set([...baselineRoutes.keys(), ...currentRoutes.keys()]));
288
+ const routeFindings = allRoutePaths
289
+ .map(path => {
290
+ const baselineRoute = baselineRoutes.get(path);
291
+ const currentRoute = currentRoutes.get(path);
292
+ const baselineBytes = baselineRoute?.totalBytes ?? 0;
293
+ const currentBytes = currentRoute?.totalBytes ?? 0;
294
+ const deltaBytes = currentBytes - baselineBytes;
295
+ const deltaRatio = calculateDeltaRatio(baselineBytes, currentBytes);
296
+ const routeChunkKeys = new Set([
297
+ ...(baselineRoute?.chunkPaths ?? []).map(normalizeChunkKey),
298
+ ...(currentRoute?.chunkPaths ?? []).map(normalizeChunkKey),
299
+ ]);
300
+ const topContributingChunks = chunkContributions
301
+ .filter(chunk => routeChunkKeys.has(chunk.key))
302
+ .slice(0, 5)
303
+ .map(({ key: _key, ...rest }) => rest);
304
+ return {
305
+ path,
306
+ deltaBytes,
307
+ deltaRatio,
308
+ severity: classifySeverity(deltaBytes, deltaRatio),
309
+ topContributingChunks,
310
+ };
311
+ })
312
+ .filter(finding => finding.deltaBytes > 0)
313
+ .sort((left, right) => right.deltaBytes - left.deltaBytes)
314
+ .slice(0, limit);
315
+ const allDeltas = allChunkKeys.map(key => {
316
+ const baselineBytes = baselineChunks.get(key)?.sizeBytes ?? 0;
317
+ const currentBytes = currentChunks.get(key)?.sizeBytes ?? 0;
318
+ return currentBytes - baselineBytes;
319
+ });
320
+ const totalDeltaBytes = current.totalChunkBytes - baseline.totalChunkBytes;
321
+ const overallSeverity = classifySeverity(Math.abs(totalDeltaBytes), calculateDeltaRatio(baseline.totalChunkBytes, current.totalChunkBytes));
322
+ const suggestions = buildGrowthSuggestions(chunkContributions, routeFindings, limit);
323
+ return {
324
+ baselineBuildId: baseline.id,
325
+ currentBuildId: current.id,
326
+ overall: {
327
+ totalDeltaBytes,
328
+ totalDeltaRatio: calculateDeltaRatio(baseline.totalChunkBytes, current.totalChunkBytes),
329
+ severity: totalDeltaBytes > 0 ? overallSeverity : 'info',
330
+ newChunkCount: allChunkKeys.filter(key => !baselineChunks.has(key)).length,
331
+ removedChunkCount: allChunkKeys.filter(key => !currentChunks.has(key)).length,
332
+ grownChunkCount: allDeltas.filter(d => d > 0).length,
333
+ shrunkChunkCount: allDeltas.filter(d => d < 0).length,
334
+ },
335
+ routeFindings,
336
+ topGrowingChunks,
337
+ suggestions,
338
+ };
339
+ }
110
340
  //# sourceMappingURL=analysis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../../src/parser/analysis.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../../src/parser/analysis.ts"],"names":[],"mappings":"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"}
@@ -83,4 +83,90 @@ export interface BuildComparison {
83
83
  routeDeltas: RouteDeltaEntry[];
84
84
  chunkDeltas: ChunkDeltaEntry[];
85
85
  }
86
+ export type GrowthSeverity = 'info' | 'warning' | 'critical';
87
+ export interface ChunkGrowthContribution {
88
+ chunkPath: string;
89
+ deltaBytes: number;
90
+ deltaRatio: number | null;
91
+ isNew: boolean;
92
+ isShared: boolean;
93
+ affectedRouteCount: number;
94
+ }
95
+ export interface RouteGrowthFinding {
96
+ path: string;
97
+ deltaBytes: number;
98
+ deltaRatio: number | null;
99
+ severity: GrowthSeverity;
100
+ topContributingChunks: ChunkGrowthContribution[];
101
+ }
102
+ export interface OverallGrowthSummary {
103
+ totalDeltaBytes: number;
104
+ totalDeltaRatio: number | null;
105
+ severity: GrowthSeverity;
106
+ newChunkCount: number;
107
+ removedChunkCount: number;
108
+ grownChunkCount: number;
109
+ shrunkChunkCount: number;
110
+ }
111
+ export type GrowthSuggestionKind = 'shared-chunk-growth' | 'new-chunk' | 'chunk-growth' | 'route-regression';
112
+ export interface GrowthSuggestion {
113
+ kind: GrowthSuggestionKind;
114
+ severity: GrowthSeverity;
115
+ chunkPath: string | null;
116
+ routePath: string | null;
117
+ deltaBytes: number;
118
+ deltaRatio: number | null;
119
+ affectedRouteCount: number | null;
120
+ message: string;
121
+ recommendedAction: string;
122
+ }
123
+ export interface GrowthExplanation {
124
+ baselineBuildId: string;
125
+ currentBuildId: string;
126
+ overall: OverallGrowthSummary;
127
+ routeFindings: RouteGrowthFinding[];
128
+ topGrowingChunks: ChunkGrowthContribution[];
129
+ suggestions: GrowthSuggestion[];
130
+ }
131
+ export interface WebpackModuleReason {
132
+ moduleName: string | null;
133
+ userRequest: string | null;
134
+ }
135
+ export interface WebpackModule {
136
+ name: string;
137
+ packageName: string | null;
138
+ sizeBytes: number;
139
+ chunkIds: Array<string | number>;
140
+ reasons: WebpackModuleReason[];
141
+ }
142
+ export interface WebpackChunk {
143
+ id: string | number;
144
+ names: string[];
145
+ files: string[];
146
+ sizeBytes: number;
147
+ }
148
+ export interface ParsedWebpackStats {
149
+ buildId: string;
150
+ statsPath: string;
151
+ modules: WebpackModule[];
152
+ chunks: WebpackChunk[];
153
+ moduleCount: number;
154
+ parsedModuleCount: number;
155
+ }
156
+ export interface ImportChainNode {
157
+ moduleName: string;
158
+ packageName: string | null;
159
+ }
160
+ export interface ImportTrace {
161
+ moduleName: string;
162
+ packageName: string | null;
163
+ sizeBytes: number;
164
+ chunkFiles: string[];
165
+ importChain: ImportChainNode[];
166
+ }
167
+ export interface TraceImportResult {
168
+ query: string;
169
+ matchCount: number;
170
+ traces: ImportTrace[];
171
+ }
86
172
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/parser/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/parser/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ParsedWebpackStats, TraceImportResult } from './types.js';
2
+ /**
3
+ * Resolve the npm package an emitted module belongs to. Uses the LAST `node_modules/` segment so
4
+ * nested installs (`a/node_modules/b`) attribute to the inner package, and preserves scoped names
5
+ * (`@org/pkg`). Returns null for first-party application code.
6
+ */
7
+ export declare function extractPackageName(moduleName: string): string | null;
8
+ /**
9
+ * Parse a webpack module-stats JSON (`.next/stats.json`) into a compact, analysis-ready shape.
10
+ * Only the fields the attribution tools need are retained — raw source, asset maps, and other
11
+ * webpack noise are dropped so a multi-MB stats file stays small in memory.
12
+ */
13
+ export declare function parseWebpackStats(buildDirPath: string, buildId: string): Promise<ParsedWebpackStats | null>;
14
+ export declare function traceImport(stats: ParsedWebpackStats, moduleName: string, limit?: number): TraceImportResult;
15
+ //# sourceMappingURL=webpack-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webpack-stats.d.ts","sourceRoot":"","sources":["../../src/parser/webpack-stats.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,kBAAkB,EAClB,iBAAiB,EAIlB,MAAM,YAAY,CAAC;AA6CpB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBpE;AA4DD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA2CpC;AAmED,wBAAgB,WAAW,CACzB,KAAK,EAAE,kBAAkB,EACzB,UAAU,EAAE,MAAM,EAClB,KAAK,SAAK,GACT,iBAAiB,CAsBnB"}