diff --git a/docs/3.api/4.advanced/1.hooks.md b/docs/3.api/4.advanced/1.hooks.md index af93555a06..151446493d 100644 --- a/docs/3.api/4.advanced/1.hooks.md +++ b/docs/3.api/4.advanced/1.hooks.md @@ -38,7 +38,7 @@ Hook | Arguments | Description `kit:compatibility` | `compatibility, issues` | Allows extending compatibility checks. `ready` | `nuxt` | Called after Nuxt initialization, when the Nuxt instance is ready to work. `close` | `nuxt` | Called when Nuxt instance is gracefully closing. -`restart` | - | Called to restart the current Nuxt instance. **This hook is currently only available on the [Edge Channel](/docs/guide/going-further/edge-channel/).** +`restart` | `{ hard?: boolean }` | To be called to restart the current Nuxt instance. **This hook is currently only available on the [Edge Channel](/docs/guide/going-further/edge-channel/).** `modules:before` | - | Called during Nuxt initialization, before installing user modules. `modules:done` | - | Called during Nuxt initialization, after installing user modules. `app:resolve` | `app` | Called after resolving the `app` instance. diff --git a/packages/nuxi/bin/nuxi.mjs b/packages/nuxi/bin/nuxi.mjs index b6bf5f6a68..8dcfc256bd 100755 --- a/packages/nuxi/bin/nuxi.mjs +++ b/packages/nuxi/bin/nuxi.mjs @@ -1,3 +1,2 @@ #!/usr/bin/env node -process._startTime = Date.now() -import('../dist/cli.mjs').then(r => (r.default || r).main()) +import('../dist/cli-wrapper.mjs') diff --git a/packages/nuxi/build.config.ts b/packages/nuxi/build.config.ts index 294834abe4..522086d61a 100644 --- a/packages/nuxi/build.config.ts +++ b/packages/nuxi/build.config.ts @@ -10,6 +10,8 @@ export default defineBuildConfig({ }, entries: [ 'src/cli', + 'src/cli-run', + 'src/cli-wrapper', 'src/index' ], externals: [ diff --git a/packages/nuxi/src/cli-run.ts b/packages/nuxi/src/cli-run.ts new file mode 100644 index 0000000000..56c55f22b4 --- /dev/null +++ b/packages/nuxi/src/cli-run.ts @@ -0,0 +1,4 @@ +// @ts-ignore +process._startTime = Date.now() +// @ts-ignore +import('./cli').then(r => (r.default || r).main()) diff --git a/packages/nuxi/src/cli-wrapper.ts b/packages/nuxi/src/cli-wrapper.ts new file mode 100644 index 0000000000..58a25250ab --- /dev/null +++ b/packages/nuxi/src/cli-wrapper.ts @@ -0,0 +1,40 @@ +/** + * This file is used to wrap the CLI entrypoint in a restartable process. + */ +import { fileURLToPath } from 'node:url' +import { execa } from 'execa' +import { EXIT_CODE_RESTART } from './constants' + +const cliEntry = fileURLToPath(new URL('../dist/cli-run.mjs', import.meta.url)) + +async function startSubprocess (preArgs: string[], postArgs: string[]) { + const child = await execa( + 'node', + [ + ...preArgs, + cliEntry, + ...postArgs + ], + { + reject: false, + stdio: 'inherit', + env: { + ...process.env, + NUXI_CLI_WRAPPER: 'true' + } + } + ) + if (child.exitCode === EXIT_CODE_RESTART) { + await startSubprocess(preArgs, postArgs) + } else { + process.exit(child.exitCode) + } +} + +const args = process.argv.slice(2) +// only enable wrapper in dev command +if (args[0] === 'dev') { + await startSubprocess([], args) +} else { + await import(cliEntry) +} diff --git a/packages/nuxi/src/commands/dev.ts b/packages/nuxi/src/commands/dev.ts index 139d69e629..52cb53fa39 100644 --- a/packages/nuxi/src/commands/dev.ts +++ b/packages/nuxi/src/commands/dev.ts @@ -14,6 +14,7 @@ import { loadKit } from '../utils/kit' import { importModule } from '../utils/cjs' import { overrideEnv } from '../utils/env' import { writeNuxtManifest, loadNuxtManifest, cleanupNuxtDirs } from '../utils/nuxt' +import { EXIT_CODE_RESTART } from '../constants' import { defineNuxtCommand } from './index' export default defineNuxtCommand({ @@ -89,6 +90,14 @@ export default defineNuxtCommand({ } currentNuxt = await loadNuxt({ rootDir, dev: true, ready: false }) + // Hard restart + if (process.env.NUXI_CLI_WRAPPER) { + currentNuxt.hooks.hook('restart', (options) => { + if (options?.hard) { + process.exit(EXIT_CODE_RESTART) + } + }) + } currentNuxt.hooks.hookOnce('restart', () => load(true)) if (!isRestart) { diff --git a/packages/nuxi/src/constants.ts b/packages/nuxi/src/constants.ts new file mode 100644 index 0000000000..36ebe5dfd8 --- /dev/null +++ b/packages/nuxi/src/constants.ts @@ -0,0 +1,11 @@ +/** + * Special exit code to restart the process + * + * Usage: + * ```ts + * if (process.env.NUXI_CLI_WRAPPER) { + * process.exit(EXIT_CODE_RESTART) + * } + * ``` + */ +export const EXIT_CODE_RESTART = 85 diff --git a/packages/nuxi/src/index.ts b/packages/nuxi/src/index.ts index b8492c1b01..119ab45c2a 100755 --- a/packages/nuxi/src/index.ts +++ b/packages/nuxi/src/index.ts @@ -1 +1,2 @@ export * from './run' +export * from './constants' diff --git a/packages/schema/src/types/hooks.ts b/packages/schema/src/types/hooks.ts index 566b89042b..ea19a809b7 100644 --- a/packages/schema/src/types/hooks.ts +++ b/packages/schema/src/types/hooks.ts @@ -77,7 +77,12 @@ export interface NuxtHooks { * Called to restart the current Nuxt instance. * @returns Promise */ - 'restart': () => HookResult + 'restart': (options?: { + /** + * Try to restart the whole process if supported + */ + hard?: boolean + }) => HookResult /** * Called during Nuxt initialization, before installing user modules.