Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions crates/next-napi-bindings/src/turbo_trace_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ pub struct TraceSpanInfo {
pub avg_corrected_duration: Option<i64>,
/// Raw span ID for aggregated groups (the index of the first span).
pub first_span_id: Option<String>,
/// TurboMalloc memory-usage samples recorded while this span
/// (or its example span, for aggregated groups) was live.
///
/// Each entry is `[ts_offset_from_span_start_in_ticks, bytes, pressure]`,
/// where `pressure` is the memory-pressure byte (0 = no pressure, higher
/// = more pressure). `100 ticks = 1 µs`. The offset is always `>= 0` and
/// `<= span_duration`. Capped and downsampled by the store.
pub memory_samples: Vec<Vec<i64>>,
}

/// The result of a `query_trace_spans` call.
Expand Down Expand Up @@ -125,6 +133,11 @@ pub fn query_trace_spans(
total_corrected_duration: s.total_corrected_duration.map(|v| v as i64),
avg_corrected_duration: s.avg_corrected_duration.map(|v| v as i64),
first_span_id: s.first_span_id,
memory_samples: s
.memory_samples
.into_iter()
.map(|(ts, mem, pressure)| vec![ts, mem as i64, pressure as i64])
.collect(),
})
.collect(),
page: result.page as u32,
Expand Down
2 changes: 2 additions & 0 deletions docs/01-app/02-guides/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ Through `next-devtools-mcp`, agents can use the following tools:
- **`get_project_metadata`**: Retrieve project structure, configuration, and dev server URL
- **`get_routes`**: Get all routes that will become entry points by scanning the filesystem. Returns routes grouped by router type (appRouter, pagesRouter). Dynamic segments appear as `[param]` or `[...slug]` patterns
- **`get_server_action_by_id`**: Look up Server Actions by their ID to find the source file and function name
- **`get_compilation_issues`**: Retrieve compilation warnings and errors for the whole project from the bundler. Turbopack only.
- **`compile_route`**: Trigger on-demand compilation of a specific route without making an HTTP request to it. Accepts either a `routeSpecifier` (e.g. `/blog/[slug]`, as returned by `get_routes`) or a `path` (e.g. `/blog/hello-world`) which is resolved to the matching route using the dev router's live route table. Returns any compilation issues for the route. Turbopack only.

