Skip to content

feat(build,dev): add --profile support#1243

Merged
danielroe merged 13 commits intomainfrom
feat/profile-2
Mar 10, 2026
Merged

feat(build,dev): add --profile support#1243
danielroe merged 13 commits intomainfrom
feat/profile-2

Conversation

@danielroe
Copy link
Member

🔗 Linked issue

📚 Description

paired with nuxt/nuxt#34468 - this allows enabling profiling nuxt builds with a new --profile flag

@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

📦 Bundle Size Comparison

📈 nuxi

Metric Base Head Diff
Rendered 3375.70 KB 3698.79 KB +323.09 KB (+9.57%)

📈 nuxt-cli

Metric Base Head Diff
Rendered 138.80 KB 142.04 KB +3.23 KB (+2.33%)

📈 create-nuxt

Metric Base Head Diff
Rendered 1645.98 KB 1646.02 KB +0.04 KB (+0.00%)

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 9, 2026

  • nuxt-cli-playground

    npm i https://pkg.pr.new/create-nuxt@1243
    
    npm i https://pkg.pr.new/nuxi@1243
    
    npm i https://pkg.pr.new/@nuxt/cli@1243
    

commit: 61d3b93

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 9, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing feat/profile-2 (61d3b93) with main (77f8619)

Open in CodSpeed

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds CLI CPU profiling support across nuxi: introduces exported profileArgs for --profile, a new profiling utility (startCpuProfile / stopCpuProfile), and wiring to start/stop inspector-based CPU profiling from the CLI entry points. The build, dev, and generate commands include profileArgs; build and dev flows compute a perf mode and inject a Nitro debug.perf override when profiling. Dev context args gain profile?: string | boolean, and a cpuProfileSession field is stored on globalThis.__nuxt_cli__ with corresponding type declaration.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(build,dev): add --profile support' directly and clearly summarizes the main change: adding a new --profile flag for profiling Nuxt builds and dev commands.
Description check ✅ Passed The description explains that the PR adds profiling support with a new --profile flag, which directly relates to the changeset that implements this feature across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/profile-2

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/nuxi/src/commands/build.ts`:
- Around line 67-68: The issue is that spreading ctx.data?.overrides after
adding { debug: { perf: perfValue } } replaces any existing overrides.debug and
can silently discard --profile; fix by merging the debug objects instead of
replacing them: build a merged debug object from ctx.data?.overrides?.debug and
the new perf entry (e.g. merge existing debug first, then add perf if perfValue)
and then spread that merged debug into the final options while still spreading
the rest of ctx.data?.overrides; update the construction that currently uses
...(perfValue && { debug: { perf: perfValue } }), ...ctx.data?.overrides to use
the merged debug so both existing debug keys and the perf flag are preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 91ef465f-202c-404a-a1ca-c975b68814e6

📥 Commits

Reviewing files that changed from the base of the PR and between 914cac7 and 338aebf.

📒 Files selected for processing (3)
  • packages/nuxi/src/commands/_shared.ts
  • packages/nuxi/src/commands/build.ts
  • packages/nuxi/src/dev/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nuxi/src/dev/index.ts
  • packages/nuxi/src/commands/_shared.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
packages/nuxi/bin/nuxi.mjs (1)

29-41: ⚠️ Potential issue | 🟠 Major

Same profiler bootstrap error-handling bug as the sibling entrypoint.

This block also ignores Profiler.enable errors and resolves the promise on Profiler.start errors, so it can cache a cpuProfileSession that never actually started.

Node.js inspector Session.post callback signature and how errors are reported for Profiler.enable / Profiler.start
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/bin/nuxi.mjs` around lines 29 - 41, The profiler bootstrap
currently ignores errors from inspector.Session.post calls and may set
globalThis.__nuxt_cli__.cpuProfileSession even if Profiler.enable or
Profiler.start failed; update the boot logic around inspector.Session/
session.post so the Profiler.enable callback checks its first (error) argument
and only calls session.post('Profiler.start') when enable succeeded, and the
Profiler.start callback also checks its error argument and only then assigns
globalThis.__nuxt_cli__.cpuProfileSession = session; if either callback reports
an error, disconnect the session and resolve the promise without setting
cpuProfileSession to avoid caching a non-started session.
packages/nuxi/src/commands/build.ts (1)

71-77: ⚠️ Potential issue | 🟡 Minor

ctx.data?.overrides still overwrites the merged debug block.

Because the full overrides object is spread after the merged debug value, any caller that already passes ctx.data?.overrides.debug replaces perf again. That still makes --profile a no-op for composed callers.

