import { fork } from 'node:child_process'; import process from 'node:process'; import { defineCommand } from 'citty'; import defu from 'defu'; import { createJiti } from 'jiti'; import { getArgs, parseArgs } from 'listhen/cli'; import { resolve } from 'pathe'; import { satisfies } from 'semver'; import { isTest, isBun } from 'std-env'; import { s as showVersions } from '../shared/cli.CVvsnRpF.mjs'; import { _ as _getDevServerOverrides, a as _getDevServerDefaults, r as renderError } from './dev2.mjs'; import { o as overrideEnv } from '../shared/cli.wjLTNSBo.mjs'; import { l as loadKit } from '../shared/cli.DlcAx0De.mjs'; import { e as envNameArgs, b as legacyRootDirArgs, d as dotEnvArgs, l as logLevelArgs, c as cwdArgs, a as logger } from '../shared/cli.CyjRwZnH.mjs'; import 'consola/utils'; import 'pkg-types'; import 'node:events'; import 'chokidar'; import 'h3'; import 'listhen'; import 'perfect-debounce'; import 'ufo'; import '../shared/cli.BI-F07wL.mjs'; import 'node:fs'; import '../shared/cli.CFGy0wx0.mjs'; import 'ohash'; import 'youch'; import 'node:path'; import 'consola'; import 'node:url'; const forkSupported = !isTest && (!isBun || isBunForkSupported()); const listhenArgs = getArgs(); const command = defineCommand({ meta: { name: "dev", description: "Run Nuxt development server" }, args: { ...cwdArgs, ...logLevelArgs, ...dotEnvArgs, ...legacyRootDirArgs, ...envNameArgs, clear: { type: "boolean", description: "Clear console on restart", negativeDescription: "Disable clear console on restart" }, fork: { type: "boolean", description: forkSupported ? "Disable forked mode" : "Enable forked mode", negativeDescription: "Disable forked mode", default: forkSupported, alias: ["f"] }, ...{ ...listhenArgs, "port": { ...listhenArgs.port, description: "Port to listen on (default: `NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port`)", alias: ["p"] }, "open": { ...listhenArgs.open, alias: ["o"], default: false }, "host": { ...listhenArgs.host, alias: ["h"], description: "Host to listen on (default: `NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host`)" }, "clipboard": { ...listhenArgs.clipboard, default: false }, "https.domains": { ...listhenArgs["https.domains"], description: "Comma separated list of domains and IPs, the autogenerated certificate should be valid for (https: true)" } }, sslCert: { type: "string", description: "(DEPRECATED) Use `--https.cert` instead." }, sslKey: { type: "string", description: "(DEPRECATED) Use `--https.key` instead." } }, async run(ctx) { overrideEnv("development"); const cwd = resolve(ctx.args.cwd || ctx.args.rootDir); await showVersions(cwd); const { loadNuxtConfig } = await loadKit(cwd); const nuxtOptions = await loadNuxtConfig({ cwd, dotenv: { cwd, fileName: ctx.args.dotenv }, envName: ctx.args.envName, // c12 will fall back to NODE_ENV overrides: { dev: true, logLevel: ctx.args.logLevel, ...ctx.data?.overrides } }); const listenOptions = _resolveListenOptions(nuxtOptions, ctx.args); if (ctx.args.fork) { const devProxy = await _createDevProxy(nuxtOptions, listenOptions); await _startSubprocess(devProxy, ctx.rawArgs, listenOptions); return { listener: devProxy?.listener }; } else { const { createNuxtDevServer } = await import('./dev2.mjs').then(function (n) { return n.d; }); const devServerOverrides = _getDevServerOverrides({ public: listenOptions.public }); const devServerDefaults = _getDevServerDefaults({ hostname: listenOptions.hostname, https: listenOptions.https }); const devServer = await createNuxtDevServer( { cwd, overrides: defu(ctx.data?.overrides, devServerOverrides), defaults: devServerDefaults, logLevel: ctx.args.logLevel, clear: ctx.args.clear, dotenv: { cwd, fileName: ctx.args.dotenv }, envName: ctx.args.envName, loadingTemplate: nuxtOptions.devServer.loadingTemplate, devContext: {} }, listenOptions ); await devServer.init(); return { listener: devServer?.listener }; } } }); async function _createDevProxy(nuxtOptions, listenOptions) { const jiti = createJiti(nuxtOptions.rootDir); let loadingMessage = "Nuxt dev server is starting..."; let error; let loadingTemplate = nuxtOptions.devServer.loadingTemplate; for (const url of nuxtOptions.modulesDir) { if (loadingTemplate) { break; } loadingTemplate = await jiti.import("@nuxt/ui-templates", { parentURL: url }).then((r) => r.loading); } const { createProxyServer } = await import('httpxy'); const proxy = createProxyServer({}); let address; const handler = (req, res) => { if (error) { renderError(req, res, error); return; } if (!address) { res.statusCode = 503; res.setHeader("Content-Type", "text/html"); res.end(loadingTemplate({ loading: loadingMessage })); return; } return proxy.web(req, res, { target: address }); }; const wsHandler = (req, socket, head) => { if (!address) { socket.destroy(); return; } return proxy.ws(req, socket, { target: address }, head); }; const { listen } = await import('listhen'); const listener = await listen(handler, listenOptions); listener.server.on("upgrade", wsHandler); return { listener, handler, wsHandler, setAddress: (_addr) => { address = _addr; }, setLoadingMessage: (_msg) => { loadingMessage = _msg; }, setError: (_error) => { error = _error; }, clearError() { error = void 0; } }; } async function _startSubprocess(devProxy, rawArgs, listenArgs) { let childProc; const kill = (signal) => { if (childProc) { childProc.kill(signal); childProc = void 0; } }; const restart = async () => { devProxy.clearError(); if (process.platform === "win32") { kill("SIGTERM"); } else { kill("SIGHUP"); } childProc = fork(globalThis.__nuxt_cli__.entry, ["_dev", ...rawArgs], { execArgv: [ "--enable-source-maps", process.argv.find((a) => a.includes("--inspect")) ].filter(Boolean), env: { ...process.env, __NUXT_DEV__: JSON.stringify({ hostname: listenArgs.hostname, public: listenArgs.public, publicURLs: await devProxy.listener.getURLs().then((r) => r.map((r2) => r2.url)), proxy: { url: devProxy.listener.url, urls: await devProxy.listener.getURLs(), https: devProxy.listener.https } }) } }); childProc.on("close", (errorCode) => { if (errorCode) { process.exit(errorCode); } }); childProc.on("message", (message) => { if (message.type === "nuxt:internal:dev:ready") { devProxy.setAddress(`http://127.0.0.1:${message.port}`); } else if (message.type === "nuxt:internal:dev:loading") { devProxy.setAddress(void 0); devProxy.setLoadingMessage(message.message); devProxy.clearError(); } else if (message.type === "nuxt:internal:dev:loading:error") { devProxy.setAddress(void 0); devProxy.setError(message.error); } else if (message.type === "nuxt:internal:dev:restart") { restart(); } else if (message.type === "nuxt:internal:dev:rejection") { logger.info(`Restarting Nuxt due to error: \`${message.message}\``); restart(); } }); }; for (const signal of [ "exit", "SIGTERM", "SIGINT", "SIGQUIT" ]) { process.once(signal, () => { kill(signal === "exit" ? 0 : signal); }); } await restart(); return { restart, kill }; } function _resolveListenOptions(nuxtOptions, args) { const _port = args.port ?? args.p ?? process.env.NUXT_PORT ?? process.env.NITRO_PORT ?? process.env.PORT ?? nuxtOptions.devServer.port; const _hostname = typeof args.host === "string" ? args.host : (args.host === true ? "" : void 0) ?? process.env.NUXT_HOST ?? process.env.NITRO_HOST ?? process.env.HOST ?? (nuxtOptions.devServer?.host || void 0) ?? void 0; const _public = args.public ?? (_hostname && !["localhost", "127.0.0.1", "::1"].includes(_hostname)) ? true : void 0; const _httpsCert = args["https.cert"] || args.sslCert || process.env.NUXT_SSL_CERT || process.env.NITRO_SSL_CERT || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "cert" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.cert || ""; const _httpsKey = args["https.key"] || args.sslKey || process.env.NUXT_SSL_KEY || process.env.NITRO_SSL_KEY || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "key" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.key || ""; const _httpsPfx = args["https.pfx"] || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "pfx" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.pfx || ""; const _httpsPassphrase = args["https.passphrase"] || typeof nuxtOptions.devServer.https !== "boolean" && nuxtOptions.devServer.https && "passphrase" in nuxtOptions.devServer.https && nuxtOptions.devServer.https.passphrase || ""; const httpsEnabled = !!(args.https ?? nuxtOptions.devServer.https); const _listhenOptions = parseArgs({ ...args, "open": args.o || args.open, "https": httpsEnabled, "https.cert": _httpsCert, "https.key": _httpsKey, "https.pfx": _httpsPfx, "https.passphrase": _httpsPassphrase }); const httpsOptions = httpsEnabled && { ...nuxtOptions.devServer.https, ..._listhenOptions.https }; return { ..._listhenOptions, port: _port, hostname: _hostname, public: _public, https: httpsOptions, baseURL: nuxtOptions.app.baseURL.startsWith("./") ? nuxtOptions.app.baseURL.slice(1) : nuxtOptions.app.baseURL }; } function isBunForkSupported() { const bunVersion = globalThis.Bun.version; return satisfies(bunVersion, ">=1.2"); } export { command as default };