## Using with agents

Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "16.3.0-canary.23"
"version": "16.3.0-canary.24"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"keywords": [
"react",
"next",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-next",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "ESLint configuration used by Next.js.",
"license": "MIT",
"repository": {
Expand All @@ -12,7 +12,7 @@
"dist"
],
"dependencies": {
"@next/eslint-plugin-next": "16.3.0-canary.23",
"@next/eslint-plugin-next": "16.3.0-canary.24",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.32.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-internal/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@next/eslint-plugin-internal",
"private": true,
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "ESLint plugin for working on Next.js.",
"exports": {
".": "./src/eslint-plugin-internal.js"
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "ESLint plugin for Next.js.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/font/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@next/font",
"private": true,
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"repository": {
"url": "vercel/next.js",
"directory": "packages/font"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-playwright/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/playwright",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-playwright"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-routing/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/routing",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-rspack/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-rspack",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-rspack"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-swc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/swc",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"private": true,
"files": [
"native/"
Expand Down
5 changes: 4 additions & 1 deletion packages/next/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -1252,5 +1252,8 @@
"1251": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Use \\`generateStaticParams\\` to make route params static\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1252": "\\`experimental.cssChunking: \"graph\"\\` is only supported with Turbopack. Please remove the option or run Next.js with Turbopack in %s.",
"1253": "\\`experimental.cssChunking: \"strict\"\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.",
"1254": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s."
"1254": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.",
"1255": "Compilation failed but no issues were recorded",
"1256": "no route matched for path \"%s\"",
"1257": "compileRoute: either routeSpecifier or path is required"
}
14 changes: 7 additions & 7 deletions packages/next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next",
"version": "16.3.0-canary.23",
"version": "16.3.0-canary.24",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
Expand Down Expand Up @@ -101,7 +101,7 @@
]
},
"dependencies": {
"@next/env": "16.3.0-canary.23",
"@next/env": "16.3.0-canary.24",
"@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579",
Expand Down Expand Up @@ -165,11 +165,11 @@
"@modelcontextprotocol/sdk": "1.18.1",
"@mswjs/interceptors": "0.23.0",
"@napi-rs/triples": "1.2.0",
"@next/font": "16.3.0-canary.23",
"@next/polyfill-module": "16.3.0-canary.23",
"@next/polyfill-nomodule": "16.3.0-canary.23",
"@next/react-refresh-utils": "16.3.0-canary.23",
"@next/swc": "16.3.0-canary.23",
"@next/font": "16.3.0-canary.24",
"@next/polyfill-module": "16.3.0-canary.24",
"@next/polyfill-nomodule": "16.3.0-canary.24",
"@next/react-refresh-utils": "16.3.0-canary.24",
"@next/swc": "16.3.0-canary.24",
"@opentelemetry/api": "1.6.0",
"@playwright/test": "1.58.2",
"@rspack/core": "1.6.7",
Expand Down
6 changes: 4 additions & 2 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { bold, yellow } from '../lib/picocolors'
import { makeRe } from 'next/dist/compiled/picomatch'
import { existsSync, promises as fs } from 'fs'
import os from 'os'
import { Worker } from '../lib/worker'
import { getNextBuildDebuggerPortOffset, Worker } from '../lib/worker'
import { defaultConfig, getNextConfigRuntime } from '../server/config-shared'
import devalue from 'next/dist/compiled/devalue'
import findUp from 'next/dist/compiled/find-up'
Expand Down Expand Up @@ -2047,7 +2047,9 @@ export default async function build(

staticWorker = createStaticWorker(config, {
numberOfWorkers,
debuggerPortOffset: -1,
debuggerPortOffset: getNextBuildDebuggerPortOffset({
kind: 'export-page',
}),
})

const analysisBegin = process.hrtime()
Expand Down
10 changes: 10 additions & 0 deletions packages/next/src/build/swc/generated-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,16 @@ export interface TraceSpanInfo {
avgCorrectedDuration?: number
/** Raw span ID for aggregated groups (the index of the first span). */
firstSpanId?: string
/**
* TurboMalloc memory-usage samples recorded while this span
* (or its example span, for aggregated groups) was live.
*
* Each entry is `[ts_offset_from_span_start_in_ticks, bytes, pressure]`,
* where `pressure` is the memory-pressure byte (0 = no pressure, higher
* = more pressure). `100 ticks = 1 µs`. The offset is always `>= 0` and
* `<= span_duration`. Capped and downsampled by the store.
*/
memorySamples: Array<Array<number>>
}
/** The result of a `query_trace_spans` call. */
export interface TraceQueryResult {
Expand Down
35 changes: 34 additions & 1 deletion packages/next/src/cli/internal/turbo-trace-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,34 @@ function formatRelative(ticks: number): string {
return prefix + formatDuration(Math.abs(ticks))
}

function formatBytes(bytes: number): string {
const KB = 1024
const MB = KB * 1024
const GB = MB * 1024
if (bytes >= GB) return `${(bytes / GB).toFixed(2)} GB`
if (bytes >= MB) return `${(bytes / MB).toFixed(2)} MB`
if (bytes >= KB) return `${(bytes / KB).toFixed(2)} KB`
return `${bytes} B`
}

function summarizeMemorySamples(samples: number[][]): string | null {
if (!samples || samples.length === 0) return null
const bytes = samples.map((s) => s[1])
const pressures = samples.map((s) => s[2] ?? 0)
const min = Math.min(...bytes)
const max = Math.max(...bytes)
const first = bytes[0]
const last = bytes[bytes.length - 1]
const delta = last - first
const deltaSign = delta >= 0 ? '+' : '-'
const maxPressure = Math.max(...pressures)
return (
`samples=${samples.length}, min=${formatBytes(min)}, max=${formatBytes(max)}, ` +
`start=${formatBytes(first)}, end=${formatBytes(last)}, ` +
`Δ=${deltaSign}${formatBytes(Math.abs(delta))}, maxPressure=${maxPressure}`
)
}

/**
* Render a single span (or aggregated span group) as a markdown section.
*/
Expand Down Expand Up @@ -74,6 +102,11 @@ function renderSpanMarkdown(span: TraceSpanInfo): string {
}
}

const memSummary = summarizeMemorySamples(span.memorySamples)
if (memSummary) {
md += `\n**Memory (TurboMalloc live bytes):** ${memSummary}\n`
}

md += '\n---\n\n'
return md
}
Expand Down Expand Up @@ -121,7 +154,7 @@ export async function startTurboTraceServerCli(
'query_spans',
{
description:
'Query spans from a turbopack trace file. Returns spans with timing, CPU usage, and attribute details. Set `outputType` to "json" for machine-readable output or "markdown" (default) for human-readable output. Use the `parent` parameter (with an ID from a previous result) to drill into children. Results are paginated to 20 spans per page.',
'Query spans from a turbopack trace file. Returns spans with timing, CPU usage, attribute details, and TurboMalloc live-memory samples recorded while each span was active. Set `outputType` to "json" for machine-readable output (including the raw `memorySamples` array of `[ts_offset_ticks, bytes, pressure]` triples per span — pressure is 0 = none, higher = more memory pressure) or "markdown" (default) for a human-readable summary. Use the `parent` parameter (with an ID from a previous result) to drill into children. Results are paginated to 20 spans per page.',
inputSchema: {
parent: z
.string()
Expand Down
Loading
Loading