import { createRequire } from "node:module"; import { defu } from "defu"; import { AsyncLocalStorage } from "node:async_hooks"; import { getContext } from "unctx"; import { createConsoleReporter, defineDiagnostics } from "nostics"; import process from "node:process"; import { ansiFormatter } from "nostics/formatters/ansi"; import { colors } from "consola/utils"; import { existsSync, lstatSync, promises, readFileSync, realpathSync, statSync } from "node:fs"; import { isGreaterThan, satisfies } from "verkit"; import { readFile } from "node:fs/promises"; import { fileURLToPath, pathToFileURL } from "node:url"; import { basename, dirname, isAbsolute, join, normalize, relative, resolve } from "pathe"; import { resolveModulePath, resolveModuleURL } from "exsolve"; import { captureStackTrace } from "errx"; import { glob } from "tinyglobby"; import { resolveAlias } from "pathe/utils"; import ignore from "ignore"; import { performance } from "node:perf_hooks"; import { read, update } from "rc9"; import { consola } from "consola"; import { x } from "tinyexec"; import { detect, resolveCommand } from "package-manager-detector"; import { hasTTY, isCI, provider } from "std-env"; //#region \0rolldown/runtime.js var __defProp = Object.defineProperty; var __exportAll = (all, no_symbols) => { let target = {}; for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" }); return target; }; //#endregion //#region src/constants.ts /** * Default extensions for files that may contain JSX. * @internal */ const DEFAULT_JSX_FILE_EXTENSIONS = [".tsx", ".jsx"]; /** * Default extensions for JavaScript/TypeScript files, in order of resolution priority. * @internal */ const DEFAULT_JS_FILE_EXTENSIONS = [ ".mjs", ".js", ".cjs", ".mts", ".ts", ".cts", ...DEFAULT_JSX_FILE_EXTENSIONS ]; //#endregion //#region src/diagnostics/_shared.ts /** * Resolve the docs URL for a stable `NUXT_B` code. * * Codes with a dedicated docs page pass this as their `see:` URL; codes whose * inline why+fix is self-sufficient opt out with `docs: false`. */ const docsBase = (code) => `https://nuxt.com/docs/4.x/errors/${code.replace("NUXT_", "").toLowerCase()}`; const reporters = [/* @__PURE__ */ createConsoleReporter(process.env.NODE_ENV === "test" ? void 0 : { formatter: ansiFormatter(colors) })]; //#endregion //#region src/diagnostics/kit-api.ts /** * B8xxx * Kit API diagnostics. */ const kitDiagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase, reporters, codes: { NUXT_B8001: { why: "The active Nuxt instance is unavailable in the current context.", fix: "Call this within a Nuxt module `setup()` function, or inside a `nuxt.hook()` callback.", docs: false }, NUXT_B8002: { why: "The `base` argument to `createResolver(base)` is missing.", fix: "Pass `import.meta.url` or a directory path as the `base` argument to `createResolver()`.", docs: false }, NUXT_B8003: { why: "Nitro is not initialized yet: `useNitro()` was called before the `ready` hook ran.", fix: "Move the `useNitro()` call inside a hook that runs after initialization, such as `nuxt.hook('ready', () => { ... })`.", docs: false }, NUXT_B8004: { why: (p) => `Nuxt compatibility issues were found:\n${p.issues}`, fix: "Update the module to support the current Nuxt version, or check if a newer version of the module is available.", docs: false }, NUXT_B8005: { why: "The Nuxt version cannot be determined: no current instance was passed.", fix: "Pass a valid Nuxt instance to `getNuxtVersion()`, or ensure `useNuxt()` is available in the current context.", docs: false }, NUXT_B8006: { why: (p) => `No Nuxt version could be found from \`${p.cwd}\`.`, fix: (p) => `Run \`${p.installCommand}\` in your project directory to install Nuxt.`, docs: false }, NUXT_B8007: { why: (p) => `The type template filename \`${p.template}\` is invalid.`, fix: "Rename the template filename to end with `.d.ts`.", docs: false }, NUXT_B8008: { why: (p) => `The template value is invalid: ${p.template}.`, fix: "Pass a valid template object or a string path to `addTemplate()`.", docs: false }, NUXT_B8009: { why: (p) => `The template was not found at \`${p.template}\`.`, fix: "Check that the `src` path exists and is an absolute path or resolvable from the module directory.", docs: false }, NUXT_B8010: { why: (p) => `The template \`${p.template}\` provides neither \`getContents\` nor \`src\`.`, fix: "Add a `getContents` function or a `src` path to the template object.", docs: false }, NUXT_B8011: { why: (p) => `The template is missing a \`filename\`: ${p.template}.`, fix: "Add a `filename` property to the template object, or provide a `src` path so the filename can be derived from it.", docs: false }, NUXT_B8012: { why: (p) => `\`${p.name}\` was used outside of a Nuxt context.`, fix: "Register this module in the `modules` array of `nuxt.config` rather than calling it directly.", docs: false }, NUXT_B8013: { why: (p) => p.message, fix: "Update the module to a version that supports the current Nuxt version, or set `experimental.enforceModuleCompatibility` to `true` to make this a fatal error.", docs: false }, NUXT_B8014: { why: (p) => `Module \`${p.name}\` was slow to set up, taking \`${p.time}ms\`.`, fix: "Defer expensive operations to a later hook (e.g. `build:before`) to reduce startup time.", docs: false }, NUXT_B8015: { why: (p) => `A Nuxt module must be a function or a string to import. Received: \`${p.received}\`.`, fix: "Pass a module function or a string package name to the `modules` array in `nuxt.config`.", docs: false }, NUXT_B8016: { why: (p) => `The Nuxt module \`${p.module}\` is not a function.`, fix: "Ensure the module has a default export that is a function, using `defineNuxtModule()` to create a valid module.", docs: false }, NUXT_B8017: { why: (p) => `The module \`${p.module}\` could not be loaded. It may not be installed.`, fix: (p) => p.installCommand ? `Run \`${p.installCommand}\` to install it.` : "Check that the module path exists and points to a valid Nuxt module.", docs: false }, NUXT_B8018: { why: (p) => `An error occurred while importing the module \`${p.module}\`: ${p.error}.`, fix: "A sub-dependency of this module is missing. Install it, or check that the module is compatible with the current environment.", docs: false }, NUXT_B8019: { why: (p) => `An error occurred while executing the ${p.phase} hook for module \`${p.name}\`: ${p.error}.`, fix: "Check the module's install/upgrade hook implementation, or report this issue to the module author.", docs: false }, NUXT_B8020: { why: (p) => `The module \`${p.module}\` could not be loaded: ${p.error}`, fix: (p) => `${p.hint} Alternatively, run \`${p.installCommand}\` and Nuxt will load it through jiti instead.`, docs: false }, NUXT_B8021: { why: "The deprecated `requireModule` helper needs `jiti`, which is an optional peer dependency and is not installed.", fix: "Use `importModule` instead, which loads the file with the runtime's own loader. If the calling code cannot be made async, add `jiti` to your project.", docs: false }, NUXT_B8022: { why: (p) => `Scanning a module for its export names needs a parser (\`${p.specifiers}\`), and neither could be loaded.`, fix: "Add `oxc-parser` to your project; every supported version of Nuxt already ships a package that can be used here.", docs: false }, NUXT_B8023: { why: (p) => `The module \`${p.module}\` was loaded through jiti because the runtime could not load it: ${p.error}`, fix: "Loading it natively is faster, as jiti has to transform the module first. Report it to the module author if the module is not your own.", docs: false }, NUXT_B8024: { why: (p) => `A \`${p.api}\` registration was skipped because this project's server runs \`${p.host}\`.${p.declared ? ` It provided implementations for \`${p.declared}\`.` : ""}`, fix: "Provide an implementation the server can run: `nuxt/server` code runs everywhere. Report it to the module author if the module is not your own.", docs: false }, NUXT_B8025: { why: (p) => `\`${p.api}\` was passed a \`${p.value}\` variant, which is not a server API it accepts.`, fix: (p) => `Key the variants by the server API the code is written against (\`${p.accepted}\`), or pass a single path: the registered file's imports say which API it uses.`, docs: false } } }); //#endregion //#region src/context.ts /** * Direct access to the Nuxt global context. * @deprecated Use `getNuxtCtx` instead */ const nuxtCtx = getContext("nuxt"); /** async local storage for the name of the current nuxt instance */ const asyncNuxtStorage = getContext("asyncNuxtStorage", { asyncContext: true, AsyncLocalStorage }); /** Direct access to the Nuxt context with asyncLocalStorage - see https://github.com/unjs/unctx. */ const getNuxtCtx = () => asyncNuxtStorage.tryUse(); /** * Get access to Nuxt instance. * * Throws an error if Nuxt instance is unavailable. * @example * ```js * const nuxt = useNuxt() * ``` */ function useNuxt() { const instance = asyncNuxtStorage.tryUse() || nuxtCtx.tryUse(); if (!instance) throw kitDiagnostics.NUXT_B8001(); return instance; } /** * Get access to Nuxt instance. * * Returns null if Nuxt instance is unavailable. * @example * ```js * const nuxt = tryUseNuxt() * if (nuxt) { * // Do something * } * ``` */ function tryUseNuxt() { return asyncNuxtStorage.tryUse() || nuxtCtx.tryUse(); } function runWithNuxtContext(nuxt, fn) { return asyncNuxtStorage.call(nuxt, fn); } //#endregion //#region src/internal/package-json.ts var package_json_exports = /* @__PURE__ */ __exportAll({ findWorkspaceDir: () => findWorkspaceDir, readPackageJSON: () => readPackageJSON, resolvePackageDir: () => resolvePackageDir, resolvePackageJSON: () => resolvePackageJSON }); const WORKSPACE_FILES = [ "pnpm-workspace.yaml", "lerna.json", "turbo.json", "rush.json", "deno.json", "deno.jsonc" ]; const LOCK_FILES = [ "yarn.lock", "package-lock.json", "pnpm-lock.yaml", "npm-shrinkwrap.json", "bun.lockb", "bun.lock", "deno.lock" ]; function isFile(path) { try { return statSync(path).isFile(); } catch { return false; } } function resolveStartPath(id, options) { if (id instanceof URL || id.startsWith("file://")) return normalize(fileURLToPath(id)); if (isAbsolute(id)) return normalize(id); return resolveModulePath(id, { ...options, from: options.from || options.parent }); } /** Walk up from `start` looking for one of `filenames`, stopping at the nearest `node_modules`. */ function findUp(start, filenames, furthest) { const segments = resolve(start).split("/").filter(Boolean); if (start[0] === "/") segments[0] = "/" + segments[0]; const root = Math.max(segments.findIndex((s) => s === "node_modules"), 0); const length = segments.length - root; for (let i = 0; i < length; i++) { const index = furthest ? root + 1 + i : segments.length - i; for (const filename of filenames) { const candidate = join(...segments.slice(0, index), filename); if (isFile(candidate)) return candidate; } } } /** Find the `package.json` nearest to `id`, which may be a path, a URL or a module id. */ function resolvePackageJSON(id = process.cwd(), options = {}) { const start = resolveStartPath(id, options); const path = start ? findUp(start, ["package.json"]) : void 0; if (!path && !options.try) throw new Error(`Cannot find matching package.json in ${id} or parent directories.`); return path; } /** Find the directory containing the `package.json` nearest to `id`. */ function resolvePackageDir(id, options = {}) { const path = resolvePackageJSON(id, options); return path ? dirname(path) : void 0; } /** Read the `package.json` nearest to `id`, which may be a path, a URL or a module id. */ async function readPackageJSON(id = process.cwd(), options = {}) { const path = resolvePackageJSON(id, options); return JSON.parse(await readFile(path, "utf8")); } /** * Detect the workspace root for `id`, preferring workspace manifests, then git, then lockfiles. * * Returns a promise because the inlined `c12` awaits this and attaches a `.catch()` to it. * * @knipignore reached only through the `pkg-types` alias in `tsdown.config.ts` */ function findWorkspaceDir(id = process.cwd(), options = {}) { return Promise.resolve().then(() => resolveWorkspaceDir(id, options)); } function resolveWorkspaceDir(id, options) { const start = resolveStartPath(id, options); if (!start) throw new Error(`Cannot detect workspace root from ${id}.`); const workspaceFile = findUp(start, WORKSPACE_FILES, true); if (workspaceFile) return dirname(workspaceFile); const gitConfig = findUp(start, [".git/config"]); if (gitConfig) return resolve(gitConfig, "../.."); const lockFile = findUp(start, LOCK_FILES, true); if (lockFile) return dirname(lockFile); const packageJSON = findUp(start, ["package.json"], true); if (packageJSON) return dirname(packageJSON); throw new Error(`Cannot detect workspace root from ${id}.`); } //#endregion //#region src/internal/interop.ts /** * Return the `default` export of a module namespace, with the module's other named exports * grafted onto it, so consumers can use a CJS-transpiled module as if it were ESM. */ function interopDefault(sourceModule, opts = {}) { if (sourceModule === null || typeof sourceModule !== "object" || !("default" in sourceModule)) return sourceModule; const defaultValue = sourceModule.default; if (defaultValue === void 0 || defaultValue === null) return sourceModule; const defaultType = typeof defaultValue; if (defaultType !== "object" && !(defaultType === "function" && !opts.preferNamespace)) return opts.preferNamespace ? sourceModule : defaultValue; for (const key in sourceModule) try { if (!(key in defaultValue)) Object.defineProperty(defaultValue, key, { enumerable: key !== "default", configurable: key !== "default", get() { return sourceModule[key]; } }); } catch {} return defaultValue; } //#endregion //#region src/internal/trace.ts const distURL = import.meta.url.replace(/\/dist\/.*$/, "/"); function getUserCaller() { if (!import.meta.dev) return null; const { source, line, column } = captureStackTrace().find((entry) => !entry.source.startsWith(distURL)) ?? {}; if (!source) return null; return { source: source.replace(/^file:\/\//, ""), line, column }; } const warnings = /* @__PURE__ */ new Set(); function warn(warning) { if (!warnings.has(warning)) { console.warn(warning); warnings.add(warning); } } //#endregion //#region src/internal/node-module.ts const NODE_MODULES_SEGMENT = "/node_modules/"; function toPath(path) { return normalize(typeof path === "string" && !path.startsWith("file://") ? path.replace(/\\/g, "/") : fileURLToPath(path).replace(/\\/g, "/")); } /** * Split a path within `node_modules` into the containing `node_modules` directory, * the package name and the subpath within the package. */ function parseNodeModulePath(path) { if (!path) return {}; const resolvedPath = toPath(path); const index = resolvedPath.lastIndexOf(NODE_MODULES_SEGMENT); if (index === -1) return {}; const dir = resolvedPath.slice(0, index + 14); const segments = resolvedPath.slice(dir.length).split("/"); const name = segments.splice(0, segments[0]?.startsWith("@") ? 2 : 1).join("/"); if (!name) return {}; const subpath = segments.join("/"); return { dir, name, subpath: subpath ? `./${subpath}` : void 0 }; } /** * Resolve the public subpath (as exposed through the package `exports` field, if any) * that corresponds to a resolved file within `node_modules`. */ async function lookupNodeModuleSubpath(path) { const resolvedPath = toPath(path); const { name, subpath } = parseNodeModulePath(resolvedPath); if (!name || !subpath) return subpath; const { exports } = await readPackageJSON(resolvedPath).catch(() => void 0) || {}; return exports && findSubpath(subpath, exports) || subpath; } function findSubpath(subpath, exports) { if (typeof exports === "string") exports = { ".": exports }; if (!subpath.startsWith(".")) subpath = subpath.startsWith("/") ? `.${subpath}` : `./${subpath}`; if (subpath in exports) return subpath; return flattenExports(exports).find((p) => p.fsPath === subpath)?.subpath; } function flattenExports(exports, parentSubpath = "./") { if (typeof exports === "string") return [{ subpath: parentSubpath, fsPath: exports }]; if (Array.isArray(exports)) return exports.flatMap((value) => flattenExports(value, parentSubpath)); return Object.entries(exports).flatMap(([key, value]) => { const segment = key.startsWith(".") ? key.slice(1).replace(/^\//, "") : ""; const childSubpath = segment ? `${parentSubpath.replace(/\/$/, "")}/${segment}` : parentSubpath; if (typeof value === "string") return [{ subpath: childSubpath, fsPath: value }]; return flattenExports(value, childSubpath); }); } //#endregion //#region src/layers.ts const layerMap = /* @__PURE__ */ new WeakMap(); /** * Get the resolved directory paths for all layers in a Nuxt application. * * Returns an array of LayerDirectories objects, ordered by layer priority: * - The first layer is the user/project layer (highest priority) * - Earlier layers override later layers in the array * - Base layers appear last in the array (lowest priority) * * @param nuxt - The Nuxt instance to get layers from. Defaults to the current Nuxt context. * @returns Array of LayerDirectories objects, ordered by priority (user layer first) */ function getLayerDirectories(nuxt = useNuxt()) { return nuxt.options._layers.map((layer) => { if (layerMap.has(layer)) return layerMap.get(layer); const config = withTrailingSlash(layer.config.rootDir) === withTrailingSlash(nuxt.options.rootDir) ? nuxt.options : layer.config; const src = withTrailingSlash(config.srcDir || layer.cwd); const root = withTrailingSlash(config.rootDir || layer.cwd); const directories = { root, shared: withTrailingSlash(resolve(root, resolveAlias$1(config.dir?.shared || "shared", nuxt.options.alias))), server: withTrailingSlash(resolve(src, resolveAlias$1(config.serverDir || "server", nuxt.options.alias))), modules: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.modules || "modules", nuxt.options.alias))), public: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.public || "public", nuxt.options.alias))), app: src, appLayouts: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.layouts || "layouts", nuxt.options.alias))), appMiddleware: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.middleware || "middleware", nuxt.options.alias))), appPages: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.pages || "pages", nuxt.options.alias))), appPlugins: withTrailingSlash(resolve(src, resolveAlias$1(config.dir?.plugins || "plugins", nuxt.options.alias))) }; layerMap.set(layer, directories); return directories; }); } function withTrailingSlash(dir) { return dir.replace(/[^/]$/, "$&/"); } //#endregion //#region src/ignore.ts function createIsIgnored(nuxt = tryUseNuxt()) { return (pathname, stats) => isIgnored(pathname, stats, nuxt); } const layerRootsCache = /* @__PURE__ */ new WeakMap(); /** * Return a filter function to filter an array of paths */ function isIgnored(pathname, _stats, nuxt = tryUseNuxt()) { if (!nuxt) return false; if (!nuxt._ignore) { nuxt._ignore = ignore(nuxt.options.ignoreOptions); nuxt._ignore.add(resolveIgnorePatterns()); } let cwds = layerRootsCache.get(nuxt); if (!cwds) { cwds = getLayerDirectories(nuxt).map((dirs) => dirs.root).sort((a, b) => b.length - a.length); layerRootsCache.set(nuxt, cwds); } for (const cwd of cwds) if (pathname.startsWith(cwd)) { const relativePath = pathname.slice(cwd.length); return !!(relativePath && nuxt._ignore.ignores(relativePath)); } const relativePath = relative(nuxt.options.rootDir, pathname); if (relativePath[0] === "." && relativePath[1] === ".") return false; return !!(relativePath && nuxt._ignore.ignores(relativePath)); } const NEGATION_RE = /^(!?)(.*)$/; function resolveIgnorePatterns(relativePath) { const nuxt = tryUseNuxt(); if (!nuxt) return []; const ignorePatterns = nuxt.options.ignore.flatMap((s) => resolveGroupSyntax(s)); const nuxtignoreFile = join(nuxt.options.rootDir, ".nuxtignore"); if (existsSync(nuxtignoreFile)) { const contents = readFileSync(nuxtignoreFile, "utf-8"); ignorePatterns.push(...contents.trim().split(/\r?\n/)); } if (relativePath) return ignorePatterns.map((p) => { const [_, negation = "", pattern] = p.match(NEGATION_RE) || []; if (pattern && pattern[0] === "*") return p; return negation + relative(relativePath, resolve(nuxt.options.rootDir, pattern || p)); }); return ignorePatterns; } /** * This function turns string containing groups '**\/*.{spec,test}.{js,ts}' into an array of strings. * For example will '**\/*.{spec,test}.{js,ts}' be resolved to: * ['**\/*.spec.js', '**\/*.spec.ts', '**\/*.test.js', '**\/*.test.ts'] * @param group string containing the group syntax * @returns {string[]} array of strings without the group syntax */ function resolveGroupSyntax(group) { let groups = [group]; while (groups.some((group) => group.includes("{"))) groups = groups.flatMap((group) => { const [head, ...tail] = group.split("{"); if (tail.length) { const [body = "", ...rest] = tail.join("{").split("}"); return body.split(",").map((part) => `${head}${part}${rest.join("")}`); } return group; }); return groups; } //#endregion //#region src/utils.ts /** @since 3.9.0 */ function toArray(value) { return Array.isArray(value) ? value : [value]; } /** * Filter out items from an array in place. This function mutates the array. * `predicate` get through the array from the end to the start for performance. * * This function should be faster than `Array.prototype.filter` on large arrays. */ function filterInPlace(array, predicate) { for (let i = array.length; i--;) if (!predicate(array[i], i, array)) array.splice(i, 1); return array; } const MODE_RE = /\.(server|client)(\.\w+)*$/; const distDirURL = new URL(".", import.meta.url); //#endregion //#region src/resolve.ts /** * Resolve the full path to a file or a directory (based on the provided type), respecting Nuxt alias and extensions options. * * If a path cannot be resolved, normalized input will be returned unless the `fallbackToOriginal` option is set to `true`, * in which case the original input path will be returned. */ async function resolvePath(path, opts = {}) { const { type = "file" } = opts; const res = await _resolvePathGranularly(path, { ...opts, type }); if (res.type === type) return res.path; return opts.fallbackToOriginal ? path : res.path; } /** * Try to resolve first existing file in paths */ async function findPath(paths, opts, pathType = "file") { for (const path of toArray(paths)) { const type = opts?.type || pathType; const res = await _resolvePathGranularly(path, { ...opts, type }); if (!res.type || res.type !== type) continue; if (res.virtual || await existsSensitive(res.path)) return res.path; } return null; } /** * Resolve path aliases respecting Nuxt alias options */ function resolveAlias$1(path, alias) { alias ||= tryUseNuxt()?.options.alias || {}; return resolveAlias(path, alias); } /** * Create a relative resolver */ function createResolver(base) { if (!base) throw kitDiagnostics.NUXT_B8002(); base = base.toString(); if (base.startsWith("file://")) base = dirname(fileURLToPath(base)); return { resolve: (...path) => resolve(base, ...path), resolvePath: (path, opts) => resolvePath(path, { cwd: base, ...opts }) }; } async function resolveNuxtModule(base, paths) { const resolved = []; const resolver = createResolver(base); for (const path of paths) { if (path.startsWith(base)) { resolved.push(path.split("/index.ts")[0]); continue; } const resolvedPath = await resolver.resolvePath(path); const dir = parseNodeModulePath(resolvedPath).dir; if (dir) { resolved.push(dir); continue; } const index = resolvedPath.lastIndexOf(path); resolved.push(index === -1 ? dirname(resolvedPath) : resolvedPath.slice(0, index + path.length)); } return resolved; } async function _resolvePathType(path, opts = {}, skipFs = false) { if (opts?.virtual && existsInVFS(path)) return { path, type: "file", virtual: true }; if (skipFs) return; const stats = await promises.stat(path).catch(() => null); if (stats) return { path, type: stats.isFile() ? "file" : "dir", virtual: false }; } function normalizeExtension(ext) { return ext.startsWith(".") ? ext : `.${ext}`; } async function _resolvePathGranularly(path, opts = { type: "file" }) { const _path = path; path = normalize(path); if (isAbsolute(path)) { const res = await _resolvePathType(path, opts); if (res && res.type === opts.type) return res; } const nuxt = tryUseNuxt(); const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd()); const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : [...DEFAULT_JS_FILE_EXTENSIONS, ".json"]); const modulesDir = nuxt ? nuxt.options.modulesDir : []; path = resolveAlias(path, opts.alias ?? nuxt?.options.alias ?? {}); if (!isAbsolute(path)) path = resolve(cwd, path); const res = await _resolvePathType(path, opts); if (res && res.type === opts.type) return res; if (opts.type === "file") { for (const ext of extensions) { const normalizedExt = normalizeExtension(ext); const extPath = await _resolvePathType(path + normalizedExt, opts); if (extPath && extPath.type === "file") return extPath; const indexPath = await _resolvePathType(join(path, "index" + normalizedExt), opts, res?.type !== "dir"); if (indexPath && indexPath.type === "file") return indexPath; } const resolvedModulePath = resolveModulePath(_path, { try: true, suffixes: ["", "index"], from: [cwd, ...modulesDir].map((d) => directoryToURL(d)) }); if (resolvedModulePath) return { path: resolvedModulePath, type: "file", virtual: false }; } return { path }; } async function existsSensitive(path) { return new Set(await promises.readdir(dirname(path)).catch(() => [])).has(basename(path)); } function existsInVFS(path, nuxt = tryUseNuxt()) { if (!nuxt) return false; if (path in nuxt.vfs) return true; return (nuxt.apps.default?.templates ?? nuxt.options.build.templates).some((template) => template.dst === path); } /** * Resolve absolute file paths in the provided directory with respect to `.nuxtignore` and return them sorted. * @param path path to the directory to resolve files in * @param pattern glob pattern or an array of glob patterns to match files * @param opts options for globbing * @param opts.followSymbolicLinks whether to follow symbolic links, default is `true` * @param opts.ignore additional glob patterns to ignore * @returns sorted array of absolute file paths */ async function resolveFiles(path, pattern, opts = {}) { const files = []; for (const p of await glob(pattern, { cwd: path, followSymbolicLinks: opts.followSymbolicLinks ?? true, absolute: true, ignore: opts.ignore })) if (!isIgnored(p)) files.push(p); return files.sort(); } //#endregion //#region src/internal/esm.ts function directoryToURL(dir) { return pathToFileURL(dir + "/"); } function tryResolveModule(id, url = import.meta.url) { return Promise.resolve(resolveModulePath(id, { from: url, suffixes: ["", "index"], try: true })); } function resolveModule(id, options) { return resolveModulePath(id, { from: options?.url ?? options?.paths ?? [import.meta.url], extensions: options?.extensions ?? DEFAULT_JS_FILE_EXTENSIONS }); } async function importModule(id, opts) { const resolvedPath = resolveModule(id, opts); return await import(pathToFileURL(resolvedPath).href).then((r) => opts?.interopDefault !== false ? interopDefault(r) : r); } function tryImportModule(id, opts) { try { return importModule(id, opts).catch(() => void 0); } catch {} } /** * @deprecated Please use `importModule` instead. */ function requireModule(id, opts) { const caller = getUserCaller(); warn(`[@nuxt/kit] \`requireModule\` is deprecated${caller ? ` (used at \`${resolveAlias$1(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Please use \`importModule\` instead.`); const resolvedPath = resolveModule(id, opts); const { createJiti } = requireJiti(); return createJiti(import.meta.url, { interopDefault: opts?.interopDefault !== false })(pathToFileURL(resolvedPath).href); } /** * Load `jiti` synchronously, looking in the same places as {@link loadJiti} minus the install * prompt, which cannot be awaited from here. * * `jiti` is an optional peer dependency, and this entry point is synchronous, so it has to be * loaded through `require` rather than a dynamic import. */ function requireJiti() { const require = createRequire(import.meta.url); try { return require("jiti"); } catch (error) { const rootDir = tryUseNuxt()?.options.rootDir; const path = rootDir && resolveModulePath("jiti", { from: directoryToURL(rootDir), try: true }); if (!path) throw kitDiagnostics.NUXT_B8021({ cause: error }); return require(path); } } /** * @deprecated Please use `tryImportModule` instead. */ function tryRequireModule(id, opts) { try { return requireModule(id, opts); } catch {} } //#endregion //#region src/compatibility.ts const SEMANTIC_VERSION_RE = /-\d+[.-][0-9a-f]+/; function normalizeSemanticVersion(version) { return version.replace(SEMANTIC_VERSION_RE, ""); } const builderMap = { "@nuxt/rspack-builder": "rspack", "@nuxt/vite-builder": "vite", "@nuxt/webpack-builder": "webpack" }; function checkNuxtVersion(version, nuxt = useNuxt()) { const nuxtVersion = getNuxtVersion(nuxt); return satisfies(normalizeSemanticVersion(nuxtVersion), version, { includePrerelease: true }); } /** * Check version constraints and return incompatibility issues as an array */ async function checkNuxtCompatibility(constraints, nuxt = useNuxt()) { const issues = []; if (constraints.nuxt) { const nuxtVersion = getNuxtVersion(nuxt); if (!checkNuxtVersion(constraints.nuxt, nuxt)) issues.push({ name: "nuxt", message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\`` }); } if (constraints.builder && typeof nuxt.options.builder === "string") { const currentBuilder = builderMap[nuxt.options.builder] || nuxt.options.builder; if (currentBuilder in constraints.builder) { const constraint = constraints.builder[currentBuilder]; if (constraint === false) issues.push({ name: "builder", message: `Not compatible with \`${nuxt.options.builder}\`.` }); else for (const parent of [ nuxt.options.rootDir, nuxt.options.workspaceDir, import.meta.url ]) { const builderVersion = await readPackageJSON(nuxt.options.builder, { parent }).then((r) => r.version).catch(() => void 0); if (builderVersion) { if (!satisfies(normalizeSemanticVersion(builderVersion), constraint, { includePrerelease: true })) issues.push({ name: "builder", message: `Not compatible with \`${builderVersion}\` of \`${currentBuilder}\`. This module requires \`${constraint}\`.` }); break; } } } } if (constraints.nitro) { const nitroVersion = getNitroFullVersion(nuxt); if (nitroVersion && !satisfies(normalizeSemanticVersion(nitroVersion), constraints.nitro, { includePrerelease: true })) issues.push({ name: "nitro", message: `Nitro version \`${constraints.nitro}\` is required but currently using \`${nitroVersion}\`` }); } await nuxt.callHook("kit:compatibility", constraints, issues); issues.toString = () => issues.map((issue) => ` - [${issue.name}] ${issue.message}`).join("\n"); return issues; } /** * Check version constraints and throw a detailed error if has any, otherwise returns true */ async function assertNuxtCompatibility(constraints, nuxt = useNuxt()) { const issues = await checkNuxtCompatibility(constraints, nuxt); if (issues.length) throw kitDiagnostics.NUXT_B8004({ issues: issues.toString() }); return true; } /** * Check version constraints and return true if passed, otherwise returns false */ async function hasNuxtCompatibility(constraints, nuxt = useNuxt()) { return !(await checkNuxtCompatibility(constraints, nuxt)).length; } /** * Check if current Nuxt instance is of specified major version */ function isNuxtMajorVersion(majorVersion, nuxt = useNuxt()) { const version = getNuxtVersion(nuxt); return version[0] === majorVersion.toString() && version[1] === "."; } /** * @deprecated Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version. */ function isNuxt2(nuxt = useNuxt()) { return isNuxtMajorVersion(2, nuxt); } /** * @deprecated Use `isNuxtMajorVersion(3, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version. */ function isNuxt3(nuxt = useNuxt()) { return isNuxtMajorVersion(3, nuxt); } const nitroVersionCache = /* @__PURE__ */ new WeakMap(); function getNitroFullVersion(nuxt) { const meta = nuxt._nitro?.meta; if (typeof meta?.version === "string") return meta.version; if (nitroVersionCache.has(nuxt)) return nitroVersionCache.get(nuxt); let version; try { const from = [ ...(nuxt.options?.modulesDir || []).filter(Boolean).map((dir) => directoryToURL(dir)), ...nuxt.options?.rootDir ? [directoryToURL(nuxt.options.rootDir)] : [], import.meta.url ]; let nuxtMajor; try { nuxtMajor = Number.parseInt(getNuxtVersion(nuxt), 10); } catch {} const packages = nuxtMajor !== void 0 && nuxtMajor < 5 ? ["nitropack", "nitro"] : ["nitro", "nitropack"]; for (const pkg of packages) { const path = resolvePackageJSON(pkg, { from, try: true }); if (path) try { const parsed = JSON.parse(readFileSync(path, "utf8")); if (parsed.name === pkg && parsed.version) { version = parsed.version; break; } } catch {} } } catch {} nitroVersionCache.set(nuxt, version); return version; } /** * Get the major version of nitro used by the current Nuxt instance. * * Resolution order: * * 1. `nuxt.options._nitroMajor`, stamped by the host before any module runs. * 2. `nuxt._nitro.meta.majorVersion` from the initialized nitro instance. * 3. Resolving the `nitro` / `nitropack` package from the project, which is correct on * older hosts where the package is a direct dependency. * * Returns `undefined` when no nitro version can be determined; it never throws. */ function getNitroVersion(nuxt = useNuxt()) { const declaredMajor = nuxt?.options?._nitroMajor; if (declaredMajor === 2 || declaredMajor === 3) return declaredMajor; const majorVersion = nuxt?._nitro?.meta?.majorVersion; if (typeof majorVersion === "number") return majorVersion; const version = getNitroFullVersion(nuxt); if (version) { const major = Number.parseInt(version, 10); if (!Number.isNaN(major)) return major; } } const NUXT_VERSION_RE = /^v/g; /** * Get nuxt version */ function getNuxtVersion(nuxt = useNuxt()) { const rawVersion = nuxt?._version || nuxt?.version || nuxt?.constructor?.version; if (typeof rawVersion !== "string") throw kitDiagnostics.NUXT_B8005(); return rawVersion.replace(NUXT_VERSION_RE, ""); } //#endregion //#region src/logger.ts const logger = consola; function useLogger(tag, options = {}) { return tag ? logger.create(options).withTag(tag) : logger; } //#endregion //#region src/internal/terminal-host.ts const TERMINAL_HOST_KEY = Symbol.for("nuxt:terminal-host"); /** * Look up the terminal host published by the running CLI, if any. * * The contract is passed on `globalThis` rather than through an import because a single * process routinely contains several copies of `@nuxt/kit` and `@nuxt/cli`. */ function useTerminalHost() { const host = globalThis[TERMINAL_HOST_KEY]; if (!host || host.version !== 1 || typeof host.withTerminal !== "function" || typeof host.startTask !== "function") return; return host; } //#endregion //#region src/terminal.ts /** * Access the terminal, cooperating with the host UI (such as the `nuxt dev` TUI) when one is * running, and falling back to logging when it is not. * * Use this instead of writing to `process.stdout` or prompting directly, so that prompts are * answerable, tasks are rendered in one place, and nothing is lost to a captured stream. */ function useTerminal() { const host = useTerminalHost(); return { interactive: !!host, withTerminal: (work) => host ? host.withTerminal(work) : work(), prompt: (message, options) => host ? host.withTerminal(() => logger.prompt(message, options)) : logger.prompt(message, options), startTask(label) { if (host) return host.startTask(label); logger.start(label); let stopped = false; return { update(label) { if (!stopped) logger.start(label); }, stop(message, outcome) { if (stopped) return; stopped = true; if (message) logger[outcome === "failure" ? "fail" : "success"](message); } }; }, notify(notification) { if (host?.notify) return host.notify(notification); logger.box([notification.title, notification.message].filter(Boolean).join("\n\n")); return { dismiss: () => {}, dismissed: Promise.resolve() }; } }; } //#endregion //#region src/diagnostics/build.ts /** * B1xxx * Build / compilation diagnostics. * * @internal */ const buildDiagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase, reporters, codes: { NUXT_B1001: { why: (p) => `Could not compile template \`${p.filename}\`.`, fix: (p) => p.src ? `Check the template source file at \`${p.src}\` for syntax errors.` : "Check the `getContents` function of this template for errors.", docs: false }, NUXT_B1002: { why: (p) => `Error reading template from \`${p.src}\`.`, fix: "Check that the template `src` path exists and is readable.", docs: false }, NUXT_B1003: { why: "Invalid template. Templates must have either `src` or `getContents`.", fix: "Add a `getContents` function or a `src` path to the `addTemplate()` call.", docs: false }, NUXT_B1004: { why: "Failed to install dependencies.", fix: (p) => `Try installing manually with \`${p.installCommand}\`.`, docs: false }, NUXT_B1005: { why: (p) => `Plugin \`${p.plugin}\` failed to scan file \`${p.file}\`.`, fix: "Check the file for syntax errors, or report this issue to the plugin author.", docs: false }, NUXT_B1006: { why: (p) => `Cannot read file \`${p.file}\`.`, fix: "Check that the file exists and has correct permissions.", docs: false }, NUXT_B1007: { why: (p) => `Error in \`afterScan\` hook of plugin \`${p.plugin}\`.`, fix: "Check the plugin implementation or report this issue to the plugin author.", docs: false }, NUXT_B1008: { why: (p) => `No factory function found for \`${p.function}\` in file \`${p.file}\`. This is a Nuxt bug.`, fix: "Please report this issue at https://github.com/nuxt/nuxt/issues with the file contents.", docs: false }, NUXT_B1009: { why: (p) => `Duplicate keyed function name \`${p.functionName}\`${p.name && p.functionName !== p.name ? ` defined as \`${p.name}\`` : ""} with ${p.source ? `the same source \`${p.source}\`` : "no source"} found. Overwriting the existing entry.`, fix: "Ensure each keyed function has a unique name, or use a different source to distinguish them.", docs: false }, NUXT_B1010: { why: (p) => `Failed to read file \`${p.file}\` as it changed during read.`, fix: "The file was modified while being read, usually by a concurrent process writing to it. Try restarting the build.", docs: false }, NUXT_B1011: { why: (p) => `Failed to read file \`${p.file}\`.`, fix: "Check that the file exists and is readable, or try clearing the build cache with `nuxt clean`.", docs: false }, NUXT_B1012: { why: (p) => `Skipping unsafe cache path: ${p.path}. This cache file has a path that escapes the project directory (possible path traversal).`, fix: "Delete the cache with `nuxt clean` and rebuild.", docs: false }, NUXT_B1013: { why: (p) => `Failed to restore cached file \`${p.file}\`.`, fix: "Try clearing the build cache with `nuxt clean` and rebuilding from scratch.", docs: false }, NUXT_B1014: { why: "Problem checking for external configuration files.", fix: "This is likely a transient file system error. If it persists, check file permissions in your project root.", docs: false }, NUXT_B1015: { why: "Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.", fix: (p) => `Install \`@parcel/watcher\` for better performance: \`${p.installCommand}\`.`, docs: false }, NUXT_B1016: { why: "Failed to set up the `@parcel/watcher` file watcher.", fix: "This is likely an environment or file system issue. Watching for file changes may not work; restart the dev server and, if the problem persists, report it.", docs: false }, NUXT_B1017: { why: (p) => `Loading \`${p.builder}\` builder failed.`, fix: (p) => `Run \`${p.installCommand}\` to install it.`, docs: false }, NUXT_B1018: { why: (p) => `Loading \`${p.builder}\` server builder failed.`, fix: (p) => `Run \`${p.installCommand}\` to install it.`, docs: false }, NUXT_B1019: { why: (p) => `Unknown component mode \`${p.mode}\`. This might be an internal Nuxt bug.`, fix: "If you are a module author, ensure the component `mode` is set to `client`, `server`, or `all`. Otherwise, please report this issue.", docs: false }, NUXT_B1020: { why: "`experimental.watcher: \"builder\"` is set but the active builder does not implement `setupWatcher`. Falling back to the default file watcher.", fix: "Remove `experimental.watcher` from your `nuxt.config`, or use a builder that supports its own watcher.", docs: false }, NUXT_B1021: { why: (p) => `Component export name \`${p.export}\` is not a valid JavaScript identifier.`, fix: "If you are a module author, ensure the `export` you register for a component is a valid identifier. Otherwise, please report this issue.", docs: false }, NUXT_B1022: { why: (p) => `The build stopped with ${p.count} template${p.count === 1 ? "" : "s"} still compiling:\n - ${p.templates}`, fix: "A `getContents` function returned a promise that never settles. Resolve it before the bundler starts (for example from `pages:resolved` or `nitro:init`), rather than waiting on something that happens during or after bundling.", docs: false } } }); //#endregion //#region src/diagnostics/config.ts /** * B5xxx * Configuration diagnostics. * * @internal */ const configDiagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase, reporters, codes: { NUXT_B5001: { why: (p) => `No \`compatibilityDate\` is set in \`nuxt.config\`, so the \`${p.fallback}\` fallback is being used.`, fix: (p) => `Add \`compatibilityDate: '${p.latest}'\` to your \`nuxt.config.ts\`.` }, NUXT_B5002: { why: (p) => `\`@nuxt/webpack-builder\` could not be installed in \`${p.rootDir}\`.`, fix: (p) => `Install it manually with \`${p.installCommand}\`, or change the \`builder\` option to \`vite\` in \`nuxt.config\`.`, docs: false }, NUXT_B5003: { why: (p) => `The \`app\` namespace is reserved for Nuxt and exposed to the browser, but \`runtimeConfig.app.${p.key}\` is set.`, fix: "Move the key to `runtimeConfig.public` or a custom namespace." }, NUXT_B5004: { why: (p) => `External configuration files are not supported: ${p.files}.`, fix: "Move these configurations into `nuxt.config.ts` and delete the external config files." }, NUXT_B5005: { why: (p) => `Nuxt schema could not be loaded from \`${p.filePath}\`.`, fix: "Ensure the file exports a valid object with `defineNuxtSchema()` or as a plain object.", docs: false }, NUXT_B5006: { why: (p) => `\`${p.option}\` is used in dev mode, which causes a memory leak.`, fix: "Remove the hash option from your webpack config.", docs: false }, NUXT_B5007: { why: "The webpack server config `target` is not set to \"node\".", fix: "Set `target: \"node\"` in your webpack server configuration.", docs: false }, NUXT_B5009: { why: "`@parcel/watcher` cannot be resolved in your project, so `chokidar` is being used instead.", fix: (p) => `Install \`@parcel/watcher\` for better file watching: \`${p.installCommand}\`.`, docs: false }, NUXT_B5010: { why: (p) => `Required packages are not installed: ${p.names}.`, fix: (p) => `Run \`${p.installCommand}\` to install them.`, docs: false }, NUXT_B5011: { why: (p) => `Package \`${p.name}\` is missing.`, fix: (p) => `Run \`npx nuxt add ${p.name}\` to install it.`, docs: false }, NUXT_B5017: { why: (p) => `The config file \`${p.filePath}\` could not be loaded: ${p.error}`, fix: (p) => `Relative imports need an explicit file extension (\`./foo.ts\`, not \`./foo\`), and TypeScript syntax that emits code (such as \`enum\`) cannot be stripped. Alternatively, run \`${p.installCommand}\` and Nuxt will load it through jiti instead.`, docs: false }, NUXT_B5018: { why: (p) => `Extending from \`${p.source}\` downloads the layer at build time, which needs the \`giget\` package.`, fix: (p) => `Add the layer to \`package.json\` instead, so it is pinned and in your lockfile (for example \`"my-layer": "${p.source.replace(/^gh:/, "github:")}#"\`), then extend from its package name. Otherwise run \`${p.installCommand}\` to keep downloading it.`, docs: false }, NUXT_B5019: { why: (p) => `The Nuxt schema in \`${p.filePath}\` was skipped because \`jiti\` is not installed. A schema file's JSDoc annotations are read by an import-time transform, which is the one part of loading it the runtime cannot do on its own.`, fix: (p) => `Run \`${p.installCommand}\` to load it, or remove the \`nuxt.schema\` file.`, docs: false }, NUXT_B5021: { why: (p) => `The config file \`${p.filePath}\` was loaded as native ESM, which does not provide the CommonJS globals: ${p.error}`, fix: (p) => `Use \`import.meta.url\`, \`import.meta.dirname\` or \`createRequire(import.meta.url)\` from \`node:module\` instead of \`__dirname\`, \`__filename\` and \`require\`. Alternatively, run \`${p.installCommand}\` and Nuxt will load the file through jiti, which provides them.`, docs: false }, NUXT_B5022: { why: "A `nuxt.config` in yaml, toml, jsonc or json5 is parsed by the `confbox` package, which is not installed.", fix: (p) => `Run \`${p.installCommand}\`, or rename your config to \`nuxt.config.ts\`.`, docs: false }, NUXT_B5023: { why: (p) => `The config file \`${p.filePath}\` was loaded through jiti because the runtime could not load it: ${p.error}`, fix: "Loading it natively is faster, as jiti has to transform the file first. Relative imports need an explicit file extension, and `import.meta.dirname` replaces `__dirname`.", docs: false }, NUXT_B5024: { why: "`vue.vapor` requires vue `3.6.0` or later, so vapor mode has been disabled.", fix: "Upgrade to vue `3.6.0` or later, or remove `vue.vapor` from your `nuxt.config`.", docs: false }, NUXT_B5025: { why: (p) => `\`css\` entries are resolved as module ids, not relative to \`nuxt.config\`, so \`${p.entry}\` may not resolve to the intended file.`, fix: (p) => `Replace it with ${p.replacement}.`, docs: false }, NUXT_B5026: { why: (p) => `\`css\` entry \`${p.entry}\` could not be found${p.resolved ? ` (resolved to \`${p.resolved}\`)` : ""}.`, fix: "Ensure the file exists, or remove the entry from `css` in your `nuxt.config`.", docs: false }, NUXT_B5028: { why: "A generated development secret is being used because `runtimeConfig.appSecret` is unset.", fix: "Set `NUXT_APP_SECRET` in your `.env` to the output of `openssl rand -base64 32`. Builds do not generate a secret.", docs: false } } }); //#endregion //#region src/dependency.ts const isStackblitz = provider === "stackblitz"; async function ensureDependencyInstalled(names, options = {}) { const packages = Array.isArray(names) ? names : [names]; const nuxt = tryUseNuxt(); const rootDir = options.rootDir || nuxt?.options.rootDir || process.cwd(); const searchPaths = [ rootDir, ...options.from ? [options.from] : [], ...options.searchPaths || nuxt?.options.modulesDir || [] ]; const missing = findMissing(packages, searchPaths); if (missing.length === 0) return true; const installable = [...new Set(missing.map(toPackageName))].filter((name) => !isPackageInstalled(name, searchPaths)); if (installable.length === 0) return Array.isArray(names) ? missing : false; const formattedNames = installable.map((n) => `\`${n}\``).join(", "); configDiagnostics.NUXT_B5010({ names: formattedNames, installCommand: await getAddDependencyCommand(installable, rootDir, { dev: true }) }); if (isCI) return Array.isArray(names) ? missing : false; const terminal = useTerminal(); if (options.prompt === true || options.prompt !== false && !isStackblitz) { if (!hasTTY && !terminal.interactive) return Array.isArray(names) ? missing : false; if (await terminal.prompt(`Do you want to install ${formattedNames}?`, { type: "confirm", initial: true }) !== true) return Array.isArray(names) ? missing : false; } else if (!isStackblitz) return Array.isArray(names) ? missing : false; const task = terminal.startTask(`Installing ${formattedNames}...`); try { await runCommand(await resolveAddCommand(installable, rootDir, { dev: true }), rootDir); task.stop(`Installed ${formattedNames}`); } catch (err) { task.stop(void 0, "failure"); buildDiagnostics.NUXT_B1004({ installCommand: await getAddDependencyCommand(installable, rootDir, { dev: true }), cause: err }); return Array.isArray(names) ? missing : false; } const stillMissing = findMissing(missing, searchPaths); if (stillMissing.length === 0) return true; return Array.isArray(names) ? stillMissing : false; } function findMissing(packages, searchPaths) { const missing = []; for (const name of packages) { if (isResolvable(name, searchPaths)) continue; missing.push(name); } return missing; } function isResolvable(name, searchPaths) { for (const from of searchPaths) if (resolveModulePath(name, { from, try: true, cache: false })) return true; return false; } /** Whether the package `name` is installed, even if it has no entry that can be imported. */ function isPackageInstalled(name, searchPaths) { return isResolvable(name, searchPaths) || searchPaths.some((from) => hasPackageDir(name, from)); } /** * The installed package that `specifier` is a missing subpath of, such as `tailwindcss` for * `tailwindcss/nesting` when `tailwindcss` is installed but does not provide `nesting`. * * @internal */ function findPackageMissingSubpath(specifier, searchPaths) { const name = toPackageName(specifier); if (name !== specifier && !isResolvable(specifier, searchPaths) && isPackageInstalled(name, searchPaths)) return name; } function hasPackageDir(name, from) { let dir = from.startsWith("file:") ? fileURLToPath(from) : from; while (true) { if (existsSync(join(dir, "node_modules", name, "package.json"))) return true; const parent = dirname(dir); if (parent === dir) return false; dir = parent; } } const PACKAGE_NAME_RE = /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*(?=\/|$)/i; /** * The package a bare module specifier belongs to, such as `@scope/pkg` for `@scope/pkg/subpath`. * Anything else (paths, aliases, specifiers with a protocol) is returned unchanged. * * @internal */ function toPackageName(specifier) { return specifier.match(PACKAGE_NAME_RE)?.[0] || specifier; } /** * Get the command a user should run to add dependencies to their project, using the * package manager detected from `cwd` (falling back to `npm`). * * Module specifiers with a subpath are installed as the package they belong to. * * @param names - One or more package names to install * @param cwd - Directory to detect the package manager from * @param options - Options for the install command * @param options.dev - Whether the command should install as a dev dependency */ async function getAddDependencyCommand(names, cwd, options = {}) { const { command, args } = await resolveAddCommand(names, cwd, options); return [command, ...args].join(" "); } async function resolveAddCommand(names, cwd, options) { const { agent } = await detect({ cwd }).catch(() => null) || { agent: "npm" }; const packages = [...new Set((Array.isArray(names) ? names : [names]).map(toPackageName))]; const args = [...options.dev ? ["-D"] : [], ...packages]; return resolveCommand(agent, "add", args, { ignoreWorkspaceRootCheck: true }) || { command: "npm", args: ["i", ...args] }; } async function runCommand({ command, args }, cwd) { if (command === "pnpm") args = [ ...args, "--config.confirm-modules-purge=false", "--config.strict-dep-builds=false" ]; const result = await x(command, args, { nodeOptions: { cwd, stdio: [ "ignore", "ignore", "pipe" ] } }); if (result.exitCode !== 0) throw new Error(`\`${command} ${args.join(" ")}\` exited with code ${result.exitCode}${result.stderr ? `\n${result.stderr.trim()}` : ""}`); } //#endregion //#region src/internal/jiti.ts const LOADER_ERROR_CODES = /* @__PURE__ */ new Set([ "ERR_MODULE_NOT_FOUND", "ERR_IMPORT_ATTRIBUTE_MISSING", "ERR_UNKNOWN_FILE_EXTENSION", "ERR_UNSUPPORTED_DIR_IMPORT", "ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING", "ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX", "ERR_REQUIRE_ESM", "ERR_PACKAGE_IMPORT_NOT_DEFINED", "ERR_PACKAGE_PATH_NOT_EXPORTED" ]); const CJS_GLOBAL_ERROR_RE = /^(__dirname|__filename|require|module|exports) is not defined\b/; /** * Whether a failed `import()` failed because the runtime would not load the file, rather than * because the file threw once it was running. * * A resolution failure anywhere in the imported file's static graph counts, not just one for the * file itself. * * @param error the error the failed `import()` rejected with */ function isLoaderError(error) { const { code } = error ?? {}; return typeof code === "string" && LOADER_ERROR_CODES.has(code); } /** * The CJS global a failed `import()` reached for, or `undefined` if it failed for another reason. * Unlike {@link isLoaderError} the file was loaded and threw on its own, but jiti supplies these * globals so a retry is still worthwhile. * * Only covers the error raised while the module is evaluated: a `require()` inside a function * called later throws long after the import settled. * * @param error the error the failed `import()` rejected with */ function getMissingCjsGlobal(error) { const { name, message } = error ?? {}; if (name !== "ReferenceError" || typeof message !== "string") return; return CJS_GLOBAL_ERROR_RE.exec(message)?.[1]; } const DEPENDENCY_FIELDS = [ "dependencies", "devDependencies", "peerDependencies", "optionalDependencies" ]; const declaredJitiCache = /* @__PURE__ */ new Map(); const nuxtJitiCache = /* @__PURE__ */ new Map(); const reportedFallbacks = /* @__PURE__ */ new Set(); /** * Whether to tell the user that `filePath` was loaded through jiti rather than by the runtime, and * record that they have been told. * * Returns `true` at most once per file, so a dev server reloading a config does not repeat itself. * Silent only where jiti is not something the project could lose. * * @param filePath the file that had to be loaded through jiti * @param rootDir project root, where the search for a declared `jiti` starts * @param compatibilityVersion resolved `future.compatibilityVersion` */ function shouldReportJitiFallbackOnce(filePath, rootDir, compatibilityVersion) { if (reportedFallbacks.has(filePath) || jitiIsGuaranteed(rootDir, compatibilityVersion)) return false; reportedFallbacks.add(filePath); return true; } function jitiIsGuaranteed(rootDir, compatibilityVersion) { if (declaresJiti(rootDir)) return true; return compatibilityVersion < 5 && nuxtDependsOnJiti(rootDir); } function readDependencies(path) { try { return JSON.parse(readFileSync(path, "utf-8")); } catch { return; } } function declaresJiti(dir) { let declared = declaredJitiCache.get(dir); if (declared === void 0) { declared = false; for (let current = dir, parent = dirname(dir);; current = parent, parent = dirname(current)) { const pkg = readDependencies(join(current, "package.json")); if (DEPENDENCY_FIELDS.some((field) => !!pkg?.[field]?.jiti)) { declared = true; break; } if (parent === current) break; } declaredJitiCache.set(dir, declared); } return declared; } function nuxtDependsOnJiti(dir) { let depends = nuxtJitiCache.get(dir); if (depends === void 0) { const from = directoryToURL(dir); const path = resolveModulePath("nuxt/package.json", { from, try: true }) ?? resolveModulePath("nuxt-nightly/package.json", { from, try: true }); depends = !!path && !!readDependencies(path)?.dependencies?.jiti; nuxtJitiCache.set(dir, depends); } return depends; } let cached; /** * Load the `jiti` module, or return `undefined` when it is unavailable. * * `jiti` is an optional peer dependency, needed only where the runtime cannot load a file itself. * It is looked for in three places, in order, so that a project which already has `jiti` never * sees a prompt: * * 1. Resolvable from `@nuxt/kit` — the optional peer dependency, and how a package manager * satisfies it when the project (or `nuxt` itself, on v3 and v4) depends on `jiti`. * 2. Resolvable from the project, or from `nuxt` itself. A project depends on `nuxt` rather than * on what `nuxt` depends on, so under an isolated `node_modules` the `jiti` that Nuxt 3 and 4 * install is reachable only by hopping through `nuxt`. * 3. Installed on request, if `install` is not disabled. * * A successful load is cached for the lifetime of the process; a failure is not, so a later call * with different search paths can still succeed. The in-flight promise is shared so that * concurrent callers cannot each trigger an install prompt. */ function loadJiti(options) { return cached ??= resolveJiti(options).then((mod) => { if (!mod) cached = void 0; return mod; }, (error) => { cached = void 0; throw error; }); } async function resolveJiti(options) { const resolved = await importFromKit() ?? await importFromProject(options); if (resolved) return resolved; if (options.install === false) return; if (!await ensureDependencyInstalled("jiti", { rootDir: options.rootDir, searchPaths: options.searchPaths, from: import.meta.url })) return; return await importFromKit() ?? await importFromProject(options); } function importFromKit() { return import("jiti").catch(() => void 0); } async function importFromProject(options) { const path = resolveFromProject(options); if (!path) return; return await import(pathToFileURL(path).href).catch(() => void 0); } function resolveFromProject(options) { const from = [options.rootDir, ...options.searchPaths ?? []].map((dir) => directoryToURL(dir.replace(/[/\\]node_modules[/\\]?$/, ""))); const direct = resolveModulePath("jiti", { from, try: true }); if (direct) return direct; const nuxt = resolveModulePath("nuxt", { from, try: true }) ?? resolveModulePath("nuxt-nightly", { from, try: true }); if (!nuxt) return; let realNuxt; try { realNuxt = realpathSync(nuxt); } catch { return; } return resolveModulePath("jiti", { from: pathToFileURL(realNuxt), try: true }); } //#endregion //#region src/module/install.ts const NODE_MODULES_RE = /[/\\]node_modules[/\\]/; const ignoredConfigKeys = /* @__PURE__ */ new Set([ "components", "imports", "pages", "devtools", "telemetry" ]); /** * Installs a set of modules on a Nuxt instance. * @internal */ async function installModules(modulesToInstall, resolvedModulePaths, nuxt = useNuxt()) { const localLayerModuleDirs = []; for (const l of nuxt.options._layers) { const srcDir = l.config.srcDir || l.cwd; if (!NODE_MODULES_RE.test(srcDir)) localLayerModuleDirs.push(resolve(srcDir, l.config?.dir?.modules || "modules").replace(/\/?$/, "/")); } nuxt._moduleOptionsFunctions ||= /* @__PURE__ */ new Map(); const resolvedModules = []; const modulesByMetaName = /* @__PURE__ */ new Map(); const moduleLoadCache = /* @__PURE__ */ new Map(); for (const [key] of modulesToInstall) moduleLoadCache.set(key, loadNuxtModuleInstance(key, nuxt)); const inlineConfigKeys = new Set(await Promise.all([...modulesToInstall].map(async ([mod]) => { if (typeof mod === "string") return; const meta = await Promise.resolve(mod.getMeta?.()); if (meta?.name) modulesByMetaName.set(meta.name, mod); if (meta?.configKey) { if (meta.configKey !== meta.name) modulesByMetaName.set(meta.configKey, mod); return meta.configKey; } }))); let error; const dependencyMap = /* @__PURE__ */ new Map(); const dependencyPaths = /* @__PURE__ */ new Map(); for (const [key, options] of modulesToInstall) { const res = await (moduleLoadCache.get(key) || loadNuxtModuleInstance(dependencyPaths.get(key) || key, nuxt)).catch((err) => { if (dependencyMap.has(key) && typeof key === "string") err.cause = `Could not resolve \`${key}\` (specified as a dependency of ${dependencyMap.get(key)}).`; throw err; }); const dependencyMeta = await res.nuxtModule.getModuleDependencies?.(nuxt) || {}; for (const [name, value] of Object.entries(dependencyMeta)) { if (!value.overrides && !value.defaults && !value.version && value.optional) continue; const resolvedModule = modulesByMetaName.has(name) ? resolveModuleWithOptions(modulesByMetaName.get(name), nuxt) : resolveModuleDefinition(name, nuxt, res.resolvedModulePath); const moduleToAttribute = typeof key === "string" ? `\`${key}\`` : "a module in `nuxt.options`"; if (!resolvedModule?.module) { const message = `Could not resolve \`${name}\` (specified as a dependency of ${moduleToAttribute}).`; error = new TypeError(message); continue; } if (value.version) { const pkg = await readPackageJSON(name, { from: [(await moduleLoadCache.get(resolvedModule.module))?.resolvedModulePath || dependencyPaths.get(resolvedModule.module) || res.resolvedModulePath, ...nuxt.options.modulesDir].filter(Boolean) }).catch(() => null); if (pkg?.version && !satisfies(pkg.version, value.version, { includePrerelease: true })) { const message = `Module \`${name}\` version (\`${pkg.version}\`) does not satisfy \`${value.version}\` (requested by ${moduleToAttribute}).`; error = new TypeError(message); } } if (value.overrides || value.defaults) { const currentFns = nuxt._moduleOptionsFunctions.get(resolvedModule.module) || []; nuxt._moduleOptionsFunctions.set(resolvedModule.module, [...currentFns, () => ({ defaults: value.defaults, overrides: value.overrides })]); } if (value.optional === true) continue; nuxt.options.typescript.hoist.push(name); if (resolvedModule && !modulesToInstall.has(resolvedModule.module) && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) { if (typeof resolvedModule.module === "string" && inlineConfigKeys.has(resolvedModule.module)) continue; modulesToInstall.set(resolvedModule.module, resolvedModule.options); dependencyMap.set(resolvedModule.module, moduleToAttribute); const path = resolvedModule.resolvedPath || resolvedModule.module; if (typeof path === "string") { resolvedModulePaths.add(path); dependencyPaths.set(resolvedModule.module, path); } } } resolvedModules.push({ moduleToInstall: key, meta: await res.nuxtModule.getMeta?.(), nuxtModule: res.nuxtModule, buildTimeModuleMeta: res.buildTimeModuleMeta, resolvedModulePath: res.resolvedModulePath, inlineOptions: options }); } if (error) throw error; for (const { nuxtModule, meta = {}, moduleToInstall, buildTimeModuleMeta, resolvedModulePath, inlineOptions } of resolvedModules) { const configKey = meta.configKey; const optionsFns = /* @__PURE__ */ new Set([ ...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [], ...meta?.name ? nuxt._moduleOptionsFunctions.get(meta.name) || [] : [], ...configKey ? nuxt._moduleOptionsFunctions.get(configKey) || [] : [] ]); if (optionsFns.size > 0) { const overrides = []; const defaults = []; for (const fn of optionsFns) { const options = fn(); overrides.push(options.overrides); defaults.push(options.defaults); } if (configKey) nuxt.options[configKey] = defu(...overrides, nuxt.options[configKey], ...defaults); } const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false; if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, inlineOptions, nuxt); const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0; await callModule(nuxt, nuxtModule, inlineOptions, { meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta), nameOrPath: path, modulePath: resolvedModulePath || path, localLayerModuleDirs }); } delete nuxt._moduleOptionsFunctions; } /** * Installs a module on a Nuxt instance. * @deprecated Use module dependencies. */ async function installModule(moduleToInstall, inlineOptions, nuxt = useNuxt()) { const { nuxtModule, buildTimeModuleMeta, resolvedModulePath } = await loadNuxtModuleInstance(moduleToInstall, nuxt); const localLayerModuleDirs = []; for (const dirs of getLayerDirectories(nuxt)) if (!NODE_MODULES_RE.test(dirs.app)) localLayerModuleDirs.push(dirs.modules); const meta = await nuxtModule.getMeta?.(); let mergedOptions = inlineOptions; const configKey = meta?.configKey; if (configKey && nuxt._moduleOptionsFunctions) { const optionsFns = [...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [], ...nuxt._moduleOptionsFunctions.get(configKey) || []]; if (optionsFns.length > 0) { const overrides = []; const defaults = []; for (const fn of optionsFns) { const options = fn(); overrides.push(options.overrides); defaults.push(options.defaults); } mergedOptions = defu(inlineOptions, ...overrides, nuxt.options[configKey], ...defaults); nuxt.options[configKey] = mergedOptions; } } const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false; if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, mergedOptions, nuxt); const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0; await callModule(nuxt, nuxtModule, mergedOptions, { meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta), nameOrPath: path, modulePath: resolvedModulePath || path, localLayerModuleDirs }); } function resolveModuleWithOptions(definition, nuxt) { return resolveModuleDefinition(definition, nuxt); } function resolveModuleDefinition(definition, nuxt, parentPath) { const [module, options = {}] = Array.isArray(definition) ? definition : [definition, {}]; if (!module) return; if (typeof module !== "string") return { module, options }; const modAlias = resolveAlias$1(module, nuxt.options.alias); return { module, resolvedPath: resolveModulePath(modAlias, { try: true, from: [...parentPath ? [pathToFileURL(parentPath)] : [], ...nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/")))], suffixes: [ "nuxt", "nuxt/index", "module", "module/index", "", "index" ], extensions: DEFAULT_JS_FILE_EXTENSIONS }) || modAlias, options }; } let _jitiCache; /** * Resolve a jiti instance scoped to the project, or `undefined` if jiti is unavailable and the * user declined to install it. * * Needed only for module sources the runtime cannot import itself (TypeScript that cannot be * type-stripped, CJS interop, alias-prefixed imports). Cached per Nuxt instance so at most one * install prompt is shown per build. * * @param nuxt the Nuxt instance the jiti instance is scoped to * @param install whether looking for jiti may extend to offering to install it, which is only * appropriate where jiti is expected to be the answer */ async function getSharedJiti(nuxt, install) { _jitiCache ||= /* @__PURE__ */ new WeakMap(); let promise = _jitiCache.get(nuxt); if (!promise) { promise = loadJiti({ rootDir: nuxt.options.rootDir, searchPaths: nuxt.options.modulesDir, install }).then((mod) => mod?.createJiti(nuxt.options.rootDir, { alias: nuxt.options.alias })); _jitiCache.set(nuxt, promise); } const jiti = await promise; if (!jiti && !install) _jitiCache.delete(nuxt); return jiti; } const CJS_GLOBALS_HINT = "The file was loaded as native ESM, which does not provide the CommonJS globals `__dirname`, `__filename`, `require`, `module` or `exports`. Use `import.meta.url`, `import.meta.dirname` and `createRequire(import.meta.url)` from `node:module` instead."; /** * Explain a failed native import in terms of what the author can change. The runtime supports * TypeScript, so the fix is never "stop using TypeScript": it is the specific thing the runtime * will not do. */ function describeNativeImportFailure(error) { if (getMissingCjsGlobal(error)) return CJS_GLOBALS_HINT; switch (error?.code) { case "ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING": return "Published packages cannot ship TypeScript entrypoints, because the runtime does not strip types under `node_modules`. Ask the author to publish compiled JavaScript."; case "ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX": return "The runtime erases type annotations but cannot compile TypeScript syntax that emits code, such as `enum`, `namespace`, decorators or constructor parameter properties. Replace it with erasable syntax."; case "ERR_MODULE_NOT_FOUND": case "ERR_UNSUPPORTED_DIR_IMPORT": return "A specifier could not be resolved. Relative imports need an explicit file extension (`./foo.ts`, not `./foo`), and aliases such as `~/` are not resolved outside the bundler."; default: return "Check that the module and everything it imports can be loaded by the runtime directly."; } } async function loadNuxtModuleInstance(nuxtModule, nuxt = useNuxt()) { let buildTimeModuleMeta = {}; if (typeof nuxtModule === "function") return { nuxtModule, buildTimeModuleMeta }; if (typeof nuxtModule !== "string") throw kitDiagnostics.NUXT_B8015({ received: `${typeof nuxtModule} (${JSON.stringify(nuxtModule)})` }); nuxtModule = resolveAlias$1(nuxtModule, nuxt.options.alias); if (nuxtModule.startsWith("./") || nuxtModule.startsWith("../")) nuxtModule = resolve(nuxt.options.rootDir, nuxtModule); let src; try { src = resolveModuleURL(nuxtModule, { from: nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/"))), suffixes: [ "nuxt", "nuxt/index", "module", "module/index", "", "index" ], extensions: DEFAULT_JS_FILE_EXTENSIONS }); } catch (error) { throw kitDiagnostics.NUXT_B8017({ module: nuxtModule, installCommand: isAbsolute(nuxtModule) ? void 0 : await getAddDependencyCommand(nuxtModule, nuxt.options.rootDir), cause: error }); } const resolvedModulePath = fileURLToPath(src); let resolvedNuxtModule; try { resolvedNuxtModule = await import(src).then((r) => interopDefault(r)); } catch (nativeError) { const missingGlobal = getMissingCjsGlobal(nativeError); const jitiCanHelp = isLoaderError(nativeError) || !!missingGlobal; const jiti = await getSharedJiti(nuxt, jitiCanHelp); if (!jiti) { if (!jitiCanHelp) throw kitDiagnostics.NUXT_B8018({ module: nuxtModule, error: String(nativeError), cause: nativeError }); throw kitDiagnostics.NUXT_B8020({ module: nuxtModule, error: nativeError instanceof Error ? nativeError.message : String(nativeError), hint: describeNativeImportFailure(nativeError), installCommand: await getAddDependencyCommand("jiti", nuxt.options.rootDir, { dev: true }), cause: nativeError }); } try { resolvedNuxtModule = await jiti.import(src, { default: true }); } catch (error) { const repeated = missingGlobal && getMissingCjsGlobal(error) === missingGlobal; const reported = jitiCanHelp && !repeated ? error : nativeError; throw kitDiagnostics.NUXT_B8018({ module: nuxtModule, error: String(reported), cause: reported }); } if (shouldReportJitiFallbackOnce(resolvedModulePath, nuxt.options.rootDir, nuxt.options.future?.compatibilityVersion ?? 4)) kitDiagnostics.NUXT_B8023({ module: nuxtModule, error: nativeError instanceof Error ? nativeError.message : String(nativeError) }); } if (typeof resolvedNuxtModule !== "function") throw kitDiagnostics.NUXT_B8016({ module: nuxtModule }); const moduleMetadataPath = new URL("module.json", src); if (existsSync(moduleMetadataPath)) buildTimeModuleMeta = JSON.parse(await promises.readFile(moduleMetadataPath, "utf-8")); return { nuxtModule: resolvedNuxtModule, buildTimeModuleMeta, resolvedModulePath }; } function getDirectory(p) { try { return isAbsolute(p) && lstatSync(p).isFile() ? dirname(p) : p; } catch {} return p; } const normalizeModuleTranspilePath = (p) => { return getDirectory(p).split("node_modules/").pop(); }; async function callLifecycleHooks(nuxtModule, meta = {}, inlineOptions, nuxt = useNuxt()) { if (!meta.name || !meta.version) return; if (!nuxtModule.onInstall && !nuxtModule.onUpgrade) return; const previousVersion = read({ dir: nuxt.options.rootDir, name: ".nuxtrc" })?.setups?.[meta.name]; try { if (!previousVersion) await nuxtModule.onInstall?.(nuxt); else if (isGreaterThan(meta.version, previousVersion)) await nuxtModule.onUpgrade?.(nuxt, inlineOptions, previousVersion); if (previousVersion !== meta.version) update({ setups: { [meta.name]: meta?.version } }, { dir: nuxt.options.rootDir, name: ".nuxtrc" }); } catch (e) { kitDiagnostics.NUXT_B8019({ phase: !previousVersion ? "install" : "upgrade", name: meta.name, error: String(e) }); } } function getModuleName(nuxtModule, meta, nameOrPath, rootDir) { if (meta.name) return meta.name; if (nameOrPath) { const parsed = parseNodeModulePath(nameOrPath); if (parsed.name) return parsed.name; return isAbsolute(nameOrPath) ? relative(rootDir, nameOrPath) : nameOrPath; } return nuxtModule.name || "anonymous module"; } async function callModule(nuxt, nuxtModule, moduleOptions = {}, options) { const modulePath = options.modulePath; const nameOrPath = options.nameOrPath; const localLayerModuleDirs = options.localLayerModuleDirs; const fn = () => nuxt.options.experimental?.debugModuleMutation && nuxt._asyncLocalStorageModule ? nuxt._asyncLocalStorageModule.run(nuxtModule, () => nuxtModule(moduleOptions, nuxt)) : nuxtModule(moduleOptions, nuxt); const moduleInfo = { name: getModuleName(nuxtModule, options.meta, nameOrPath, nuxt.options.rootDir), meta: options.meta, path: modulePath }; await nuxt.callHook("module:before", moduleInfo); const start = performance.now(); const res = options.meta.disabled ? false : await fn(); const duration = Math.round((performance.now() - start) * 100) / 100; const timings = defu({ setup: duration }, (res || {}).timings); if (!options.meta.disabled) { if (duration > 5e3 && moduleInfo.name !== "@nuxt/telemetry") kitDiagnostics.NUXT_B8014({ name: moduleInfo.name, time: duration }); else if (nuxt.options.debug && nuxt.options.debug.modules) logger.info(`Module \`${moduleInfo.name}\` took \`${duration}ms\` to setup.`); } let entryPath; if (typeof modulePath === "string") { const parsed = parseNodeModulePath(modulePath); if (parsed.name) { const subpath = await lookupNodeModuleSubpath(modulePath) || "."; entryPath = join(parsed.name, subpath === "./" ? "." : subpath); } if (res !== false) { const moduleRoot = parsed.dir ? parsed.dir + parsed.name : resolvePackageDir(modulePath, { try: true }) || modulePath; nuxt.options.build.transpile.push(normalizeModuleTranspilePath(moduleRoot)); const directory = moduleRoot.replace(/\/?$/, "/"); if (moduleRoot !== nameOrPath && !localLayerModuleDirs.some((dir) => directory.startsWith(dir))) nuxt.options.modulesDir.push(join(moduleRoot, "node_modules")); } } if (nameOrPath) { entryPath ||= resolveAlias$1(nameOrPath, nuxt.options.alias); if (entryPath !== nameOrPath) options.meta.rawPath = nameOrPath; } nuxt.options._installedModules ||= []; nuxt.options._installedModules.push({ meta: options.meta, module: nuxtModule, timings: options.meta.disabled ? void 0 : timings, entryPath }); await nuxt.callHook("module:done", { ...moduleInfo, entryPath, timings }); } //#endregion //#region src/nitro.ts const SERVER_APIS = /* @__PURE__ */ new Set([ "nitro2", "nitro3", "nuxt" ]); const NITRO_APIS = /* @__PURE__ */ new Set(["nitro2", "nitro3"]); const NITRO_SERVER_BUILDER_RE = /(?:^|[\\/])(?:@nuxt\/)?nitro-server(?:$|[\\/.])/; /** * The server APIs the configured `server.builder` runs, most preferred first, or * `undefined` when nothing identifies it. Hardcoded per builder for now. * @internal */ function getHostServerApis(nuxt = useNuxt()) { const builder = nuxt.options.server?.builder; if (builder !== void 0 && !(typeof builder === "string" && NITRO_SERVER_BUILDER_RE.test(builder))) return ["nuxt"]; switch (getNitroVersion(nuxt)) { case 3: return [ "nitro3", "nuxt", "nitro2" ]; case 2: return ["nitro2", "nuxt"]; default: return; } } /** * Returns the variant the configured server prefers, or `undefined` (with a warning) * when it runs none of them. * * @example * ```ts * const server = resolveServerVariant({ * nuxt: resolver.resolve('./runtime/server'), * nitro2: resolver.resolve('./runtime/server.legacy'), * }) * ``` */ function resolveServerVariant(variants) { return resolveVariant("resolveServerVariant", variants, (value) => value, SERVER_APIS)?.value; } /** An unidentifiable host is, in practice, an older Nuxt on nitro v2. */ const UNIDENTIFIED_HOST_APIS = [ "nitro2", "nuxt", "nitro3" ]; /** * The server API a registration was resolved for, and the variants the host does not run. * * Symbol-keyed and non-enumerable, so that an entry is exactly what a server builder * expects to find in `serverHandlers`, including one that hands it straight to nitro. * @internal */ const kServerApi = Symbol.for("nuxt.serverApi"); /** @internal */ const kUnusedVariants = Symbol.for("nuxt.serverApiUnused"); /** * The variant of a registration this host runs, or `undefined` when it runs none of them. * * Resolved here rather than by the server builder, because kit is installed against hosts * whose builder knows nothing about variants. */ function resolveVariant(api, variants, normalizeValue, accepted) { const host = (getHostServerApis() ?? UNIDENTIFIED_HOST_APIS).filter((candidate) => accepted.has(candidate)); if (host.length === 0) { kitDiagnostics.NUXT_B8024({ api, declared: "", host: (getHostServerApis() ?? []).join("`, `") }); return; } if (variants === null || typeof variants !== "object") return { value: normalizeValue(variants), unused: [] }; const declared = /* @__PURE__ */ new Map(); for (const key in variants) { if (!accepted.has(key)) throw kitDiagnostics.NUXT_B8025({ api, value: key, accepted: [...accepted].join("`, `") }); declared.set(key, normalizeValue(variants[key])); } const picked = host.find((candidate) => declared.has(candidate)); if (picked === void 0) { kitDiagnostics.NUXT_B8024({ api, declared: [...declared.keys()].join("`, `"), host: host.join("`, `") }); return; } const value = declared.get(picked); declared.delete(picked); return { value, api: picked, unused: [...declared.values()] }; } function withVariantMeta(entry, resolved) { if (resolved.api !== void 0) Object.defineProperty(entry, kServerApi, { value: resolved.api, configurable: true }); if (resolved.unused.length > 0) Object.defineProperty(entry, kUnusedVariants, { value: resolved.unused, configurable: true }); return entry; } const HANDLER_METHOD_RE = /\.(get|head|patch|post|put|delete|connect|options|trace|query)(\.\w+)*$/; const WILDCARD_SUFFIX_RE = /\/\*\*(?::\w+)?$/; /** * h3 v1 routes with radix3, where `/fonts/**` matches every path below `/fonts` but not * `/fonts` itself; h3 v2 routes with rou3, where it matches both. A second registration on * the base path gives one wildcard route the same reach on either, and rou3 prefers the * static route, so the pair is unambiguous where both are registered. * * A handler already registered on the base path for the same method keeps it: a * method-specific handler there does not answer the other methods the wildcard covers. * * Not applied to middleware, which nitro v2 mounts with `app.use()` and so already runs on * the base path, nor to `/**`, whose base would shadow the renderer on `/`. */ function addLegacyBaseRoute(nuxt, entry, resolved) { const route = entry.route; if (!route || entry.middleware || getNitroVersion(nuxt) !== 2) return; const base = route.replace(WILDCARD_SUFFIX_RE, ""); if (base === route || !base || base === "/") return; const method = entry.method?.toUpperCase(); if (!nuxt.options.serverHandlers.some((handler) => handler.route === base && (!handler.method || handler.method.toUpperCase() === method))) nuxt.options.serverHandlers.push(withVariantMeta({ ...entry, route: base }, resolved)); } const LITERAL_ROUTE_RE = /^[^:*]+$/; /** * Nitro v2 mounts dev handlers with `app.use()`, a literal prefix match that ignores method, * so a `/fonts/**` route needs a second registration on `/fonts` to reach anything. */ function addLegacyDevBaseRoute(nuxt, entry, resolved) { const route = entry.route; if (!route || getNitroVersion(nuxt) !== 2) return; const base = route.replace(WILDCARD_SUFFIX_RE, ""); if (base === route || !base || base === "/" || !LITERAL_ROUTE_RE.test(base)) return; if (!nuxt.options.devServerHandlers.some((handler) => handler.route === base)) nuxt.options.devServerHandlers.push(withVariantMeta({ ...entry, route: base }, resolved)); } /** * Adds a server handler. * * `handler` is a path, or one path per server API for a module shipping an implementation * for each while it migrates: the host runs the one it prefers, and the registration is * skipped if it can run none of them. * * @example * ```ts * addServerHandler({ * route: '/api/test', * handler: { * nuxt: resolver.resolve('./runtime/test'), * nitro2: resolver.resolve('./runtime/test.v2'), * }, * }) * ``` */ function addServerHandler(handler) { const nuxt = useNuxt(); const resolved = resolveVariant("addServerHandler", handler.handler, normalize, SERVER_APIS); if (!resolved) return; const [, method = void 0] = resolved.value.match(HANDLER_METHOD_RE) || []; const entry = { method: getNitroVersion(nuxt) === 2 ? method : method?.toUpperCase(), ...handler, handler: resolved.value }; nuxt.options.serverHandlers.push(withVariantMeta(entry, resolved)); addLegacyBaseRoute(nuxt, entry, resolved); } /** * Adds a server handler for development only. * * Variants per server API are resolved as for {@link addServerHandler}. */ function addDevServerHandler(handler) { const nuxt = useNuxt(); const resolved = resolveVariant("addDevServerHandler", handler.handler, (value) => value, SERVER_APIS); if (!resolved) return; const entry = { ...handler, handler: resolved.value }; nuxt.options.devServerHandlers.push(withVariantMeta(entry, resolved)); addLegacyDevBaseRoute(nuxt, entry, resolved); } /** * Adds a nitro plugin, which runs once when the server starts. * * `plugin` is a path, or one path per nitro major, resolved as for * {@link addServerHandler}. There is no portable variant: `nuxt/server` has no plugin * surface, so a plugin is written against nitro. */ function addNitroPlugin(plugin) { const nuxt = useNuxt(); const resolved = resolveVariant("addNitroPlugin", plugin, normalize, NITRO_APIS); if (!resolved) return; const plugins = nuxt.options._serverPlugins; if (Array.isArray(plugins)) { plugins.push({ plugin: resolved.value, compatibility: resolved.api, unused: resolved.unused }); return; } nuxt.options.nitro.plugins ||= []; if (!nuxt.options.nitro.plugins.includes(resolved.value)) nuxt.options.nitro.plugins.push(resolved.value); } /** @deprecated Use {@link addNitroPlugin}: a startup plugin is nitro's, not a portable server API. */ function addServerPlugin(plugin) { addNitroPlugin(plugin); } /** * Adds routes to be prerendered */ function addPrerenderRoutes(routes) { const nuxt = useNuxt(); routes = toArray(routes).filter(Boolean); if (!routes.length) return; nuxt.hook("prerender:routes", (ctx) => { for (const route of routes) ctx.routes.add(route); }); } /** * Access to the Nitro instance * * **Note:** You can call `useNitro()` only after `ready` hook. * * **Note:** Changes to the Nitro instance configuration are not applied. * @example * * ```ts * nuxt.hook('ready', () => { * console.log(useNitro()) * }) * ``` */ function useNitro() { const nitro = tryUseNitro(); if (!nitro) throw kitDiagnostics.NUXT_B8003(); return nitro; } /** * Access to the Nitro instance, if there is one. * * Returns `undefined` before the `ready` hook has run, and for the lifetime of the * build when the configured `server.builder` is not backed by Nitro (such as the * static SPA builder). Prefer this over {@link useNitro} for anything that should * still work without a server runtime. */ function tryUseNitro() { return tryUseNuxt()?._nitro; } /** * Add server imports to be auto-imported in the server program. */ function addServerImports(imports) { const nuxt = useNuxt(); const _imports = []; for (const entry of toArray(imports)) { const resolved = resolveVariant("addServerImports", entry.from, (value) => value, SERVER_APIS); if (resolved) _imports.push({ ...entry, from: resolved.value }); } if (_imports.length === 0) return; nuxt.hook("nitro:config", (config) => { config.imports ||= {}; config.imports.imports ||= []; config.imports.imports.push(..._imports); }); } /** * Add directories to be scanned for auto-imports in the server program. */ function addServerImportsDir(dirs, opts = {}) { const nuxt = useNuxt(); const _dirs = toArray(dirs); if (_dirs.length === 0) return; nuxt.hook("nitro:config", (config) => { config.imports ||= {}; config.imports.dirs ||= []; config.imports.dirs[opts.prepend ? "unshift" : "push"](..._dirs); }); } /** * Add directories to be scanned by Nitro. It will check for subdirectories, * which will be registered just like the `~~/server` folder is. */ function addServerScanDir(dirs, opts = {}) { useNuxt().hook("nitro:config", (config) => { config.scanDirs ||= []; for (const dir of toArray(dirs)) config.scanDirs[opts.prepend ? "unshift" : "push"](dir); }); } //#endregion //#region src/diagnostics/components.ts /** * B3xxx * Component diagnostics. * * @internal */ const componentDiagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase, reporters, codes: { NUXT_B3001: { why: (p) => `Components directory not found: \`${p.dirPath}\`.`, fix: "If this is intentional, remove it from `components.dirs` in your `nuxt.config`.", docs: false }, NUXT_B3002: { why: (p) => `Using server component \`${p.component}\` with \`ssr: false\` is not supported with auto-detected component islands.`, fix: "Set `experimental.componentIslands` to `true` in your `nuxt.config`, or convert the component to a client component.", docs: false }, NUXT_B3003: { why: (p) => `Standalone server components (\`${p.component}\`) are not yet supported without enabling \`experimental.componentIslands\`.`, fix: "Set `experimental.componentIslands` to `true` in your `nuxt.config`.", docs: false }, NUXT_B3004: { why: (p) => `\`${p.file}\` is using \`${p.component}\` which requires \`${p.requiredModule}\`.`, fix: (p) => `Run \`npx nuxt add ${p.requiredModule}\` to install it.`, docs: false }, NUXT_B3005: { why: (p) => `Multiple hydration strategies are not supported in the same component \`<${p.component}>\` in \`${p.file}\`.`, fix: "Use only one hydration strategy attribute (e.g. `hydrate-on-visible` or `hydrate-on-idle`) per component.", docs: false }, NUXT_B3006: { why: (p) => `Component \`<${p.component}>\` (used in \`${p.file}\`) has lazy-hydration props but is not declared as a lazy component.`, fix: (p) => `Rename it to \`<${p.lazyName} />\` or remove the lazy-hydration props.`, docs: false }, NUXT_B3007: { why: (p) => `Using the \`nuxt-client\` attribute (in \`${p.file}\`) to render client components within islands requires \`experimental.componentIslands.selectiveClient\` to be enabled.`, fix: "Set `experimental.componentIslands.selectiveClient` to `true` in your `nuxt.config`.", docs: false }, NUXT_B3008: { why: (p) => `Components not scanned from \`${p.scannedPath}\`, likely due to a directory casing mismatch.`, fix: (p) => `Rename the directory from \`${p.scannedPath}\` to \`${p.expectedPath}\` to match the expected casing.`, docs: false }, NUXT_B3009: { why: (p) => `The component \`${p.component}\` (in \`${p.filePath}\`) is using the reserved "Lazy" prefix used for dynamic imports, which may cause it to break at runtime.`, fix: "Rename the component to avoid the `Lazy` prefix.", docs: false }, NUXT_B3010: { why: (p) => `Component did not resolve to a file name in \`${p.filePath}\`.`, fix: "Rename the component file to something other than `index` (e.g. `MyComponent.vue`).", docs: false }, NUXT_B3011: { why: (p) => `Two component files resolving to the same name \`${p.component}\`:\n\n - ${p.filePath}\n - ${p.duplicatePath}`, fix: "Rename one of the files or adjust the `components.dirs` prefix settings in your `nuxt.config`.", docs: false }, NUXT_B3012: { why: (p) => `Overriding ${p.name} component.`, fix: "Specify a `priority` option when calling `addComponent` to avoid this warning.", docs: false }, NUXT_B3013: { why: (p) => `Rendering client components within islands via the \`nuxt-client\` attribute (in \`${p.file}\`) is only supported with the Vite builder.`, fix: "Switch to the Vite builder with `builder: 'vite'` in your `nuxt.config`.", docs: false } } }); //#endregion //#region src/internal/exports.ts /** * Resolve the names a module exports, following `export * from '...'` re-exports. * * Type-only exports are omitted; a default export is returned as `default`. * * @internal */ async function resolveModuleExportNames(id, options = {}) { const parser = await loadParser(); if ("resolveModuleExportNames" in parser) return parser.resolveModuleExportNames(id, options); const names = /* @__PURE__ */ new Set(); await collectExportNames(parser.parseSync, id, options, names, /* @__PURE__ */ new Set()); return [...names]; } async function collectExportNames(parseSync, id, options, names, seen) { const path = resolveModulePath(id, { from: options.url ?? [import.meta.url], extensions: options.extensions, try: true }); if (!path || seen.has(path)) return; seen.add(path); const { module } = parseSync(path, await readFile(path, "utf8")); const starExports = []; for (const statement of module.staticExports) for (const entry of statement.entries) { if (entry.isType) continue; if (entry.exportName.kind === "Default") names.add("default"); else if (entry.exportName.kind === "Name" && entry.exportName.name) names.add(entry.exportName.name); else if (entry.importName.kind === "AllButDefault" && entry.moduleRequest) starExports.push(entry.moduleRequest.value); } const url = pathToFileURL(path); for (const specifier of starExports) await collectExportNames(parseSync, specifier, { ...options, url }, names, seen); } /** * Packages able to list a module's exports, in order of preference. `rolldown/utils` re-exports * `oxc-parser`'s parser, so `nuxt` has shipped one of the two since v3.16; `mlly` covers the * versions before that, where it is a direct dependency of `nuxt`. */ const PARSER_SPECIFIERS = [ "rolldown/utils", "oxc-parser", "mlly" ]; let parser; /** * Load the first of {@link PARSER_SPECIFIERS} that can be resolved. * * All of them are optional peer dependencies of `@nuxt/kit`, so if none is visible to kit itself * we look them up from the `nuxt` installation the project resolves to, and then from its root. */ async function loadParser() { if (parser) return parser; const rootDir = tryUseNuxt()?.options.rootDir; const rootURL = rootDir ? directoryToURL(rootDir) : void 0; const from = [rootURL && resolveModuleURL("nuxt", { from: rootURL, try: true }), rootURL].filter((v) => !!v); for (const specifier of PARSER_SPECIFIERS) { const path = from.length ? resolveModulePath(specifier, { from, try: true }) : void 0; try { parser = await (path ? import(pathToFileURL(path).href) : import(specifier)); return parser; } catch {} } throw kitDiagnostics.NUXT_B8022({ specifiers: PARSER_SPECIFIERS.join("` or `") }); } //#endregion //#region src/diagnostics/pages.ts /** * B4xxx * Pages / routing diagnostics. * * @internal */ const pageDiagnostics = /* #__PURE__ */ defineDiagnostics({ docsBase, reporters, codes: { NUXT_B4001: { why: (p) => `The file \`${p.pathname}\` is empty, so it cannot be a valid page.`, fix: "Add a `