Conversation
|
|
@nuxt/kit
@nuxt/nitro-server
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
Merging this PR will improve performance by 11.18%
Performance Changes
Comparing Footnotes
|
WalkthroughAdds in-process performance profiling across Nuxt: CLI docs for build, dev and generate include a new --profile[=verbose] flag. Introduces NuxtPerfProfiler class and attaches it to the Nuxt instance as an optional _perf API. Integrates phase timing around init, modules, app generation, bundling, Nitro build/dev flows and module setup. Instruments Vite plugins via a new PerfPlugin and wraps Rollup/Nitro hooks for per-hook timing. Adds schema/types support (debug.perf, NUXT_DEBUG_PERF) and export surface for perf methods, plus report/trace generation and lifecycle teardown. 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/schema/src/config/common.ts (1)
121-134:⚠️ Potential issue | 🟠 MajorDon’t make
debug: trueopt in to profiling.This branch now evaluates
perftotruewheneverNUXT_DEBUG_PERFis unset, so every existingdebug: trueproject will start CPU profiling and emit perf artefacts unexpectedly. Please keep perf explicit here.Suggested change
if (val === true) { return { templates: true, modules: true, watchers: true, hooks: { client: true, server: true, }, nitro: true, router: true, hydration: true, - perf: process.env.NUXT_DEBUG_PERF === 'quiet' ? 'quiet' : true, - } satisfies Required<NuxtDebugOptions> + ...(process.env.NUXT_DEBUG_PERF + ? { perf: process.env.NUXT_DEBUG_PERF === 'quiet' ? 'quiet' : true } + : {}), + } satisfies NuxtDebugOptions }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/schema/src/config/common.ts` around lines 121 - 134, The branch that handles val === true currently sets perf to true when NUXT_DEBUG_PERF is unset, enabling profiling by default; change it so perf is false unless NUXT_DEBUG_PERF is explicitly set (and 'quiet' maps to 'quiet'), e.g. make the perf value conditional on process.env.NUXT_DEBUG_PERF so it remains false by default and only enables profiling when the env var is present (and preserves the 'quiet' mapping); update the object returned in the val === true branch (the object annotated with satisfies Required<NuxtDebugOptions>) to implement this behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/kit/src/module/define.ts`:
- Around line 125-131: Wrap the module.setup invocation and timing in a
try/finally so nuxt._perf.endPhase(`module:${moduleName}`) always runs even if
module.setup throws: call nuxt._perf?.startPhase before invoking module.setup
(as already done), record start = performance.now(), then in a finally block
compute perf = performance.now() - start, set setupTime
(Math.round((perf*100))/100), call nuxt._perf?.endPhase(`module:${moduleName}`),
and rethrow any caught error so behavior is unchanged; update the code around
module.setup?.call(...) in define.ts to use this try/finally pattern.
In `@packages/nuxt/src/core/nuxt.ts`:
- Around line 943-955: The onSignal handler currently calls process.exit(0)
which masks interrupt failures; change it so after performing the flush/dispose
steps it preserves the original signal semantics by re-emitting the received
signal (e.g. process.kill(process.pid, signal)) or at minimum exits with a
non-zero code instead of 0; update the registration of the handlers
(process.once('SIGINT', onSignal) / process.once('SIGTERM', onSignal)) and
modify onSignal to accept the signal name (e.g. onSignal = (signal) => { ... })
so you can re-raise that same signal after flushing (or call process.exit(1) if
re-emitting is not feasible), and remove the unconditional process.exit(0) call.
- Around line 807-823: The profiler may be created too late because
options.debug.perf is only set after loadNuxtConfig; update the early-init logic
(around NuxtPerfProfiler, perf, cliStartTime and opts.overrides) to also check
the NUXT_DEBUG_PERF environment variable before calling loadNuxtConfig and start
the 'config' phase when true so the config loading is profiled consistently;
ensure the same code path that currently handles opts.overrides.debug.perf also
respects process.env.NUXT_DEBUG_PERF (and still falls back to options.debug.perf
after loadNuxtConfig), then keep perf?.endPhase('config') as-is.
In `@packages/nuxt/src/core/perf.ts`:
- Around line 94-95: Add a Biome-specific suppression comment immediately above
the ANSI_RE regex declaration to disable
lint/suspicious/noControlCharactersInRegex for this line; keep the existing
ESLint disable comment and insert a line like the suggested biome-ignore with a
brief justification so the ANSI_RE constant (const ANSI_RE = /\x1B\[[0-9;]*m/g)
is exempted from Biome's control-character-in-regex rule.
- Around line 173-191: stopCpuProfileSync is not actually synchronous (it uses
session.post callback) causing lost profiles on SIGINT; instead route the signal
handler through the existing async stopCpuProfile so we await the profiler stop
before calling process.exit. Update the SIGINT handler to call and await
stopCpuProfile() (not stopCpuProfileSync), ensure stopCpuProfile correctly uses
this.#cpuProfileSession and returns the output path after writing the file, and
remove or mark stopCpuProfileSync as unsafe/unused to avoid future misuse.
In `@packages/vite/src/plugins/perf.ts`:
- Around line 42-52: timedCall currently skips calling
nuxt._perf.recordBundlerPluginHook when the hook throws or returns a rejected
promise; wrap the synchronous invocation in a try/finally and ensure the async
path uses Promise.resolve(result).finally(...) so
recordBundlerPluginHook(pluginName, hookName, elapsed) always runs regardless of
success or failure, keeping the same performance measurement logic (use
performance.now() at start and compute delta in finally).
---
Outside diff comments:
In `@packages/schema/src/config/common.ts`:
- Around line 121-134: The branch that handles val === true currently sets perf
to true when NUXT_DEBUG_PERF is unset, enabling profiling by default; change it
so perf is false unless NUXT_DEBUG_PERF is explicitly set (and 'quiet' maps to
'quiet'), e.g. make the perf value conditional on process.env.NUXT_DEBUG_PERF so
it remains false by default and only enables profiling when the env var is
present (and preserves the 'quiet' mapping); update the object returned in the
val === true branch (the object annotated with satisfies
Required<NuxtDebugOptions>) to implement this behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: eefcb715-21c4-4868-b65f-d957553ea22a
📒 Files selected for processing (14)
docs/4.api/4.commands/build.mddocs/4.api/4.commands/dev.mddocs/4.api/4.commands/generate.mdpackages/kit/src/module/define.tspackages/nitro-server/src/index.tspackages/nuxt/src/core/app.tspackages/nuxt/src/core/builder.tspackages/nuxt/src/core/nuxt.tspackages/nuxt/src/core/perf.tspackages/schema/src/config/common.tspackages/schema/src/types/debug.tspackages/schema/src/types/nuxt.tspackages/vite/src/plugins/perf.tspackages/vite/src/vite.ts
| // Early-init profiler when CLI passes perf overrides (captures config loading). | ||
| // Otherwise, create after config resolves from nuxt.config / env vars. | ||
| let perf: NuxtPerfProfiler | undefined | ||
| const cliStartTime = (globalThis as any).__nuxt_cli__?.startTime as number | undefined | ||
| const perfOverride = typeof opts.overrides?.debug === 'object' && opts.overrides.debug.perf | ||
| if (perfOverride) { | ||
| perf = new NuxtPerfProfiler({ startTime: cliStartTime }) | ||
| perf.startPhase('config') | ||
| } | ||
|
|
||
| const options = await loadNuxtConfig(opts) | ||
|
|
||
| if (!perf && typeof options.debug === 'object' && options.debug.perf) { | ||
| perf = new NuxtPerfProfiler({ startTime: cliStartTime }) | ||
| } | ||
| perf?.endPhase('config') | ||
|
|
There was a problem hiding this comment.
Initialise the profiler before loadNuxtConfig() for the env-var flow.
NUXT_DEBUG_PERF=1 only becomes visible in options.debug.perf after config resolution, so this branch creates perf too late and the config phase never starts in the main workflow. Check the env var here as well so config loading is profiled consistently.
Suggested change
let perf: NuxtPerfProfiler | undefined
const cliStartTime = (globalThis as any).__nuxt_cli__?.startTime as number | undefined
const perfOverride = typeof opts.overrides?.debug === 'object' && opts.overrides.debug.perf
- if (perfOverride) {
+ const perfFromEnv = process.env.NUXT_DEBUG_PERF
+ if (perfOverride || perfFromEnv) {
perf = new NuxtPerfProfiler({ startTime: cliStartTime })
perf.startPhase('config')
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/core/nuxt.ts` around lines 807 - 823, The profiler may be
created too late because options.debug.perf is only set after loadNuxtConfig;
update the early-init logic (around NuxtPerfProfiler, perf, cliStartTime and
opts.overrides) to also check the NUXT_DEBUG_PERF environment variable before
calling loadNuxtConfig and start the 'config' phase when true so the config
loading is profiled consistently; ensure the same code path that currently
handles opts.overrides.debug.perf also respects process.env.NUXT_DEBUG_PERF (and
still falls back to options.debug.perf after loadNuxtConfig), then keep
perf?.endPhase('config') as-is.
packages/nuxt/src/core/nuxt.ts
Outdated
| // Signal handlers must be synchronous | ||
| const onSignal = () => { | ||
| if (!flushed) { | ||
| flushed = true | ||
| if (!quiet) { perf!.printReport({ title }) } | ||
| perf!.writeReportSync(nuxt.options.buildDir, { quiet }) | ||
| perf!.stopCpuProfileSync(nuxt.options.buildDir) | ||
| perf!.dispose() | ||
| } | ||
| process.exit(0) | ||
| } | ||
| process.once('SIGINT', onSignal) | ||
| process.once('SIGTERM', onSignal) |
There was a problem hiding this comment.
Don’t turn SIGINT/SIGTERM into a successful exit.
This handler always calls process.exit(0), so an interrupted profiled build is reported as success to shells and CI. Please preserve the signal semantics here by re-emitting the signal after flushing, or at least by setting the conventional non-zero exit code.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/core/nuxt.ts` around lines 943 - 955, The onSignal handler
currently calls process.exit(0) which masks interrupt failures; change it so
after performing the flush/dispose steps it preserves the original signal
semantics by re-emitting the received signal (e.g. process.kill(process.pid,
signal)) or at minimum exits with a non-zero code instead of 0; update the
registration of the handlers (process.once('SIGINT', onSignal) /
process.once('SIGTERM', onSignal)) and modify onSignal to accept the signal name
(e.g. onSignal = (signal) => { ... }) so you can re-raise that same signal after
flushing (or call process.exit(1) if re-emitting is not feasible), and remove
the unconditional process.exit(0) call.
| // eslint-disable-next-line no-control-regex | ||
| const ANSI_RE = /\x1B\[[0-9;]*m/g |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
python - <<'PY'
from pathlib import Path
path = Path("packages/nuxt/src/core/perf.ts")
line = path.read_text(encoding="utf-8", errors="surrogatepass").splitlines()[94]
print(repr(line))
print("Contains ESC byte:", "\x1b" in line)
PYRepository: nuxt/nuxt
Length of output: 115
🏁 Script executed:
# Check for Biome configuration files
find . -maxdepth 2 -type f \( -name "biome.json" -o -name "biome.jsonc" -o -name ".biomerc*" \) 2>/dev/null | head -20Repository: nuxt/nuxt
Length of output: 65
🏁 Script executed:
# Check if there are any Biome suppress comments in the codebase
rg "@biome.*noControlCharactersInRegex|biome.*suppress.*regex" --type ts --type tsx -A 2 -B 2 | head -50Repository: nuxt/nuxt
Length of output: 80
🏁 Script executed:
# Check the context around line 94-95 in perf.ts
sed -n '90,100p' packages/nuxt/src/core/perf.tsRepository: nuxt/nuxt
Length of output: 437
🌐 Web query:
Biome linter suppress control characters in regex comment syntax
💡 Result:
To suppress Biome’s “control characters in regex” diagnostic (lint/suspicious/noControlCharactersInRegex), add a suppression comment on the line above the regex literal:
// biome-ignore lint/suspicious/noControlCharactersInRegex: needed for this pattern
const re = /\x00/;For a larger block, use a range suppression:
// biome-ignore-start lint/suspicious/noControlCharactersInRegex: vendor regex
const a = /\x00/;
const b = /\u000C/;
// biome-ignore-end lint/suspicious/noControlCharactersInRegex: vendor regexSources: Biome suppression comment syntax and range suppressions [1]; rule category/name for this diagnostic [2].
Add Biome suppression comment for regex control character rule.
The ESLint suppression does not suppress Biome's lint/suspicious/noControlCharactersInRegex rule. Add a Biome-specific suppression comment above the regex:
Suggested fix
// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences required for stripping formatting
const ANSI_RE = /\x1B\[[0-9;]*m/g
🧰 Tools
🪛 Biome (2.4.4)
[error] 95-95: Unexpected control character in a regular expression.
(lint/suspicious/noControlCharactersInRegex)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/core/perf.ts` around lines 94 - 95, Add a Biome-specific
suppression comment immediately above the ANSI_RE regex declaration to disable
lint/suspicious/noControlCharactersInRegex for this line; keep the existing
ESLint disable comment and insert a line like the suggested biome-ignore with a
brief justification so the ANSI_RE constant (const ANSI_RE = /\x1B\[[0-9;]*m/g)
is exempted from Biome's control-character-in-regex rule.
packages/nuxt/src/core/perf.ts
Outdated
| stopCpuProfileSync (buildDir: string): string | undefined { | ||
| const session = this.#cpuProfileSession | ||
| if (!session) { return } | ||
| this.#cpuProfileSession = undefined | ||
| let outPath: string | undefined | ||
| session.post('Profiler.stop', (_err, params) => { | ||
| if (_err || !params?.profile) { return } | ||
| outPath = join(buildDir, `profile-${this.#cpuProfileCount++}.cpuprofile`) | ||
| try { | ||
| mkdirSync(buildDir, { recursive: true }) | ||
| writeFileSync(outPath, JSON.stringify(params.profile)) | ||
| consola.info(`CPU profile written to ${colors.cyan(outPath)}`) | ||
| consola.info(`Open it in ${colors.cyan('https://www.speedscope.app')} or Chrome DevTools`) | ||
| } catch { | ||
| // don't throw an error if we can't write the file | ||
| } | ||
| session.disconnect() | ||
| }) | ||
| return outPath |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Node.js, does inspector.Session.post('Profiler.stop', callback) complete asynchronously, and is there any synchronous API for stopping a CPU profile?
💡 Result:
Yes—session.post('Profiler.stop', callback) completes asynchronously: Session.post() sends a message to the inspector backend and the callback is invoked later, when the response is received (i.e., not synchronously during the post() call). [1]
There is no synchronous API in Node’s inspector interface for stopping (and retrieving) a CPU profile. The supported APIs are the callback form (session.post(..., callback)) and the Promise-based form (await session.post('Profiler.stop') via node:inspector/promises). [1]
Sources:
[1] Node.js Inspector docs (inspector.Session.post(...), callback notified on response; Promise-based session.post usage incl. Profiler.stop) (nodejs.org)
Citations:
🏁 Script executed:
# Search for calls to stopCpuProfileSync to understand the context
rg 'stopCpuProfileSync' packages/nuxt/src/core/Repository: nuxt/nuxt
Length of output: 232
🏁 Script executed:
# Look for the async stopCpuProfile method and the signal path handling
rg 'stopCpuProfile|signal.*exit|process.*exit' packages/nuxt/src/core/nuxt.ts -A 2 -B 2Repository: nuxt/nuxt
Length of output: 541
🏁 Script executed:
# Look for the onSignal function definition and its full context
rg -B 10 'process\.once.*SIGINT.*onSignal' packages/nuxt/src/core/nuxt.ts | head -50Repository: nuxt/nuxt
Length of output: 396
🏁 Script executed:
# Find the stopCpuProfile (async) method definition to confirm it exists and is async
rg -A 15 'stopCpuProfile\s*\(' packages/nuxt/src/core/perf.ts | grep -v 'stopCpuProfileSync'Repository: nuxt/nuxt
Length of output: 868
stopCpuProfileSync() is not actually synchronous and causes profile data loss on interrupt.
session.post() completes asynchronously via callback, so the method returns before outPath is assigned. In the SIGINT signal handler path, process.exit(0) is called immediately afterwards, meaning the async callback never completes and the profile file is never written. The async stopCpuProfile() method already exists and correctly handles this flow—route the signal handler through it via await to preserve profile data on interrupt.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/core/perf.ts` around lines 173 - 191, stopCpuProfileSync is
not actually synchronous (it uses session.post callback) causing lost profiles
on SIGINT; instead route the signal handler through the existing async
stopCpuProfile so we await the profiler stop before calling process.exit. Update
the SIGINT handler to call and await stopCpuProfile() (not stopCpuProfileSync),
ensure stopCpuProfile correctly uses this.#cpuProfileSession and returns the
output path after writing the file, and remove or mark stopCpuProfileSync as
unsafe/unused to avoid future misuse.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/nuxt/src/core/perf.ts (1)
480-494: Silent error swallowing may hide filesystem issues.The
catchblock silently discards all errors. Consider logging a debug message so users can diagnose permission or disk space issues when the report fails to write.Suggested improvement
} catch { - // don't throw an error if we can't write the file + // don't throw an error if we can't write the file, but log for debugging + consola.debug(`Failed to write perf report to ${reportPath}`) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/src/core/perf.ts` around lines 480 - 494, The writeReportSync function currently swallows all errors in its catch, which hides filesystem problems; update the catch in writeReportSync to log the caught error (including error.message and context like reportPath and buildDir) at a debug or trace level (e.g., via consola.debug or existing logger) so failures to mkdirSync/writeFileSync are recorded, and preserve the current behavior of not throwing; reference writeReportSync, reportPath, buildDir and options to include useful context in the log.packages/nitro-server/src/index.ts (1)
775-803: Consider extracting shared timing wrapper.The plugin hook timing logic (lines 785-799) duplicates the
timedCallpattern frompackages/vite/src/plugins/perf.ts. Consider extracting this to a shared utility in the perf module to reduce duplication and ensure consistent behaviour.Example shared utility location
The timing wrapper could be exported from
packages/nuxt/src/core/perf.ts:export function createTimedHookWrapper( original: (...args: any[]) => any, ctx: any, args: any[], record: () => void ): any { try { const result = original.apply(ctx, args) if (result && typeof result === 'object' && 'then' in result) { return (result as Promise<any>).finally(record) } record() return result } catch (err) { record() throw err } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nitro-server/src/index.ts` around lines 775 - 803, Extract the duplicated timing wrapper into a shared utility and use it here: create a function (e.g. createTimedHookWrapper or timedCall) in the perf module (referenced by nuxt._perf usage) that accepts the original function, this/context, args and a record callback and implements the try/await/finally pattern currently in the inline wrapper; then replace the inline wrapper inside the nitro.hooks.hook loop (where plugin[hookName] is reassigned for each hookName) to call that shared utility instead of duplicating the timing logic so both packages/vite/src/plugins/perf.ts and this file use the same implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/nitro-server/src/index.ts`:
- Around line 775-803: Extract the duplicated timing wrapper into a shared
utility and use it here: create a function (e.g. createTimedHookWrapper or
timedCall) in the perf module (referenced by nuxt._perf usage) that accepts the
original function, this/context, args and a record callback and implements the
try/await/finally pattern currently in the inline wrapper; then replace the
inline wrapper inside the nitro.hooks.hook loop (where plugin[hookName] is
reassigned for each hookName) to call that shared utility instead of duplicating
the timing logic so both packages/vite/src/plugins/perf.ts and this file use the
same implementation.
In `@packages/nuxt/src/core/perf.ts`:
- Around line 480-494: The writeReportSync function currently swallows all
errors in its catch, which hides filesystem problems; update the catch in
writeReportSync to log the caught error (including error.message and context
like reportPath and buildDir) at a debug or trace level (e.g., via consola.debug
or existing logger) so failures to mkdirSync/writeFileSync are recorded, and
preserve the current behavior of not throwing; reference writeReportSync,
reportPath, buildDir and options to include useful context in the log.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9c2b38ed-4c0e-4a76-960d-2d893f0e4290
📒 Files selected for processing (8)
packages/kit/src/module/define.tspackages/nitro-server/src/index.tspackages/nuxt/src/core/builder.tspackages/nuxt/src/core/nuxt.tspackages/nuxt/src/core/perf.tspackages/schema/src/config/common.tspackages/schema/src/types/nuxt.tspackages/vite/src/plugins/perf.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/schema/src/config/common.ts
- packages/nuxt/src/core/builder.ts
- packages/kit/src/module/define.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/nuxt/src/core/perf.ts (2)
696-696: Minor: Redundant double-rounding.
round(hp.duration - round(attributedTime))appliesround()twice. The inner round isn't necessary sinceattributedTimeis derived from already-precise floating-point arithmetic.Suggested fix
- const ownDuration = round(hp.duration - round(attributedTime)) + const ownDuration = round(hp.duration - attributedTime)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/src/core/perf.ts` at line 696, The calculation for ownDuration currently double-rounds: in the expression assigning ownDuration (using hp.duration and attributedTime) remove the inner round() around attributedTime so you call round once on the final difference; update the assignment of ownDuration from round(hp.duration - round(attributedTime)) to round(hp.duration - attributedTime) to avoid redundant rounding while keeping the final rounding via round().
659-661: Consider logging a warning on write failure.Silently catching write errors may hide file system issues (e.g., permissions, disk full). A brief warning would help users diagnose why perf reports are missing without failing the build.
Suggested change
- } catch { - // don't throw an error if we can't write the file + } catch (err) { + if (!options?.quiet) { + consola.warn('Failed to write performance report:', err) + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/src/core/perf.ts` around lines 659 - 661, The silent catch around the perf report file write should log a brief warning instead of swallowing errors; modify the catch to capture the error (e.g., catch (err)) and emit a warning via the module's logger or console.warn that includes the error message and the target file path (the same write operation in perf.ts where the file is written), so users see filesystem issues (permissions, disk full) without failing the build.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/nuxt/src/core/perf.ts`:
- Line 696: The calculation for ownDuration currently double-rounds: in the
expression assigning ownDuration (using hp.duration and attributedTime) remove
the inner round() around attributedTime so you call round once on the final
difference; update the assignment of ownDuration from round(hp.duration -
round(attributedTime)) to round(hp.duration - attributedTime) to avoid redundant
rounding while keeping the final rounding via round().
- Around line 659-661: The silent catch around the perf report file write should
log a brief warning instead of swallowing errors; modify the catch to capture
the error (e.g., catch (err)) and emit a warning via the module's logger or
console.warn that includes the error message and the target file path (the same
write operation in perf.ts where the file is written), so users see filesystem
issues (permissions, disk full) without failing the build.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8cee29c1-197e-4847-90be-c2eab3d7326a
📒 Files selected for processing (5)
packages/nitro-server/src/index.tspackages/nuxt/src/core/nuxt.tspackages/nuxt/src/core/perf.tspackages/schema/src/types/nuxt.tspackages/vite/src/plugins/perf.ts
🔗 Linked issue
📚 Description
you can test with:
this produces a report that looks like this after a build:
🚧 TODO
integrate with vite's profilerwe launch our own cpu profiler--profileflag innuxt/cli