Suggested fix
-        ...((perfValue || ctx.data?.overrides?.debug) && {
-          debug: {
-            ...ctx.data?.overrides?.debug,
-            ...(perfValue && { perf: perfValue }),
-          },
-        }),
         ...ctx.data?.overrides,
+        ...((perfValue || ctx.data?.overrides?.debug) && {
+          debug: {
+            ...ctx.data?.overrides?.debug,
+            ...(perfValue && { perf: perfValue }),
+          },
+        }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/src/commands/build.ts` around lines 71 - 77, The merged debug
block is being overwritten because ...ctx.data?.overrides is spread after the
constructed debug object; update the merge order so the final overrides preserve
the injected perf value by either (A) spreading ctx.data?.overrides first and
then spreading the constructed debug block after, or (B) build a single
overrides object like overrides = { ...ctx.data?.overrides, debug: {
...ctx.data?.overrides?.debug, ...(perfValue && { perf: perfValue }) } } and use
that; reference the existing symbols ctx.data?.overrides, debug and perfValue
when making the change so --profile (perfValue) wins over callers' debug.debug.
🤖 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/nuxi/src/commands/build.ts`:
- Around line 43-47: The profiling is started unconditionally when profileArg is
set (profileArg and startCpuProfile in build.ts) but not reliably stopped on
errors; wrap the entire profiled build region (everything after startCpuProfile
up through where stopCpuProfile should run) in a try/finally so stopCpuProfile
is always called (await it if it becomes async), using profileArg to gate
start/stop and ensuring perfValue logic remains the same; locate
startCpuProfile/stopCpuProfile calls in the build command and move
stopCpuProfile into the finally block to guarantee cleanup on exceptions.

In `@packages/nuxi/src/utils/profile.ts`:
- Around line 17-31: The Profiler.enable callback currently ignores its error
and can allow Profiler.start to run on a failed session and leave a connected
session in global state; update the startup Promise so the callback for
session.post('Profiler.enable', ...) checks the error and rejects if present,
and in any rejection path disconnect the session (call session.disconnect()) and
clear the global session reference (set session = undefined) before
rethrowing/returning the error; ensure the same cleanup happens if
Profiler.start's callback returns an error so the session is not left connected
in a broken state.
- Around line 34-55: stopCpuProfile currently returns before the inspector
callback runs and can skip s.disconnect; change stopCpuProfile to return a
Promise<string|undefined> (make it async) so it waits for the Profiler.stop
callback to finish and resolves with outPath only after the file write
completes; ensure you always call s.disconnect() even on errors, reject or
resolve accordingly, and keep the early-return when there is no session by
returning Promise.resolve(undefined); update callers (e.g., build.ts and
dev/index.ts) to await stopCpuProfile(...) so exit handlers get the correct
value.

In `@packages/nuxt-cli/bin/nuxi.mjs`:
- Around line 29-41: The profiler startup promise currently resolves even if
inspector.Session.post('Profiler.enable') or session.post('Profiler.start')
return errors, which stores a broken session in
globalThis.__nuxt_cli__.cpuProfileSession; change the new Promise used around
inspector.Session() so both post callbacks check their error argument and reject
the promise on error (only resolve after Profiler.start succeeds), and only
assign globalThis.__nuxt_cli__.cpuProfileSession = session after the promise
fulfills successfully; reference inspector.Session,
session.post('Profiler.enable'), session.post('Profiler.start') and
globalThis.__nuxt_cli__.cpuProfileSession when making the change.

---

Duplicate comments:
In `@packages/nuxi/bin/nuxi.mjs`:
- Around line 29-41: The profiler bootstrap currently ignores errors from
inspector.Session.post calls and may set
globalThis.__nuxt_cli__.cpuProfileSession even if Profiler.enable or
Profiler.start failed; update the boot logic around inspector.Session/
session.post so the Profiler.enable callback checks its first (error) argument
and only calls session.post('Profiler.start') when enable succeeded, and the
Profiler.start callback also checks its error argument and only then assigns
globalThis.__nuxt_cli__.cpuProfileSession = session; if either callback reports
an error, disconnect the session and resolve the promise without setting
cpuProfileSession to avoid caching a non-started session.

In `@packages/nuxi/src/commands/build.ts`:
- Around line 71-77: The merged debug block is being overwritten because
...ctx.data?.overrides is spread after the constructed debug object; update the
merge order so the final overrides preserve the injected perf value by either
(A) spreading ctx.data?.overrides first and then spreading the constructed debug
block after, or (B) build a single overrides object like overrides = {
...ctx.data?.overrides, debug: { ...ctx.data?.overrides?.debug, ...(perfValue &&
{ perf: perfValue }) } } and use that; reference the existing symbols
ctx.data?.overrides, debug and perfValue when making the change so --profile
(perfValue) wins over callers' debug.debug.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 537bcdcf-1f7e-4d18-b05b-4c01addaaecd

📥 Commits

Reviewing files that changed from the base of the PR and between 338aebf and 74916dd.

📒 Files selected for processing (6)
  • packages/nuxi/bin/nuxi.mjs
  • packages/nuxi/src/commands/build.ts
  • packages/nuxi/src/dev/index.ts
  • packages/nuxi/src/utils/profile.ts
  • packages/nuxt-cli/bin/nuxi.mjs
  • types.d.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nuxi/src/dev/index.ts

Comment on lines +34 to +55
export function stopCpuProfile(outDir: string): string | undefined {
if (!session) {
return
}
const s = session
session = undefined
let outPath: string | undefined
s.post('Profiler.stop', (_err, params) => {
if (_err || !params?.profile) {
return
}
outPath = join(outDir, `profile-${profileCount++}.cpuprofile`)
try {
mkdirSync(outDir, { recursive: true })
writeFileSync(outPath, JSON.stringify(params.profile))
logger.info(`CPU profile written to ${colors.cyan(outPath)}`)
logger.info(`Open it in ${colors.cyan('https://www.speedscope.app')} or Chrome DevTools`)
}
catch {}
s.disconnect()
})
return outPath
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Can asynchronous work scheduled inside process.on('exit') run in Node.js, and does inspector.Session.post complete synchronously or via a later callback?

💡 Result:

No.

  • In process.on('exit', ...), listeners must only do synchronous work; Node exits immediately after the 'exit' listeners finish, and any work you schedule onto the event loop (timers, I/O, promise continuations, etc.) is abandoned (e.g., a setTimeout(..., 0) “will not run”). [1]
    If you need to extend the life of the process to finish async cleanup, use 'beforeExit' (when the process is exiting naturally), because a 'beforeExit' handler may schedule async work and keep the process alive. [2]

  • inspector.Session.post(...) is not “synchronously complete” in the sense of “you have the result when post() returns”. It posts a message and the result is delivered later, via the callback (“notified when a response is received”) or, in the promises API, by the returned Promise. [3]
    So, calling session.post(..., cb) inside an 'exit' handler should not be expected to run cb, because that requires the event loop to continue. [1][3]

Sources
[1] Node.js docs — process 'exit' event: synchronous-only; queued work abandoned https://nodejs.org/api/process.html
[2] Node.js docs — process 'beforeExit' event: async work can keep process alive https://nodejs.org/api/process.html
[3] Node.js docs — inspector.Session.post: callback notified when response is received / promises API https://nodejs.org/api/inspector.html


🏁 Script executed:

# Find calls to stopCpuProfile in the codebase
rg "stopCpuProfile" --type typescript --type ts --context 3

Repository: nuxt/cli

Length of output: 86


🏁 Script executed:

# Find calls to stopCpuProfile in the codebase
rg "stopCpuProfile" -A 3 -B 3

Repository: nuxt/cli

Length of output: 2162


🏁 Script executed:

# Get the full context of the dev/index.ts call
rg "process.once\('exit'" -A 1 -B 2 packages/nuxi/src/dev/index.ts

Repository: nuxt/cli

Length of output: 139


stopCpuProfile returns before the profile is written and does not run in exit handlers.

Profiler.stop completes asynchronously, so this function returns while outPath is still undefined and before the file write runs. In packages/nuxi/src/dev/index.ts, this is called from process.once('exit', ...), where async inspector callbacks will not execute because Node.js abandons the event loop once 'exit' listeners finish. The build flow also receives an incorrect return value. Additionally, the early return on error skips s.disconnect().

Suggested fix
-export function stopCpuProfile(outDir: string): string | undefined {
+export async function stopCpuProfile(outDir: string): Promise<string | undefined> {
   if (!session) {
     return
   }
   const s = session
   session = undefined
-  let outPath: string | undefined
-  s.post('Profiler.stop', (_err, params) => {
-    if (_err || !params?.profile) {
-      return
-    }
-    outPath = join(outDir, `profile-${profileCount++}.cpuprofile`)
+  try {
+    const params = await new Promise<any>((resolve, reject) => {
+      s.post('Profiler.stop', (err, params) => {
+        if (err) {
+          return reject(err)
+        }
+        resolve(params)
+      })
+    })
+    if (!params?.profile) {
+      return
+    }
+    const outPath = join(outDir, `profile-${profileCount++}.cpuprofile`)
     try {
       mkdirSync(outDir, { recursive: true })
       writeFileSync(outPath, JSON.stringify(params.profile))
       logger.info(`CPU profile written to ${colors.cyan(outPath)}`)
       logger.info(`Open it in ${colors.cyan('https://www.speedscope.app')} or Chrome DevTools`)
     }
     catch {}
-    s.disconnect()
-  })
-  return outPath
+    return outPath
+  }
+  finally {
+    s.disconnect()
+  }
 }

Update call sites in build.ts and dev/index.ts to use await stopCpuProfile(...).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/src/utils/profile.ts` around lines 34 - 55, stopCpuProfile
currently returns before the inspector callback runs and can skip s.disconnect;
change stopCpuProfile to return a Promise<string|undefined> (make it async) so
it waits for the Profiler.stop callback to finish and resolves with outPath only
after the file write completes; ensure you always call s.disconnect() even on
errors, reject or resolve accordingly, and keep the early-return when there is
no session by returning Promise.resolve(undefined); update callers (e.g.,
build.ts and dev/index.ts) to await stopCpuProfile(...) so exit handlers get the
correct value.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/nuxi/src/commands/build.ts (1)

91-93: Consider adding an explanatory comment inside the catch block.

The empty catch is intentional for backward compatibility, but the placeholder // comment doesn't convey the intent. Consider adding a brief note like // Expected in Bridge or older Nuxt versions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/src/commands/build.ts` around lines 91 - 93, Update the empty
catch block in packages/nuxi/src/commands/build.ts to include a concise
explanatory comment explaining the intentional no-op for backward compatibility
(e.g., note about Bridge or older Nuxt versions) so future readers understand
this is deliberate; locate the catch associated with the build command logic and
replace the placeholder `//` with a short comment referencing that it's an
expected no-op for compatibility rather than swallowing an unexpected error.
🤖 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/nuxi/src/commands/build.ts`:
- Around line 99-102: The hook registered on nuxt.hook('build:error') currently
calls logger.error(...) then process.exit(1), which bypasses the surrounding
try/finally and loses CPU profiling data; change this to either re-throw the
error (throw err) so the error propagates and the finally block runs, or call
stopCpuProfile() (the profiler shutdown function used elsewhere) before calling
process.exit(1) so profiling is saved; update the handler attached to
'build:error' (and remove direct process.exit(1) usage) to ensure finally logic
that writes profiling data is always executed.

---

Nitpick comments:
In `@packages/nuxi/src/commands/build.ts`:
- Around line 91-93: Update the empty catch block in
packages/nuxi/src/commands/build.ts to include a concise explanatory comment
explaining the intentional no-op for backward compatibility (e.g., note about
Bridge or older Nuxt versions) so future readers understand this is deliberate;
locate the catch associated with the build command logic and replace the
placeholder `//` with a short comment referencing that it's an expected no-op
for compatibility rather than swallowing an unexpected error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07f7b316-de8d-49bc-a883-c7a39843f6ff

📥 Commits

Reviewing files that changed from the base of the PR and between 74916dd and 26b08e5.

📒 Files selected for processing (3)
  • packages/nuxi/src/commands/build.ts
  • packages/nuxi/src/utils/profile.ts
  • packages/nuxt-cli/bin/nuxi.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nuxt-cli/bin/nuxi.mjs
  • packages/nuxi/src/utils/profile.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
packages/nuxi/src/utils/profile.ts (1)

48-70: ⚠️ Potential issue | 🟠 Major

Return the written path from stopCpuProfile.

This function is typed as Promise<string | undefined>, but the success path never returns outPath, so callers always get undefined even after the profile is flushed.

Suggested fix
-  const outPath = join(outDir, `profile-${profileCount++}.cpuprofile`)
   try {
-    await new Promise<any>((resolve, reject) => {
+    const params = await new Promise<any>((resolve, reject) => {
       s.post('Profiler.stop', (err, params) => {
         if (err) {
           return reject(err)
         }
-
-        if (!params?.profile) {
-          return resolve(params)
-        }
-
-        try {
-          mkdirSync(outDir, { recursive: true })
-          writeFileSync(outPath, JSON.stringify(params.profile))
-          logger.info(`CPU profile written to ${colors.cyan(outPath)}`)
-          logger.info(`Open it in ${colors.cyan('https://www.speedscope.app')} or Chrome DevTools`)
-        }
-        catch {}
-
         resolve(params)
       })
     })
+    if (!params?.profile) {
+      return
+    }
+
+    const outPath = join(outDir, `profile-${profileCount++}.cpuprofile`)
+    try {
+      mkdirSync(outDir, { recursive: true })
+      writeFileSync(outPath, JSON.stringify(params.profile))
+      logger.info(`CPU profile written to ${colors.cyan(outPath)}`)
+      logger.info(`Open it in ${colors.cyan('https://www.speedscope.app')} or Chrome DevTools`)
+      return outPath
+    }
+    catch {}
   }
   finally {
     s.disconnect()
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/src/utils/profile.ts` around lines 48 - 70, The function
stopCpuProfile currently resolves the internal Promise with params even when a
profile file is written, causing callers to get undefined despite the function
being typed Promise<string | undefined>; change the resolve path so that when
params?.profile is present and the file write succeeds you resolve(outPath) (use
the existing outPath local variable), keep resolving undefined (or
resolve(params) if you prefer undefined) when params?.profile is absent, and
ensure the outer stopCpuProfile returns the awaited value so callers receive the
written path; look for the s.post('Profiler.stop') callback, the params.profile
check, and the outPath/profileCount identifiers to locate where to change
resolve(params) to resolve(outPath) inside the try that writes the file.
packages/nuxi/src/commands/build.ts (1)

99-105: ⚠️ Potential issue | 🟠 Major

Don’t exit from the build:error hook while profiling is active.

stopCpuProfile() is async, but this hook fire-and-forgets it and then immediately calls process.exit(1), so the finally block never gets a chance to await the profile flush on failing builds. Let the build failure propagate to the surrounding try/finally instead of shutting down here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nuxi/src/commands/build.ts` around lines 99 - 105, The build:error
hook currently logs the error, calls stopCpuProfile(cwd) (which is async) and
then calls process.exit(1), preventing the surrounding try/finally from awaiting
profile flush; change the handler so it no longer terminates the process or
attempts to synchronously stop profiling: in the nuxt.hook('build:error', (err)
=> { ... }) callback keep the logger.error(...) but remove the call to
process.exit(1) and do not fire-and-forget stopCpuProfile(cwd) here; instead let
the error propagate (rethrow the err or omit swallowing it) so the outer
try/finally can await stopCpuProfile(cwd) and ensure the CPU profile is flushed
correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/nuxi/src/commands/build.ts`:
- Around line 99-105: The build:error hook currently logs the error, calls
stopCpuProfile(cwd) (which is async) and then calls process.exit(1), preventing
the surrounding try/finally from awaiting profile flush; change the handler so
it no longer terminates the process or attempts to synchronously stop profiling:
in the nuxt.hook('build:error', (err) => { ... }) callback keep the
logger.error(...) but remove the call to process.exit(1) and do not
fire-and-forget stopCpuProfile(cwd) here; instead let the error propagate
(rethrow the err or omit swallowing it) so the outer try/finally can await
stopCpuProfile(cwd) and ensure the CPU profile is flushed correctly.

In `@packages/nuxi/src/utils/profile.ts`:
- Around line 48-70: The function stopCpuProfile currently resolves the internal
Promise with params even when a profile file is written, causing callers to get
undefined despite the function being typed Promise<string | undefined>; change
the resolve path so that when params?.profile is present and the file write
succeeds you resolve(outPath) (use the existing outPath local variable), keep
resolving undefined (or resolve(params) if you prefer undefined) when
params?.profile is absent, and ensure the outer stopCpuProfile returns the
awaited value so callers receive the written path; look for the
s.post('Profiler.stop') callback, the params.profile check, and the
outPath/profileCount identifiers to locate where to change resolve(params) to
resolve(outPath) inside the try that writes the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6c6666f3-4aaa-46cb-8216-14b1384ab967

📥 Commits

Reviewing files that changed from the base of the PR and between 26b08e5 and 4acc72c.

📒 Files selected for processing (4)
  • packages/nuxi/bin/nuxi.mjs
  • packages/nuxi/src/commands/build.ts
  • packages/nuxi/src/utils/profile.ts
  • types.d.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nuxi/bin/nuxi.mjs
  • types.d.ts

@danielroe danielroe merged commit e2c9686 into main Mar 10, 2026
21 of 22 checks passed
@danielroe danielroe deleted the feat/profile-2 branch March 10, 2026 10:31
@github-actions github-actions bot mentioned this pull request Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant