import { $ as findPath, A as getAddDependencyCommand, B as hasNuxtCompatibility, C as resolveModuleWithOptions, Ct as useNuxt, D as shouldReportJitiFallbackOnce, Dt as DEFAULT_JSX_FILE_EXTENSIONS$1, E as loadJiti, F as useLogger, G as directoryToURL, H as isNuxt3, I as assertNuxtCompatibility, J as resolveModule, K as importModule, L as checkNuxtCompatibility, N as useTerminal, O as ensureDependencyInstalled, Ot as DEFAULT_JS_FILE_EXTENSIONS$1, P as logger, Q as createResolver, R as getNitroVersion, S as normalizeModuleTranspilePath, St as tryUseNuxt, T as isLoaderError, U as isNuxtMajorVersion, V as isNuxt2, W as normalizeSemanticVersion, X as tryRequireModule, Y as tryImportModule, Z as tryResolveModule, _ as useNitro, _t as readPackageJSON, a as addDevServerHandler, at as distDirURL, bt as nuxtCtx, c as addServerHandler, ct as createIsIgnored, d as addServerPlugin, dt as getLayerDirectories, et as resolveAlias, f as addServerScanDir, g as tryUseNitro, h as resolveServerVariant, ht as interopDefault, i as componentDiagnostics, it as MODE_RE, j as configDiagnostics, l as addServerImports, lt as isIgnored, mt as warn, n as pageDiagnostics, nt as resolveNuxtModule, o as addNitroPlugin, ot as filterInPlace, pt as getUserCaller, q as requireModule, r as resolveModuleExportNames, rt as resolvePath, s as addPrerenderRoutes, st as toArray, t as pluginDiagnostics, tt as resolveFiles, u as addServerImportsDir, ut as resolveIgnorePatterns, v as getDirectory, vt as resolvePackageDir, w as getMissingCjsGlobal, wt as kitDiagnostics, x as loadNuxtModuleInstance, xt as runWithNuxtContext, y as installModule, yt as getNuxtCtx, z as getNuxtVersion } from "./plugins-DPmL7lze.mjs"; import { createDefu, defu } from "defu"; import { kebabCase, pascalCase, snakeCase } from "scule"; import process$1 from "node:process"; import { existsSync, promises, readFileSync, realpathSync, statSync } from "node:fs"; import { isGreaterThanOrEqual, satisfies } from "verkit"; import { readFile, rm, stat } from "node:fs/promises"; import { fileURLToPath, pathToFileURL } from "node:url"; import { basename, dirname, extname, isAbsolute, join, normalize, parse, relative, resolve } from "pathe"; import { resolveModulePath, resolveModuleURL } from "exsolve"; import { captureStackTrace } from "errx"; import { glob } from "tinyglobby"; import { reverseResolveAlias } from "pathe/utils"; import * as rc9 from "rc9"; import * as nodeUtil from "node:util"; import { homedir } from "node:os"; import { klona } from "klona"; import microdiff from "microdiff"; import destr from "destr"; import { createHash } from "node:crypto"; import { isAbsolute as isAbsolute$1, join as join$1, resolve as resolve$1 } from "node:path"; //#region ../../node_modules/.pnpm/untyped@2.0.0/node_modules/untyped/dist/shared/untyped.Br_uXjZG.mjs function getType(val) { const type = typeof val; if (type === "undefined" || val === null) return; if (Array.isArray(val)) return "array"; return type; } function isObject(val) { return val !== null && !Array.isArray(val) && typeof val === "object"; } function nonEmpty(arr) { return arr.filter(Boolean); } function unique(arr) { return [...new Set(arr)]; } function joinPath(a, b = "", sep = ".") { return a ? a + sep + b : b; } function setValue(obj, path, val) { const keys = path.split("."); const _key = keys.pop(); for (const key of keys) { if (!obj || typeof obj !== "object") return; if (!(key in obj)) obj[key] = {}; obj = obj[key]; } if (_key) { if (!obj || typeof obj !== "object") return; obj[_key] = val; } } function getValue(obj, path) { for (const key of path.split(".")) { if (!obj || typeof obj !== "object" || !(key in obj)) return; obj = obj[key]; } return obj; } //#endregion //#region ../../node_modules/.pnpm/untyped@2.0.0/node_modules/untyped/dist/shared/untyped.BTwOq8Jl.mjs async function resolveSchema(obj, defaults, options = {}) { return await _resolveSchema(obj, "", { root: obj, defaults, resolveCache: {}, ignoreDefaults: !!options.ignoreDefaults }); } async function _resolveSchema(input, id, ctx) { if (id in ctx.resolveCache) return ctx.resolveCache[id]; const schemaId = "#" + id.replace(/\./g, "/"); if (!isObject(input)) { const safeInput = Array.isArray(input) ? [...input] : input; const schema2 = { type: getType(input), id: schemaId, default: ctx.ignoreDefaults ? void 0 : safeInput }; normalizeSchema(schema2, { ignoreDefaults: ctx.ignoreDefaults }); ctx.resolveCache[id] = schema2; if (ctx.defaults && getValue(ctx.defaults, id) === void 0) setValue(ctx.defaults, id, schema2.default); return schema2; } const node = { ...input }; const schema = ctx.resolveCache[id] = { ...node.$schema, id: schemaId }; for (const key in node) { if (key === "$resolve" || key === "$schema" || key === "$default") continue; schema.properties = schema.properties || {}; if (!schema.properties[key]) { const child = schema.properties[key] = await _resolveSchema(node[key], joinPath(id, key), ctx); if (Array.isArray(child.tags) && child.tags.includes("@required")) { schema.required = schema.required || []; if (!schema.required.includes(key)) schema.required.push(key); } } } if (!ctx.ignoreDefaults) { if (ctx.defaults) schema.default = getValue(ctx.defaults, id); if (schema.default === void 0 && "$default" in node) schema.default = node.$default; if (typeof node.$resolve === "function") schema.default = await node.$resolve(schema.default, async (key) => { return (await _resolveSchema(getValue(ctx.root, key), key, ctx)).default; }); } if (ctx.defaults) setValue(ctx.defaults, id, schema.default); if (!schema.type) schema.type = getType(schema.default) || (schema.properties ? "object" : "any"); normalizeSchema(schema, { ignoreDefaults: ctx.ignoreDefaults }); if (ctx.defaults && getValue(ctx.defaults, id) === void 0) setValue(ctx.defaults, id, schema.default); return schema; } async function applyDefaults(ref, input) { await resolveSchema(ref, input); return input; } function normalizeSchema(schema, options) { if (schema.type === "array" && !("items" in schema)) { schema.items = { type: nonEmpty(unique(schema.default.map((i) => getType(i)))) }; if (schema.items.type) { if (schema.items.type.length === 0) schema.items.type = "any"; else if (schema.items.type.length === 1) schema.items.type = schema.items.type[0]; } } if (!options.ignoreDefaults && schema.default === void 0 && ("properties" in schema || schema.type === "object" || schema.type === "any")) { const propsWithDefaults = Object.entries(schema.properties || {}).filter(([, prop]) => "default" in prop).map(([key, value]) => [key, value.default]); schema.default = Object.fromEntries(propsWithDefaults); } } //#endregion //#region src/module/define.ts function defineNuxtModule(definition) { if (definition) return _defineNuxtModule(definition); return { with: (definition) => _defineNuxtModule(definition) }; } function _defineNuxtModule(definition) { if (typeof definition === "function") return _defineNuxtModule({ setup: definition }); const module = defu(definition, { meta: {} }); module.meta.configKey ||= module.meta.name; async function getOptions(inlineOptions, nuxt = useNuxt()) { const nuxtConfigOptionsKey = module.meta.configKey || module.meta.name; const nuxtConfigOptions = nuxtConfigOptionsKey && nuxtConfigOptionsKey in nuxt.options ? nuxt.options[nuxtConfigOptionsKey] : {}; const optionsDefaults = module.defaults instanceof Function ? await module.defaults(nuxt) : module.defaults ?? {}; let options = defu(inlineOptions, nuxtConfigOptions, optionsDefaults); if (module.schema) options = await applyDefaults(module.schema, options); return Promise.resolve(options); } function getModuleDependencies(nuxt = useNuxt()) { if (typeof module.moduleDependencies === "function") return module.moduleDependencies(nuxt); return module.moduleDependencies; } async function normalizedModule(inlineOptions, nuxt = tryUseNuxt()) { if (!nuxt) throw kitDiagnostics.NUXT_B8012({ name: module.meta.name || "module" }); const uniqueKey = module.meta.name || module.meta.configKey; if (uniqueKey) { nuxt.options._requiredModules ||= {}; if (nuxt.options._requiredModules[uniqueKey]) return false; nuxt.options._requiredModules[uniqueKey] = true; } if (module.meta.compatibility) { const issues = await checkNuxtCompatibility(module.meta.compatibility, nuxt); if (issues.length) { const errorMessage = `Module \`${module.meta.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`; if (nuxt.options.experimental.enforceModuleCompatibility) { const error = new Error(errorMessage); error.name = "ModuleCompatibilityError"; throw error; } kitDiagnostics.NUXT_B8013({ message: errorMessage }); return; } } const _options = await getOptions(inlineOptions, nuxt); if (module.hooks) nuxt.hooks.addHooks(module.hooks); const moduleName = uniqueKey || module.meta.name || ""; nuxt._perf?.startPhase(`module:${moduleName}`); let res; try { res = await module.setup?.call(null, _options, nuxt) ?? {}; } finally { nuxt._perf?.endPhase(`module:${moduleName}`); } if (res === false) return false; return res; } normalizedModule.getMeta = () => Promise.resolve(module.meta); normalizedModule.getOptions = getOptions; normalizedModule.getModuleDependencies = getModuleDependencies; normalizedModule.onInstall = module.onInstall; normalizedModule.onUpgrade = module.onUpgrade; return normalizedModule; } //#endregion //#region src/module/compatibility.ts function resolveNuxtModuleEntryName(m) { if (typeof m === "object" && !Array.isArray(m)) return m.name; if (Array.isArray(m)) return resolveNuxtModuleEntryName(m[0]); return m || false; } /** * Check if a Nuxt module is installed by name. * * This will check both the installed modules and the modules to be installed. Note * that it cannot detect if a module is _going to be_ installed programmatically by another module. */ function hasNuxtModule(moduleName, nuxt = useNuxt()) { return nuxt.options._installedModules.some(({ meta }) => meta.name === moduleName) || nuxt.options.modules.some((m) => moduleName === resolveNuxtModuleEntryName(m)); } /** * Checks if a Nuxt module is compatible with a given semver version. */ async function hasNuxtModuleCompatibility(module, semverVersion, nuxt = useNuxt()) { const version = await getNuxtModuleVersion(module, nuxt); if (!version) return false; return satisfies(normalizeSemanticVersion(version), semverVersion, { includePrerelease: true }); } /** * Get the version of a Nuxt module. * * Scans installed modules for the version, if it's not found it will attempt to load the module instance and get the version from there. */ async function getNuxtModuleVersion(module, nuxt = useNuxt()) { const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {}; if (moduleMeta.version) return moduleMeta.version; if (!moduleMeta.name) return false; for (const m of nuxt.options._installedModules) if (m.meta.name === moduleMeta.name && m.meta.version) return m.meta.version; if (hasNuxtModule(moduleMeta.name)) { const { nuxtModule, buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleMeta.name, nuxt); return buildTimeModuleMeta.version || await nuxtModule.getMeta?.().then((r) => r.version) || false; } return false; } //#endregion //#region ../../node_modules/.pnpm/c12@4.0.0-rc.2_dotenv@18.0.8_giget@3.3.1_jiti@2.7.0_magicast@0.5.5/node_modules/c12/dist/index.mjs async function setupDotenv(options) { const targetEnvironment = options.env ?? process.env; const environment = await loadDotenv({ cwd: options.cwd, fileName: options.fileName ?? ".env", env: targetEnvironment, interpolate: options.interpolate ?? true, expandFileReferences: options.expandFileReferences ?? false, parse: options.parse }); const dotenvVars = getDotEnvVars(targetEnvironment); for (const key in environment) { if (key.startsWith("_")) continue; if (targetEnvironment[key] === void 0 || dotenvVars.has(key)) targetEnvironment[key] = environment[key]; } return environment; } async function loadDotenv(options) { const environment = Object.create(null); const cwd = resolve(options.cwd || "."); const _fileName = options.fileName || ".env"; const dotenvFiles = typeof _fileName === "string" ? [_fileName] : _fileName; const dotenvVars = getDotEnvVars(options.env || {}); Object.assign(environment, options.env); for (const file of dotenvFiles) { const dotenvFile = resolve(cwd, file); if (!statSync(dotenvFile, { throwIfNoEntry: false })?.isFile()) continue; const parsed = await readEnvFile(dotenvFile, options.parse); for (const key in parsed) { if (key in environment && !dotenvVars.has(key)) continue; environment[key] = parsed[key]; dotenvVars.add(key); } } if (options.expandFileReferences) { for (const key in environment) if (key.endsWith("_FILE")) { const targetKey = key.slice(0, -5); if (environment[targetKey] === void 0) { const filePath = environment[key]; if (filePath && statSync(filePath, { throwIfNoEntry: false })?.isFile()) { environment[targetKey] = readFileSync(filePath, "utf8").trim(); dotenvVars.add(targetKey); } } } } if (options.interpolate) interpolate(environment); return environment; } let _parseEnv = nodeUtil.parseEnv; async function readEnvFile(path, parse) { const src = readFileSync(path, "utf8"); if (parse) return parse(src); if (!_parseEnv) try { const dotenv = await import("dotenv"); _parseEnv = (src) => dotenv.parse(src); } catch { throw new Error("Failed to parse .env file: `node:util.parseEnv` is not available and `dotenv` package is not installed. Please upgrade your runtime, install `dotenv` as a dependency or provide a custom `parse` option."); } return _parseEnv(src); } function interpolate(target, source = {}, parse = (v) => v) { function getValue(key) { return source[key] === void 0 ? target[key] : source[key]; } function interpolate(value, parents = []) { if (typeof value !== "string") return value; let result = ""; let index = 0; while (index < value.length) { const char = value[index]; if (char === "\\" && value[index + 1] === "$") { result += "$"; index += 2; continue; } const ref = char === "$" ? parseRef(value, index) : void 0; if (!ref) { result += char; index++; continue; } if (parents.includes(ref.key)) { if (ref.defaultValue !== void 0) { result += interpolate(ref.defaultValue, parents); index = ref.end; continue; } console.warn(`Please avoid recursive environment variables ( loop: ${parents.join(" > ")} > ${ref.key} )`); return ""; } let resolved = interpolate(getValue(ref.key), [...parents, ref.key]); if (ref.defaultValue !== void 0 && (resolved === void 0 || ref.operator === ":-" && resolved === "")) resolved = interpolate(ref.defaultValue, parents); result += resolved === void 0 ? value.slice(index, ref.end) : resolved; index = ref.end; } return parse(result); } for (const key in target) target[key] = interpolate(getValue(key)); } const REF_NAME_RE = /\w+/y; const BRACED_REF_NAME_RE = /[\w:]+/y; function parseRef(input, start) { let index = start + 1; const braced = input[index] === "{"; if (braced) index++; const nameRe = braced ? BRACED_REF_NAME_RE : REF_NAME_RE; nameRe.lastIndex = index; const name = nameRe.exec(input); if (!name) return; let key = name[0]; index = nameRe.lastIndex; if (!braced) return { key, end: index }; if (input[index] === "}") return { key, end: index + 1 }; if (input[index] === "-") { let operator = "-"; if (key.endsWith(":")) { key = key.slice(0, -1); operator = ":-"; } const defaultValue = key ? readDefault(input, index + 1) : void 0; if (!defaultValue) return; return { key, operator, defaultValue: defaultValue.value, end: defaultValue.end }; } return { key, end: index }; } function readDefault(input, start) { let value = ""; let depth = 1; for (let index = start; index < input.length; index++) { const char = input[index]; if (char === "\\" && index + 1 < input.length) { const next = input[index + 1]; value += next === "{" || next === "}" ? next : char + next; index++; continue; } if (char === "$" && input[index + 1] === "{") { depth++; value += "${"; index++; continue; } if (char === "{") depth++; if (char === "}") { depth--; if (depth === 0) return { value, end: index + 1 }; } value += char; } } function getDotEnvVars(targetEnvironment) { const globalRegistry = globalThis.__c12_dotenv_vars__ ||= /* @__PURE__ */ new Map(); if (!globalRegistry.has(targetEnvironment)) globalRegistry.set(targetEnvironment, /* @__PURE__ */ new Set()); return globalRegistry.get(targetEnvironment); } const _normalize = (p) => p?.replace(/\\/g, "/"); let importCounter = 0; const ASYNC_LOADERS = { ".json": () => JSON.parse, ".yaml": () => import("confbox/yaml").then((r) => r.parseYAML), ".yml": () => import("confbox/yaml").then((r) => r.parseYAML), ".jsonc": () => import("confbox/jsonc").then((r) => (source) => r.parseJSONC(source, { allowTrailingComma: true })), ".json5": () => import("confbox/json5").then((r) => r.parseJSON5), ".toml": () => import("confbox/toml").then((r) => r.parseTOML) }; const SUPPORTED_EXTENSIONS = Object.freeze([ ".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".json5", ".yaml", ".yml", ".toml" ]); async function loadConfig(options) { options.cwd = resolve(process.cwd(), options.cwd || "."); options.name = options.name || "config"; options.envName = options.envName ?? process.env.NODE_ENV; options.configFile = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`); options.rcFile = options.rcFile ?? `.${options.name}rc`; if (options.extend !== false) options.extend = { extendKey: "extends", ...options.extend }; const _merger = options.merger || defu; const r = { config: {}, cwd: options.cwd, configFile: resolve(options.cwd, options.configFile), layers: [], _configFile: void 0 }; const rawConfigs = { overrides: options.overrides, main: void 0, rc: void 0, packageJson: void 0, defaultConfig: options.defaultConfig }; if (options.dotenv) await setupDotenv({ cwd: options.cwd, ...options.dotenv === true ? {} : options.dotenv }); const _mainConfig = await resolveConfig(".", options); if (_mainConfig.configFile) { rawConfigs.main = _mainConfig.config; r.configFile = _mainConfig.configFile; r._configFile = _mainConfig._configFile; } if (_mainConfig.meta) r.meta = _mainConfig.meta; if (options.rcFile) { const rcSources = []; rcSources.push(rc9.read({ name: options.rcFile, dir: options.cwd })); if (options.globalRc) { const { findWorkspaceDir } = await import("./plugins-DPmL7lze.mjs").then((n) => n.gt); const workspaceDir = await findWorkspaceDir(options.cwd).catch(() => {}); if (workspaceDir) rcSources.push(rc9.read({ name: options.rcFile, dir: workspaceDir })); rcSources.push(rc9.readUserConfig({ name: options.rcFile })); rcSources.push(rc9.read({ name: options.rcFile, dir: homedir() })); } rawConfigs.rc = _merger({}, ...rcSources); } if (options.packageJson) { const keys = (Array.isArray(options.packageJson) ? options.packageJson : [typeof options.packageJson === "string" ? options.packageJson : options.name]).filter((t) => t && typeof t === "string"); const { readPackageJSON } = await import("./plugins-DPmL7lze.mjs").then((n) => n.gt); const pkgJsonFile = await readPackageJSON(options.cwd).catch(() => {}); rawConfigs.packageJson = _merger({}, ...keys.map((key) => pkgJsonFile?.[key])); } const configs = {}; for (const key in rawConfigs) { const value = rawConfigs[key]; configs[key] = await (typeof value === "function" ? value({ configs, rawConfigs }) : value); } if (Array.isArray(configs.main)) r.config = configs.main; else { r.config = _merger(configs.overrides, configs.main, configs.rc, configs.packageJson, configs.defaultConfig); if (options.extend) { await extendConfig(r.config, options); r.layers = r.config._layers; delete r.config._layers; r.config = _merger(r.config, ...r.layers.map((e) => e.config)); } } r.layers = [...[ configs.overrides && { config: configs.overrides, configFile: void 0, cwd: void 0 }, { config: configs.main, configFile: options.configFile, cwd: options.cwd }, configs.rc && { config: configs.rc, configFile: options.rcFile }, configs.packageJson && { config: configs.packageJson, configFile: "package.json" } ].filter((l) => l && l.config), ...r.layers]; if (options.defaults) r.config = _merger(r.config, options.defaults); if (options.omit$Keys) { for (const key in r.config) if (key.startsWith("$")) delete r.config[key]; } if (options.configFileRequired && !r._configFile) throw new Error(`Required config (${r.configFile}) cannot be resolved.`); if (options.schema != null) r.config = await validateConfig(r.config, options.schema); return r; } async function extendConfig(config, options) { config._layers = config._layers || []; if (!options.extend) return; let keys = options.extend.extendKey; if (typeof keys === "string") keys = [keys]; const extendSources = []; for (const key of keys) { extendSources.push(...(Array.isArray(config[key]) ? config[key] : [config[key]]).filter(Boolean)); delete config[key]; } for (let extendSource of extendSources) { const originalExtendSource = extendSource; let sourceOptions = {}; if (extendSource.source) { sourceOptions = extendSource.options || {}; extendSource = extendSource.source; } if (Array.isArray(extendSource)) { sourceOptions = extendSource[1] || {}; extendSource = extendSource[0]; } if (typeof extendSource !== "string") { console.warn(`Cannot extend config from \`${JSON.stringify(originalExtendSource)}\` in ${options.cwd}`); continue; } const _config = await resolveConfig(extendSource, options, sourceOptions); if (!_config.config) { console.warn(`Cannot extend config from \`${extendSource}\` in ${options.cwd}`); continue; } await extendConfig(_config.config, { ...options, cwd: _config.cwd }); config._layers.push(_config); if (_config.config._layers) { config._layers.push(..._config.config._layers); delete _config.config._layers; } } } const GIGET_PREFIXES = [ "gh:", "github:", "gitlab:", "bitbucket:", "https://", "http://" ]; const NPM_PACKAGE_RE = /^(@[\da-z~-][\d._a-z~-]*\/)?[\da-z~-][\d._a-z~-]*($|\/.*)/; async function resolveConfig(source, options, sourceOptions = {}) { if (options.resolve) { const res = await options.resolve(source, options); if (res) return res; } const _merger = options.merger || defu; const customProviderKeys = Object.keys(sourceOptions.giget?.providers || {}).map((key) => `${key}:`); const gigetPrefixes = customProviderKeys.length > 0 ? [.../* @__PURE__ */ new Set([...customProviderKeys, ...GIGET_PREFIXES])] : GIGET_PREFIXES; if (options.giget !== false && gigetPrefixes.some((prefix) => source.startsWith(prefix))) { const { downloadTemplate } = await import("giget").catch((error) => { throw new Error(`Extending config from \`${source}\` requires \`giget\` peer dependency to be installed.\n\nInstall it with: \`npx nypm i giget\``, { cause: error }); }); const { digest } = await import("./ohash-G6meS8mS.mjs").then((n) => n.dist_exports); const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, ""); let cloneDir; const localNodeModules = resolve(options.cwd, "node_modules"); const parentDir = dirname(options.cwd); if (basename(parentDir) === ".c12") cloneDir = join(parentDir, cloneName); else if (existsSync(localNodeModules)) cloneDir = join(localNodeModules, ".c12", cloneName); else cloneDir = process.env.XDG_CACHE_HOME ? resolve(process.env.XDG_CACHE_HOME, "c12", cloneName) : resolve(homedir(), ".cache/c12", cloneName); const install = sourceOptions.install ? defu(sourceOptions.install === true ? {} : sourceOptions.install, { ignoreWorkspace: true }) : false; if (existsSync(cloneDir) && !install) await rm(cloneDir, { recursive: true }); source = (await downloadTemplate(source, { dir: cloneDir, install, force: Boolean(install), auth: sourceOptions.auth, ...options.giget, ...sourceOptions.giget })).dir; } if (NPM_PACKAGE_RE.test(source)) source = tryResolve(source, options) || source; const ext = extname(source); const isDir = _isDirectory(resolve(options.cwd, source)) ?? (!ext || ext === basename(source)); const cwd = resolve(options.cwd, isDir ? source : dirname(source)); if (isDir) source = options.configFile; const res = { config: void 0, configFile: void 0, cwd, source, sourceOptions }; res.configFile = tryResolve(resolve(cwd, source), options) || tryResolve(resolve(cwd, ".config", source.replace(/\.config$/, "")), options) || tryResolve(resolve(cwd, ".config", source), options) || source; if (!existsSync(res.configFile)) return res; res._configFile = res.configFile; const configFileExt = extname(res.configFile) || ""; if (configFileExt in ASYNC_LOADERS) res.config = (await ASYNC_LOADERS[configFileExt]())(await readFile(res.configFile, "utf8")); else { const _resolveModule = options.resolveModule || ((mod) => mod.default || mod); if (options.import) res.config = _resolveModule(await options.import(res.configFile)); else { const _configURL = pathToFileURL(res.configFile); _configURL.search = `_${++importCounter}`; res.config = await import(_configURL.href).then(_resolveModule, async (error) => { const { createJiti } = await import("jiti").catch(() => { throw new Error(`Failed to load config file \`${res.configFile}\`: ${error?.message}. Hint install \`jiti\` for compatibility.`, { cause: error }); }); const jiti = createJiti(join(options.cwd || ".", options.configFile || "/"), { interopDefault: true, moduleCache: false, extensions: [...SUPPORTED_EXTENSIONS], ...options.jitiOptions }); options.import = (id) => jiti.import(id); return _resolveModule(await options.import(res.configFile)); }); } } if (typeof res.config === "function") res.config = await res.config(options.context); if (res.config && typeof res.config === "object" && !Array.isArray(res.config) && !Object.isExtensible(res.config)) res.config = { ...res.config }; const envConfigs = (Array.isArray(options.envName) ? options.envName : [options.envName]).filter(Boolean).reverse().flatMap((envName) => [res.config.$env?.[envName], res.config["$" + envName]]).filter((c) => c && Object.keys(c).length > 0); if (envConfigs.length > 0) res.config = (options.envMerger || _merger)({}, ...envConfigs, res.config); res.meta = defu(res.sourceOptions.meta, res.config.$meta); delete res.config.$meta; if (res.sourceOptions.overrides) res.config = _merger(res.sourceOptions.overrides, res.config); res.configFile = _normalize(res.configFile); res.source = _normalize(res.source); return res; } async function validateConfig(config, schema) { if (typeof schema?.["~standard"]?.validate !== "function") throw new TypeError("Invalid `schema` option: expected a Standard Schema (https://standardschema.dev)."); const result = await schema["~standard"].validate(config); if (result.issues) { const messages = result.issues.map((issue) => { const path = issue.path?.map((p) => String(typeof p === "object" ? p.key : p)).join("."); return ` - ${path ? `${path}: ` : ""}${issue.message}`; }); throw new Error(`Config validation failed (${schema["~standard"].vendor}):\n${messages.join("\n")}`, { cause: result.issues }); } return result.value; } function tryResolve(id, options) { const res = resolveModulePath(id, { try: true, from: pathToFileURL(join(options.cwd || ".", options.configFile || "/")), suffixes: ["", "/index"], extensions: SUPPORTED_EXTENSIONS, cache: false }); return res ? normalize(res) : void 0; } function _isDirectory(path) { try { return statSync(path).isDirectory(); } catch { return null; } } //#endregion //#region src/loader/config.ts const IDENTIFIER_RE = /^[a-z_$][\w$]*$/i; function formatLabel(path) { let label = ""; for (const segment of path) if (typeof segment === "number") label += `[${segment}]`; else if (IDENTIFIER_RE.test(segment)) label += label ? `.${segment}` : segment; else label += `[${JSON.stringify(segment)}]`; return label; } /** * Compare two `rawConfig` snapshots (as provided to `onConfigResolved`) and return the * differences between them. */ function diffNuxtConfig(oldConfig, newConfig) { const entries = []; for (const entry of microdiff(oldConfig, newConfig)) { const location = { path: entry.path, label: formatLabel(entry.path) }; switch (entry.type) { case "CREATE": entries.push({ ...location, type: "added", newValue: entry.value }); break; case "REMOVE": entries.push({ ...location, type: "removed", oldValue: entry.oldValue }); break; case "CHANGE": if (!isSameFunction(entry.oldValue, entry.value)) entries.push({ ...location, type: "changed", newValue: entry.value, oldValue: entry.oldValue }); } } return entries; } function isSameFunction(a, b) { return typeof a === "function" && typeof b === "function" && a.toString() === b.toString(); } const CONFIG_EXTENSIONS = [ ".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".json5", ".yaml", ".yml", ".toml" ]; let configImportCounter = 0; const REMOTE_SOURCE_RE = /^(?:gh|github|gitlab|bitbucket):|^https?:\/\//; /** * Check that a remote `extends` source can actually be downloaded, and explain the alternative if * not. `giget` is an optional peer dependency: most projects are better off adding the layer to * `package.json` with a git URL, which pins it and records it in the lockfile. */ async function assertRemoteLayerSupport(source, rootDir) { if (!await import("giget").then(() => true, () => false)) throw configDiagnostics.NUXT_B5018({ source, installCommand: await getAddDependencyCommand("giget", rootDir, { dev: true }) }); } /** * Whether a config load failed because `confbox` is not installed. It is an optional peer * dependency, needed only to parse a `nuxt.config` written in yaml, toml, jsonc or json5. */ function isMissingConfbox(error) { const { code, message } = error ?? {}; return code === "ERR_MODULE_NOT_FOUND" && typeof message === "string" && message.includes(`'confbox`); } const merger = createDefu((obj, key, value) => { if (Array.isArray(obj[key]) && Array.isArray(value)) { obj[key] = obj[key].concat(value); return true; } }); async function loadNuxtConfig(opts) { const rootCwd = resolve(opts.cwd || process$1.cwd()); const configFileName = opts.configFile || "nuxt.config"; const localLayers = (await glob("layers/*", { onlyDirectories: true, cwd: rootCwd })).map((d) => withTrailingSlash$1(d)).sort((a, b) => b.localeCompare(a)); opts.overrides = defu(opts.overrides, { _extends: localLayers }); const autoScanSources = new Set(localLayers); const localLayerDirs = new Set(localLayers.map((dir) => canonicalLayerDir(resolve(rootCwd, dir.replace(/\/$/, ""))))); const extendsLocalLayerOrder = []; if (opts.dotenv !== false) await setupDotenv({ cwd: opts.cwd || process$1.cwd(), ...typeof opts.dotenv === "object" ? opts.dotenv : {} }); const schemaPromise = loadNuxtSchema(opts.cwd || process$1.cwd()); const seenLayerDirs = /* @__PURE__ */ new Set(); let jitiPromise; const getJiti = async (install) => { jitiPromise ??= loadJiti({ rootDir: rootCwd, install }).then((mod) => mod?.createJiti(join(rootCwd, configFileName), { interopDefault: true, moduleCache: false, extensions: [...CONFIG_EXTENSIONS] })); const jiti = await jitiPromise; if (!jiti && !install) jitiPromise = void 0; return jiti; }; let jitiImporter; const jitiFallbacks = []; const importConfigFile = async (id) => { if (jitiImporter) return jitiImporter(id); const url = pathToFileURL(id); url.search = `_${++configImportCounter}`; try { return await import(url.href); } catch (error) { const missingGlobal = getMissingCjsGlobal(error); const jitiCanHelp = isLoaderError(error) || !!missingGlobal; const jiti = await getJiti(jitiCanHelp); if (!jiti) { if (!jitiCanHelp) throw error; throw (missingGlobal ? configDiagnostics.NUXT_B5021 : configDiagnostics.NUXT_B5017)({ filePath: id, error: error instanceof Error ? error.message : String(error), installCommand: await getAddDependencyCommand("jiti", rootCwd, { dev: true }), cause: error }); } let loaded; try { loaded = await jiti.import(id); } catch (jitiError) { const repeated = missingGlobal && getMissingCjsGlobal(jitiError) === missingGlobal; throw jitiCanHelp && !repeated ? jitiError : error; } jitiFallbacks.push({ filePath: id, error: error instanceof Error ? error.message : String(error) }); if (isLoaderError(error)) jitiImporter = (id) => jiti.import(id); return loaded; } }; const loadRootConfig = () => withDefineNuxtConfig(() => loadConfig({ name: "nuxt", configFile: configFileName, rcFile: opts.rcFile ?? ".nuxtrc", extend: { extendKey: [ "theme", "_extends", "extends" ] }, globalRc: opts.globalRc ?? true, merger, cwd: opts.cwd, overrides: opts.overrides, defaults: opts.defaults, envName: opts.envName, import: opts.import ?? importConfigFile, dotenv: false, async resolve(source, resolveOptions) { const custom = await opts.resolve?.(source, resolveOptions); if (custom) return custom; if (typeof source !== "string") return; if (REMOTE_SOURCE_RE.test(source)) await assertRemoteLayerSupport(source, rootCwd); const base = resolveOptions.cwd ? resolve(resolveOptions.cwd) : rootCwd; const aliased = resolveLayerExtendsAlias(source, rootCwd); const path = aliased ?? resolve(base, source); if (!existsSync(path)) return; const layerDir = canonicalLayerDir(path); if (base === rootCwd && !autoScanSources.has(source) && localLayerDirs.has(layerDir)) extendsLocalLayerOrder.push(layerDir); if (seenLayerDirs.has(layerDir)) return { config: {}, cwd: layerDir, source }; seenLayerDirs.add(layerDir); if (aliased) { const layer = await loadConfig({ cwd: aliased, name: "nuxt", configFile: configFileName, rcFile: false, extend: false, import: resolveOptions.import }); return layer.configFile ? { config: layer.config, configFile: layer.configFile, cwd: aliased, source: aliased, meta: layer.meta } : { config: {}, cwd: aliased, source }; } } })); const resolved = await loadRootConfig().catch(async (error) => { if (!isMissingConfbox(error)) throw error; if (!await ensureDependencyInstalled("confbox", { rootDir: rootCwd, from: import.meta.url })) throw configDiagnostics.NUXT_B5022({ installCommand: await getAddDependencyCommand("confbox", rootCwd, { dev: true }), cause: error }); seenLayerDirs.clear(); extendsLocalLayerOrder.length = 0; return loadRootConfig(); }); const { configFile, layers = [], cwd, meta } = resolved; const nuxtConfig = klona(resolved.config); const rawConfig = opts.onConfigResolved ? merger({}, ...layers.filter((layer) => layer.config && layer.config !== opts.overrides).map((layer) => layer.config)) : void 0; nuxtConfig.rootDir ||= cwd; nuxtConfig._nuxtConfigFile = configFile; nuxtConfig._nuxtConfigFiles = [configFile]; nuxtConfig._loadOptions = opts; if (typeof opts.envName === "string") nuxtConfig.envName = opts.envName; nuxtConfig.alias ||= {}; if (meta?.name) { const alias = `#layers/${meta.name}`; nuxtConfig.alias[alias] ||= withTrailingSlash$1(nuxtConfig.rootDir); } const defaultBuildDir = join(nuxtConfig.rootDir, ".nuxt"); nuxtConfig.typesDir ||= opts.overrides?.buildDir ? layers.find((l) => l.config?.buildDir && l.config.buildDir !== opts.overrides?.buildDir)?.config?.buildDir || defaultBuildDir : nuxtConfig.buildDir || defaultBuildDir; if (!opts.overrides?._prepare && !nuxtConfig.dev && !nuxtConfig.buildDir && existsSync(defaultBuildDir)) nuxtConfig.buildDir = join(nuxtConfig.rootDir, "node_modules/.cache/nuxt/.nuxt"); const NuxtConfigSchema = await schemaPromise; const layerSchemaKeys = [ "future", "srcDir", "rootDir", "serverDir", "dir" ]; const layerSchema = Object.create(null); for (const key of layerSchemaKeys) if (key in NuxtConfigSchema) layerSchema[key] = NuxtConfigSchema[key]; const _layers = []; const processedLayers = /* @__PURE__ */ new Set(); const localRelativePaths = new Set(localLayers.map((layer) => layer.replace(/\/$/, ""))); for (const layer of layers) { const layerCwd = layer.cwd; if (layer.cwd && layer.cwd !== cwd) { layer.cwd = tryRealPath(layer.cwd); layer.configFile &&= tryRealPath(layer.configFile); } const resolvedRootDir = layer.config?.rootDir ?? layer.cwd; layer.config = { ...layer.config || {}, rootDir: resolvedRootDir }; if (processedLayers.has(resolvedRootDir)) continue; processedLayers.add(resolvedRootDir); layer.config = await applyDefaults(layerSchema, layer.config); if (!layer.configFile || layer.configFile.endsWith(".nuxtrc")) continue; if (layerCwd && cwd && localRelativePaths.has(relative(cwd, layerCwd))) { layer.meta ||= {}; layer.meta.name ||= basename(layerCwd); } if (layer.meta?.name) { const alias = `#layers/${layer.meta.name}`; nuxtConfig.alias[alias] ||= withTrailingSlash$1(layer.config.rootDir || layer.cwd); } _layers.push(layer); } if (extendsLocalLayerOrder.length) reorderLocalLayersByExtends(_layers, extendsLocalLayerOrder, localLayerDirs); nuxtConfig._layers = _layers; if (!_layers.length) _layers.push({ cwd, config: { rootDir: cwd, srcDir: cwd } }); const options = await applyDefaults(NuxtConfigSchema, nuxtConfig); for (const fallback of jitiFallbacks) if (shouldReportJitiFallbackOnce(fallback.filePath, options.rootDir, options.future.compatibilityVersion)) configDiagnostics.NUXT_B5023(fallback); if (opts.onConfigResolved) await opts.onConfigResolved({ rawConfig, layers: _layers, configFile, cwd }); return options; } /** * Canonicalise a filesystem path to a layer directory: config-file paths collapse to their * directory and symlinks resolve to their target, so different spellings of the same layer * share one identity. The path must exist. */ function canonicalLayerDir(path) { return normalize(realpathSync(statSync(path).isDirectory() ? path : dirname(path))); } function tryRealPath(path) { try { return normalize(realpathSync(path)); } catch { return path; } } function withTrailingSlash$1(path) { if (!path) return "/"; return path.endsWith("/") ? path : `${path}/`; } const LAYER_EXTENDS_ALIASES = [ "~~", "@@", "~", "@" ]; /** * Resolve a leading `~`, `~~`, `@` or `@@` alias in an `extends` source to an absolute path. * Local layers live at the project root, so every alias resolves against `rootDir`. Returns * `undefined` when the source is not alias-prefixed. */ function resolveLayerExtendsAlias(source, rootDir) { for (const alias of LAYER_EXTENDS_ALIASES) { if (source === alias) return rootDir; if (source.startsWith(`${alias}/`)) return join(rootDir, source.slice(alias.length + 1)); } } /** * Reorder local layers (from the `~~/layers/` directory) in place to match the order they are * listed in `extends` (first entry = highest priority). Listed layers come first in that order; * unlisted local layers keep their existing alphabetical order after them. Non-local layers keep * their positions. */ function reorderLocalLayersByExtends(layers, extendsOrder, localLayerDirs) { const layerDir = (layer) => { const dir = (layer.config?.rootDir ?? layer.cwd ?? "").replace(/\/$/, ""); try { return normalize(realpathSync(dir)); } catch { return normalize(dir); } }; const priorityByDir = new Map(extendsOrder.map((dir, index) => [dir, index])); const localSlots = []; const localLayers = []; for (let index = 0; index < layers.length; index++) if (localLayerDirs.has(layerDir(layers[index]))) { localSlots.push(index); localLayers.push(layers[index]); } const orderedLocalLayers = localLayers.map((layer, index) => ({ layer, index })).sort((a, b) => { return (priorityByDir.get(layerDir(a.layer)) ?? Number.POSITIVE_INFINITY) - (priorityByDir.get(layerDir(b.layer)) ?? Number.POSITIVE_INFINITY) || a.index - b.index; }).map((entry) => entry.layer); localSlots.forEach((slot, index) => { layers[slot] = orderedLocalLayers[index]; }); } function loadNuxtSchema(cwd) { const url = directoryToURL(cwd); const urls = [url]; const nuxtPath = resolveModuleURL("nuxt", { try: true, from: url }) ?? resolveModuleURL("nuxt-nightly", { try: true, from: url }); if (nuxtPath) urls.unshift(nuxtPath); return import(resolveModuleURL("@nuxt/schema", { try: true, from: urls }) ?? "@nuxt/schema").then((r) => r.NuxtConfigSchema); } async function withDefineNuxtConfig(fn) { const key = "defineNuxtConfig"; const globalSelf = globalThis; if (!globalSelf[key]) { globalSelf[key] = (c) => c; globalSelf[key].count = 0; } globalSelf[key].count++; try { return await fn(); } finally { globalSelf[key].count--; if (!globalSelf[key].count) delete globalSelf[key]; } } //#endregion //#region src/loader/schema.ts function extendNuxtSchema(def) { useNuxt().hook("schema:extend", (schemas) => { schemas.push(typeof def === "function" ? def() : def); }); } //#endregion //#region src/loader/nuxt.ts async function loadNuxt(opts) { opts.cwd = resolve(opts.cwd || opts.rootDir || "."); opts.overrides ||= opts.config || {}; opts.overrides.dev = !!opts.dev; const resolvedPath = ["nuxt-nightly", "nuxt"].reduce((resolvedPath, pkg) => { const path = resolveModulePath(pkg, { try: true, from: [directoryToURL(opts.cwd)] }); return path && path.length > resolvedPath.length ? path : resolvedPath; }, ""); if (!resolvedPath) throw kitDiagnostics.NUXT_B8006({ cwd: opts.cwd, installCommand: await getAddDependencyCommand("nuxt", opts.cwd) }); const { loadNuxt } = await import(pathToFileURL(resolvedPath).href).then((r) => interopDefault(r)); return await loadNuxt(opts); } async function buildNuxt(nuxt) { const rootURL = directoryToURL(nuxt.options.rootDir); const { build } = await tryImportModule("nuxt-nightly", { url: rootURL }) || await importModule("nuxt", { url: rootURL }); return runWithNuxtContext(nuxt, () => build(nuxt)); } //#endregion //#region src/head.ts function setGlobalHead(head) { const nuxt = useNuxt(); nuxt.options.app.head = defu(head, nuxt.options.app.head); } //#endregion //#region src/imports.ts function addImports(imports) { useNuxt().hook("imports:extend", (_imports) => { _imports.push(...toArray(imports)); }); } function addImportsDir(dirs, opts = {}) { useNuxt().hook("imports:dirs", (_dirs) => { for (const dir of toArray(dirs)) _dirs[opts.prepend ? "unshift" : "push"](dir); }); } function addImportsSources(presets) { useNuxt().hook("imports:sources", (_presets) => { for (const preset of toArray(presets)) _presets.push(preset); }); } //#endregion //#region src/app-config.ts /** * Update Nuxt app configuration. * @since 4.5.0 */ function updateAppConfig(appConfig) { const nuxt = useNuxt(); Object.assign(nuxt.options.appConfig, defu(appConfig, nuxt.options.appConfig)); } //#endregion //#region src/runtime-config.ts /** * Access 'resolved' Nuxt runtime configuration, with values updated from environment. * * This mirrors the runtime behavior of Nitro. */ function useRuntimeConfig() { const nuxt = useNuxt(); return applyEnv(klona(nuxt.options.nitro.runtimeConfig), { prefix: "NITRO_", altPrefix: "NUXT_", envExpansion: nuxt.options.nitro.experimental?.envExpansion ?? !!process$1.env.NITRO_ENV_EXPANSION }); } /** * Update Nuxt runtime configuration. */ function updateRuntimeConfig(runtimeConfig) { const nitroConfig = useNuxt().options.nitro; Object.assign(nitroConfig.runtimeConfig, defu(runtimeConfig, nitroConfig.runtimeConfig)); return tryUseNitro()?.updateConfig({ runtimeConfig }); } function getEnv(key, opts, env = process$1.env) { const envKey = snakeCase(key).toUpperCase(); return destr(env[opts.prefix + envKey] ?? env[opts.altPrefix + envKey]); } function _isObject(input) { return typeof input === "object" && !Array.isArray(input); } function applyEnv(obj, opts, parentKey = "") { for (const key in obj) { const subKey = parentKey ? `${parentKey}_${key}` : key; const envValue = getEnv(subKey, opts); if (_isObject(obj[key])) { if (_isObject(envValue)) { obj[key] = { ...obj[key], ...envValue }; applyEnv(obj[key], opts, subKey); } else if (envValue === void 0) applyEnv(obj[key], opts, subKey); else obj[key] = envValue ?? obj[key]; } else obj[key] = envValue ?? obj[key]; if (opts.envExpansion && typeof obj[key] === "string") obj[key] = _expandFromEnv(obj[key]); } return obj; } const envExpandRx = /\{\{([^{}]*)\}\}/g; function _expandFromEnv(value, env = process$1.env) { return value.replace(envExpandRx, (match, key) => { return env[key] || match; }); } //#endregion //#region src/build.ts const extendWebpackCompatibleConfig = (builder) => (fn, options = {}) => { const nuxt = useNuxt(); if (options.dev === false && nuxt.options.dev) return; if (options.build === false && nuxt.options.build) return; nuxt.hook(`${builder}:config`, async (configs) => { if (options.server !== false) { const config = configs.find((i) => i.name === "server"); if (config) await fn(config); } if (options.client !== false) { const config = configs.find((i) => i.name === "client"); if (config) await fn(config); } }); }; /** * Extend webpack config * * The fallback function might be called multiple times * when applying to both client and server builds. */ const extendWebpackConfig = extendWebpackCompatibleConfig("webpack"); /** * Extend rspack config * * The fallback function might be called multiple times * when applying to both client and server builds. */ const extendRspackConfig = extendWebpackCompatibleConfig("rspack"); /** * Extend Vite config */ function extendViteConfig(fn, options = {}) { const nuxt = useNuxt(); if (options.dev === false && nuxt.options.dev) return; if (options.build === false && nuxt.options.build) return; if (options.server === false || options.client === false) { const caller = getUserCaller(); const warning = `[@nuxt/kit] calling \`extendViteConfig\` with only server/client environment is deprecated${caller ? ` (used at \`${resolveAlias(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Nuxt 5+ will use the Vite Environment API which shares a configuration between environments. You can likely use a Vite plugin to achieve the same result.`; warn(warning); } return nuxt.hook("vite:extend", ({ config }) => fn(config)); } /** * Append webpack plugin to the config. */ function addWebpackPlugin(pluginOrGetter, options) { extendWebpackConfig(async (config) => { const method = options?.prepend ? "unshift" : "push"; const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter; config.plugins ||= []; config.plugins[method](...toArray(plugin)); }, options); } /** * Append rspack plugin to the config. */ function addRspackPlugin(pluginOrGetter, options) { extendRspackConfig(async (config) => { const method = options?.prepend ? "unshift" : "push"; const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter; config.plugins ||= []; config.plugins[method](...toArray(plugin)); }, options); } /** * Append Vite plugin to the config. */ function addVitePlugin(pluginOrGetter, options = {}) { const nuxt = useNuxt(); if (options.dev === false && nuxt.options.dev) return; if (options.build === false && nuxt.options.build) return; let needsEnvInjection = false; const isIsomorphic = options.server !== false && options.client !== false; nuxt.hook("vite:extend", async ({ config }) => { config.plugins ||= []; const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter); const method = options?.prepend ? "unshift" : "push"; if (!config.environments?.ssr || !config.environments.client) { if (isIsomorphic) config.plugins[method](...plugin); else needsEnvInjection = true; return; } const isAppServer = (name) => name === "ssr" || !!nuxt._appServerEnvironments?.has(name); const isAllowed = isIsomorphic ? (name) => name === "client" || isAppServer(name) : options.server === false ? (name) => name === "client" : isAppServer; const defaultEnforce = isIsomorphic ? options?.prepend ? "pre" : void 0 : options?.prepend ? "pre" : "post"; config.plugins[method](...plugin.map((p) => scopeToEnvironments(p, defaultEnforce, isAllowed))); }); nuxt.hook("vite:extendConfig", async (config, env) => { if (!needsEnvInjection) return; const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter); const method = options?.prepend ? "unshift" : "push"; if (env.isClient && options.server === false) config.plugins[method](...plugin); if (env.isServer && options.client === false) config.plugins[method](...plugin); }); } /** * `addVitePlugin` has always scoped plugins to the app builds. Builders can contribute * further environments (Nitro adds `nitro`, and one per service), so a plugin registered * here has to opt out of any environment it wasn't registered for. The check runs per * environment as Vite resolves them, so environments added after the plugin was * registered are still excluded, unless the server builder has named them as app server * environments by then. * * The plugin is returned as a top-level plugin rather than nested behind a wrapper * so that Vite still applies `apply`, sorts by `enforce`, calls server-level hooks * like `configureServer`, and exposes any extra properties the plugin declares * (`api`, and whatever tooling scanning `config.plugins` looks for) as usual. */ function scopeToEnvironments(plugin, defaultEnforce, isAllowed) { const { applyToEnvironment } = plugin; return { ...plugin, enforce: plugin.enforce ?? defaultEnforce, applyToEnvironment(environment) { if (!isAllowed(environment.name)) return false; return applyToEnvironment ? applyToEnvironment(environment) : true; } }; } function addBuildPlugin(pluginFactory, options) { if (pluginFactory.vite) addVitePlugin(pluginFactory.vite, options); if (pluginFactory.webpack) addWebpackPlugin(pluginFactory.webpack, options); if (pluginFactory.rspack) addRspackPlugin(pluginFactory.rspack, options); } /** * Set the build output for the given key. See {@link NuxtBuildOutputs}. */ function setBuildOutput(key, provider, nuxt = useNuxt()) { nuxt.buildOutputs[key] = provider; } //#endregion //#region src/components.ts /** * Register a directory to be scanned for components and imported only when used. */ function addComponentsDir(dir, opts = {}) { const nuxt = useNuxt(); nuxt.options.components ||= []; dir.priority ||= 0; nuxt.hook("components:dirs", (dirs) => { dirs[opts.prepend ? "unshift" : "push"](dir); }); } /** * This utility takes a file path or npm package that is scanned for named exports, which are get added automatically */ function addComponentExports(opts) { const nuxt = useNuxt(); const components = []; nuxt.hook("components:dirs", async () => { const filePath = await resolvePath(opts.filePath); const names = await resolveModuleExportNames(filePath, { extensions: nuxt.options.extensions }); components.length = 0; for (const name of names) components.push(normalizeComponent({ name: pascalCase([opts.prefix || "", name === "default" ? "" : name]), export: name, ...opts })); }); addComponents(components); } /** * Register a component by its name and filePath. */ function addComponent(opts) { addComponents([normalizeComponent(opts)]); } function addComponents(addedComponents) { const nuxt = useNuxt(); nuxt.options.components ||= []; nuxt.hook("components:extend", (components) => { for (const component of addedComponents) { const existingComponentIndex = components.findIndex((c) => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode); if (existingComponentIndex !== -1) { const existingComponent = components[existingComponentIndex]; const existingPriority = existingComponent.priority ?? 0; const newPriority = component.priority ?? 0; if (newPriority < existingPriority) continue; if (newPriority === existingPriority) { const name = existingComponent.pascalName || existingComponent.kebabName; componentDiagnostics.NUXT_B3012({ name }); } components.splice(existingComponentIndex, 1, component); } else components.push(component); } }); } function normalizeComponent(opts) { if (!opts.mode) { const [, mode = "all"] = opts.filePath.match(MODE_RE) || []; opts.mode = mode; } return { export: opts.export || "default", chunkName: "components/" + kebabCase(opts.name), global: opts.global ?? false, kebabName: kebabCase(opts.name || ""), pascalName: pascalCase(opts.name || ""), prefetch: false, preload: false, mode: "all", shortPath: opts.filePath, priority: 0, meta: {}, ...opts }; } //#endregion //#region src/types.ts const TYPE_RESOLVE_OPTIONS = { conditions: [ "types", "import", "require" ], extensions: [ ".js", ".mjs", ".cjs", ".ts", ".mts", ".cts" ] }; const STRIPPABLE_EXT_RE = /\b\.(?:d\.ts|tsx?|jsx?)$/; const RUNTIME_EXT_RE = /(? s.isFile(), () => false); } /** * Rewrite a resolved module path to the declaration file TypeScript will load for it. * * A `.d.ts` / `.d.mts` / `.d.cts` or `.ts` / `.tsx` path is returned unchanged (or with * the extension stripped, where TypeScript's extensionless `paths` retry will find it). * A `.mjs` / `.cjs` / `.mts` / `.cts` runtime path is rewritten to an adjacent declaration * sibling when one exists; otherwise it is returned as-is for the caller to handle. */ async function resolveDeclarationPath(absolutePath) { const stripped = absolutePath.replace(STRIPPABLE_EXT_RE, ""); if (stripped !== absolutePath) return stripped; const runtimeMatch = absolutePath.match(RUNTIME_EXT_RE); if (runtimeMatch) { const base = absolutePath.slice(0, -runtimeMatch[0].length); if (await isFile(`${base}.d.ts`)) return base; const declaration = `${base}.d.${runtimeMatch[1]}ts`; if (await isFile(declaration)) return declaration; } return absolutePath; } /** Extract the package name (including scope) from a (possibly subpath) module specifier. */ function packageName(specifier) { const segments = specifier.split("/"); return specifier[0] === "@" ? segments.slice(0, 2).join("/") : segments[0]; } const rootCache = /* @__PURE__ */ new Map(); function resolveRoot(basePkg, from) { const cacheKey = `${basePkg}\0${from.map(String).join("\0")}`; if (rootCache.has(cacheKey)) return rootCache.get(cacheKey); const promise = Promise.resolve().then(() => { try { const r = resolveModulePath(basePkg, { from, ...TYPE_RESOLVE_OPTIONS }); return resolvePackageDir(r); } catch { return; } }); rootCache.set(cacheKey, promise); return promise; } /** * Resolve auto-import / `tsConfig.paths` entries to the path TypeScript should load types from. * * A bare package resolves to its package root, so TypeScript follows the package's own * `exports` / `types` (which may differ from the file its `.` export condition points at). * A subpath export resolves to its entry's declaration sibling when one exists, otherwise to * the resolved file itself. * * Returns `[specifier, absolutePath]` pairs, omitting any specifier that cannot be resolved. */ async function resolveTypePaths(packages, searchPaths, options = {}) { const from = searchPaths.map((d) => directoryToURL(d)); return (await Promise.allSettled(packages.map(async (pkg) => { if (pkg === packageName(pkg) && !options.entry) { const root = await resolveRoot(pkg, from); return root ? [pkg, root] : void 0; } const resolved = resolveModulePath(pkg, { from, try: true, ...TYPE_RESOLVE_OPTIONS }); if (resolved) return [pkg, await resolveDeclarationPath(resolved)]; const root = options.entry ? await resolveRoot(pkg, from) : void 0; return root ? [pkg, root] : void 0; }))).flatMap((result) => result.status === "fulfilled" && result.value ? [result.value] : []); } //#endregion //#region src/template.ts /** * Renders given template during build into the virtual file system (and optionally to disk in the project `buildDir`) */ function addTemplate(_template) { const nuxt = useNuxt(); const template = normalizeTemplate(_template); filterInPlace(nuxt.options.build.templates, (p) => (p.dst || normalizeTemplate(p).dst) !== template.dst); try { const distDir = distDirURL.toString(); const { source } = captureStackTrace().find((e) => e.source && !e.source.startsWith(distDir)) ?? {}; if (source) { const path = normalize(fileURLToPath(source)); if (existsSync(path)) template._path = path; } } catch {} nuxt.options.build.templates.push(template); return template; } /** * Adds a virtual file that can be used within the server build. */ function addServerTemplate(template) { const nuxt = useNuxt(); nuxt.options.nitro.virtual ||= {}; nuxt.options.nitro.virtual[template.filename] = template.getContents; return template; } /** * Renders given types during build to disk in the project `typesDir` * and register them as types. * * You can pass a second context object to specify in which context the type should be added. * * If no context object is passed, then it will only be added to the nuxt context. */ function addTypeTemplate(_template, context) { const nuxt = useNuxt(); const template = addTemplate(_template); if (!template.filename.endsWith(".d.ts")) throw kitDiagnostics.NUXT_B8007({ template: template.filename }); if (!context || context.nuxt) nuxt.hook("prepare:types", (payload) => { payload.references ||= []; payload.references.push({ path: template.dst }); }); if (context?.node) nuxt.hook("prepare:types", (payload) => { payload.nodeReferences ||= []; payload.nodeReferences.push({ path: template.dst }); }); if (context?.shared) nuxt.hook("prepare:types", (payload) => { payload.sharedReferences ||= []; payload.sharedReferences.push({ path: template.dst }); }); if (!context || context.nuxt || context.shared) nuxt.options.vite.vue = defu(nuxt.options.vite.vue, { script: { globalTypeFiles: [template.dst] } }); if (context?.nitro) nuxt.hook("nitro:prepare:types", (payload) => { payload.references ||= []; payload.references.push({ path: template.dst }); }); return template; } function hashPath(path) { return createHash("sha256").update(path).digest("base64url").slice(0, 10).replace(/-/g, "_"); } /** * Normalize a nuxt template object */ function normalizeTemplate(template, buildDir) { if (!template) throw kitDiagnostics.NUXT_B8008({ template: JSON.stringify(template) }); if (typeof template === "string") template = { src: template }; else template = { ...template }; if (template.src) { if (!existsSync(template.src)) throw kitDiagnostics.NUXT_B8009({ template: template.src }); if (!template.filename) { const srcPath = parse(template.src); template.filename = template.fileName || `${basename(srcPath.dir)}.${srcPath.name}.${hashPath(template.src)}${srcPath.ext}`; } } if (!template.src && !template.getContents) throw kitDiagnostics.NUXT_B8010({ template: template.filename || template.src || JSON.stringify(template) }); if (!template.filename) throw kitDiagnostics.NUXT_B8011({ template: JSON.stringify(template) }); if (template.filename.endsWith(".d.ts") || template.filename.endsWith(".d.mts") || template.filename.endsWith(".d.cts")) template.write = true; template.dst ||= resolve(buildDir ?? useNuxt().options.buildDir, template.filename); return template; } /** * Trigger rebuilding Nuxt templates * * You can pass a filter within the options to selectively regenerate a subset of templates. */ async function updateTemplates(options) { await tryUseNuxt()?.hooks.callHook("builder:generateApp", options); } function moduleFileGlobs(dir, extensions) { return extensions.map((ext) => join(dir, `*${ext}`)); } function resolveLayerPaths(dirs, projectBuildDir, extensions = DEFAULT_JS_FILE_EXTENSIONS$1) { const relativeRootDir = relativeWithDot(projectBuildDir, dirs.root); const relativeSrcDir = relativeWithDot(projectBuildDir, dirs.app); const relativeModulesDir = relativeWithDot(projectBuildDir, dirs.modules); const relativeSharedDir = relativeWithDot(projectBuildDir, dirs.shared); const relativeServerDir = relativeWithDot(projectBuildDir, dirs.server); return { nuxt: [ join(relativeSrcDir, "**/*"), join(relativeModulesDir, `*/runtime/**/*`), join(relativeRootDir, `test/nuxt/**/*`), join(relativeRootDir, `tests/nuxt/**/*`), join(relativeRootDir, `layers/*/app/**/*`), join(relativeRootDir, `layers/*/modules/*/runtime/**/*`) ], server: [ join(relativeServerDir, `**/*`), join(relativeModulesDir, `*/runtime/server/**/*`), join(relativeRootDir, `layers/*/server/**/*`), join(relativeRootDir, `layers/*/modules/*/runtime/server/**/*`) ], node: [ ...moduleFileGlobs(relativeModulesDir, extensions), join(relativeRootDir, `nuxt.config.*`), join(relativeRootDir, `.config/nuxt.*`), join(relativeRootDir, `layers/*/nuxt.config.*`), join(relativeRootDir, `layers/*/.config/nuxt.*`), ...moduleFileGlobs(join(relativeRootDir, "layers/*/modules"), extensions), ...moduleFileGlobs(join(relativeRootDir, "layers/*/modules/*"), extensions) ], shared: [ join(relativeSharedDir, `**/*`), join(relativeModulesDir, `*/shared/**/*`), join(relativeRootDir, `layers/*/shared/**/*`) ], sharedDeclarations: [ join(relativeSharedDir, `**/*.d.ts`), join(relativeModulesDir, `*/shared/**/*.d.ts`), join(relativeRootDir, `layers/*/shared/**/*.d.ts`) ], globalDeclarations: [join(relativeRootDir, `*.d.ts`), join(relativeRootDir, `layers/*/*.d.ts`)] }; } async function getPathSubstitution(absolutePath, buildDir) { return relativeWithDot(buildDir, await resolveDeclarationPath(absolutePath)); } const TS_PATH_TARGET_EXTENSIONS = [ ".d.ts", ".d.mts", ".d.cts", ".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs" ]; const TS_MATCHED_EXTENSIONS = /* @__PURE__ */ new Set([ ".ts", ".tsx", ".mts", ".cts", ".d.ts", ".js", ".jsx", ".mjs", ".cjs" ]); /** * Rewrite an `include` entry so it names `extension` explicitly, or return `undefined` when the * entry already targets specific files. */ function withExplicitExtension(entry, extension) { if (entry === "**/*" || entry.endsWith("/**/*")) return entry + extension; if (entry.includes("*") || basename(entry).includes(".")) return; return join(entry, "**/*" + extension); } /** * Resolve an extensionless `paths` target to the file TypeScript should load for it. * * `bundler` resolution retries a fixed set of extensions when a substitution is extensionless, * but the `node` environment is resolved as `nodenext`, which does not: the target has to name a * real file. Returns `undefined` when nothing matches, leaving the target untouched. */ async function resolveExtensionlessTarget(absolutePath) { for (const extension of TS_PATH_TARGET_EXTENSIONS) { const candidate = absolutePath + extension; if (await promises.stat(candidate).then((s) => s.isFile(), () => false)) return candidate; } } const excludedAlias = [/^@vue\/.*$/, /^#internal\/nuxt/]; const appOnlyAlias = [ /^@vue\/.*$/, "vue", /vue-router/, "vite/client", "vue-demi", /^#app/, /^#imports/, "~", "@", "~~", "@@" ]; async function _generateTypes(nuxt) { const typesDir = nuxt.options.typesDir || nuxt.options.buildDir; const include = /* @__PURE__ */ new Set(["./nuxt.d.ts"]); const nodeInclude = /* @__PURE__ */ new Set(["./nuxt.node.d.ts"]); const sharedInclude = /* @__PURE__ */ new Set(["./nuxt.shared.d.ts"]); const serverInclude = /* @__PURE__ */ new Set(["./nuxt.server.d.ts"]); const legacyInclude = /* @__PURE__ */ new Set([...include, ...nodeInclude]); const exclude = /* @__PURE__ */ new Set(); const nodeExclude = /* @__PURE__ */ new Set(); const sharedExclude = /* @__PURE__ */ new Set(); const serverExclude = /* @__PURE__ */ new Set(); const legacyExclude = /* @__PURE__ */ new Set(); if (nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.srcDir) { include.add(join(relative(typesDir, nuxt.options.workspaceDir), "**/*")); legacyInclude.add(join(relative(typesDir, nuxt.options.workspaceDir), "**/*")); } const layerDirs = getLayerDirectories(nuxt); const sourceDirs = layerDirs.map((layer) => layer.app); for (const dir of nuxt.options.modulesDir) { if (!sourceDirs.some((srcDir) => dir.startsWith(srcDir))) exclude.add(relativeWithDot(typesDir, dir)); nodeExclude.add(relativeWithDot(typesDir, dir)); serverExclude.add(relativeWithDot(typesDir, dir)); legacyExclude.add(relativeWithDot(typesDir, dir)); } for (const dir of ["dist", ".data"]) { exclude.add(relativeWithDot(typesDir, resolve(nuxt.options.rootDir, dir))); nodeExclude.add(relativeWithDot(typesDir, resolve(nuxt.options.rootDir, dir))); serverExclude.add(relativeWithDot(typesDir, resolve(nuxt.options.rootDir, dir))); legacyExclude.add(relativeWithDot(typesDir, resolve(nuxt.options.rootDir, dir))); } const rootDirWithSlash = withTrailingSlash(nuxt.options.rootDir); for (const dirs of layerDirs) if (!dirs.app.startsWith(rootDirWithSlash) || dirs.root === rootDirWithSlash || dirs.app.includes("node_modules")) { const rootGlob = join(relativeWithDot(typesDir, dirs.root), "**/*"); const paths = resolveLayerPaths(dirs, typesDir, nuxt.options.extensions); for (const path of paths.nuxt) { include.add(path); legacyInclude.add(path); if (path !== rootGlob) nodeExclude.add(path); } for (const path of paths.server) { serverInclude.add(path); exclude.add(path); nodeExclude.add(path); legacyExclude.add(path); } for (const path of paths.node) { nodeInclude.add(path); legacyInclude.add(path); exclude.add(path); } for (const path of paths.shared) { legacyInclude.add(path); sharedInclude.add(path); serverInclude.add(path); } for (const path of paths.sharedDeclarations) include.add(path); for (const path of paths.globalDeclarations) { include.add(path); legacyInclude.add(path); sharedInclude.add(path); serverInclude.add(path); } } for (const dirs of layerDirs) { const serverGlob = join(relativeWithDot(typesDir, dirs.server), "**/*"); serverInclude.add(serverGlob); serverInclude.add(join(relativeWithDot(typesDir, dirs.shared), "**/*.d.ts")); exclude.add(serverGlob); nodeExclude.add(serverGlob); legacyExclude.add(serverGlob); } const moduleEntryPaths = []; for (const m of nuxt.options._installedModules) { const path = m.meta?.rawPath || m.entryPath; if (path) moduleEntryPaths.push(getDirectory(path)); } const modulePaths = await resolveNuxtModule(rootDirWithSlash, moduleEntryPaths); for (const path of modulePaths) { const relative = relativeWithDot(typesDir, path); const sourceGlobs = moduleFileGlobs(relative, nuxt.options.extensions); const entryGlobs = [...sourceGlobs, ...moduleFileGlobs(join(relative, "dist"), nuxt.options.extensions)]; if (!path.includes("node_modules") && path.startsWith(rootDirWithSlash)) { include.add(join(relative, "runtime")); include.add(join(relative, "dist/runtime")); for (const glob of sourceGlobs) nodeInclude.add(glob); } legacyInclude.add(join(relative, "runtime")); legacyInclude.add(join(relative, "dist/runtime")); nodeExclude.add(join(relative, "runtime")); nodeExclude.add(join(relative, "dist/runtime")); serverInclude.add(join(relative, "runtime/server")); serverInclude.add(join(relative, "dist/runtime/server")); exclude.add(join(relative, "runtime/server")); exclude.add(join(relative, "dist/runtime/server")); for (const glob of entryGlobs) { serverExclude.add(glob); exclude.add(glob); } legacyExclude.add(join(relative, "runtime/server")); legacyExclude.add(join(relative, "dist/runtime/server")); } const extraExtensions = nuxt.options.extensions.filter((extension) => !TS_MATCHED_EXTENSIONS.has(extension)); for (const entries of [include, legacyInclude]) for (const entry of [...entries]) for (const extension of extraExtensions) { const withExtension = withExplicitExtension(entry, extension); if (withExtension) entries.add(withExtension); } const nestedModulesDirs = []; for (const dir of nuxt.options.modulesDir.toSorted()) { const withSlash = withTrailingSlash(dir); if (nestedModulesDirs.every((d) => !d.startsWith(withSlash))) nestedModulesDirs.push(withSlash); } let hasTypescriptVersionWithModulePreserve; for (const parent of nestedModulesDirs) hasTypescriptVersionWithModulePreserve ??= await readPackageJSON("typescript", { parent }).then((r) => r?.version && isGreaterThanOrEqual(r.version, "5.4.0")).catch(() => void 0); hasTypescriptVersionWithModulePreserve ??= true; const useDecorators = Boolean(nuxt.options.experimental?.decorators); const isV5OrHigher = (nuxt.options.future?.compatibilityVersion ?? 4) >= 5; const userExclude = [...nuxt.options.typescript?.tsConfig?.exclude ?? [], ...nuxt.options.typescript?.appTsConfig?.exclude ?? []]; const baseTsConfig = defu(nuxt.options.typescript?.tsConfig, { compilerOptions: { esModuleInterop: true, skipLibCheck: true, target: "ESNext", allowJs: true, allowImportingTsExtensions: true, resolveJsonModule: true, moduleDetection: "force", isolatedModules: true, verbatimModuleSyntax: true, allowArbitraryExtensions: true, strict: nuxt.options.typescript?.strict ?? true, noUncheckedIndexedAccess: true, forceConsistentCasingInFileNames: true, noImplicitOverride: true, ...isV5OrHigher ? { noUncheckedSideEffectImports: true } : {}, ...useDecorators ? { experimentalDecorators: false } : {}, module: hasTypescriptVersionWithModulePreserve ? "preserve" : "ESNext", noEmit: true, lib: [ "ESNext", ...useDecorators ? ["esnext.decorators"] : [], "dom", "dom.iterable", "webworker" ], libReplacement: false, jsx: "preserve", jsxImportSource: "vue", types: [], paths: {}, moduleResolution: nuxt.options.future?.typescriptBundlerResolution || nuxt.options.experimental?.typescriptBundlerResolution ? "Bundler" : "Node", useDefineForClassFields: true, noImplicitThis: true, allowSyntheticDefaultImports: true }, include: [...include], exclude: [...exclude] }); const tsConfig = defu(nuxt.options.typescript?.appTsConfig, baseTsConfig); const appOnlyCompilerOptions = [ "lib", "libReplacement", "jsx", "jsxImportSource", "noUncheckedSideEffectImports", "experimentalDecorators" ]; const nonAppCompilerOptions = () => { const compilerOptions = { ...baseTsConfig.compilerOptions }; for (const key of appOnlyCompilerOptions) delete compilerOptions[key]; return { ...compilerOptions, noEmit: true, types: [], paths: {} }; }; const nodeTsConfig = defu(nuxt.options.typescript?.nodeTsConfig, { compilerOptions: { ...nonAppCompilerOptions(), ...isV5OrHigher ? { module: "nodenext", moduleResolution: "nodenext", erasableSyntaxOnly: true } : {} }, include: [...nodeInclude], exclude: [...nodeExclude] }); const sharedTsConfig = defu(nuxt.options.typescript?.sharedTsConfig, { compilerOptions: nonAppCompilerOptions(), include: [...sharedInclude], exclude: [...sharedExclude] }); const serverTsConfig = defu(nuxt.options.typescript?.serverTsConfig, { compilerOptions: { ...nonAppCompilerOptions(), lib: [ "ESNext", "webworker", "dom.iterable" ], moduleResolution: "Bundler" }, include: [...serverInclude], exclude: [...serverExclude] }); const aliases = nuxt.options.alias; const baseUrl = isV5OrHigher ? void 0 : tsConfig.compilerOptions.baseUrl; const basePath = baseUrl ? resolve(typesDir, baseUrl) : typesDir; tsConfig.compilerOptions ||= {}; tsConfig.compilerOptions.paths ||= {}; tsConfig.include ||= []; tsConfig.exclude ||= []; serverTsConfig.compilerOptions ||= {}; serverTsConfig.compilerOptions.paths ||= {}; const serverBaseUrl = isV5OrHigher ? void 0 : serverTsConfig.compilerOptions.baseUrl ?? baseUrl; const serverBasePath = serverBaseUrl ? resolve(typesDir, serverBaseUrl) : typesDir; const importPaths = nuxt.options.modulesDir.map((d) => directoryToURL(d)); for (const alias in aliases) { if (excludedAlias.some((re) => re.test(alias))) continue; const inServer = !appOnlyAlias.some((pattern) => typeof pattern === "string" ? alias === pattern : pattern.test(alias)); let absolutePath = resolve(basePath, aliases[alias]); let stats = await promises.stat(absolutePath).catch(() => null); if (!stats) { const resolvedModule = resolveModulePath(aliases[alias], { try: true, from: importPaths, extensions: [ ...nuxt.options.extensions, ".d.ts", ".d.mts", ".d.cts" ] }); if (resolvedModule) { absolutePath = resolvedModule; stats = await promises.stat(resolvedModule).catch(() => null); } } const serverAbsolutePath = serverBasePath === basePath ? absolutePath : resolve(serverBasePath, aliases[alias]); const relativePath = relativeWithDot(typesDir, absolutePath); const serverRelativePath = relativeWithDot(typesDir, serverAbsolutePath); if (stats?.isDirectory() || aliases[alias].endsWith("/")) { tsConfig.compilerOptions.paths[alias] = [relativePath]; tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`]; if (inServer) { serverTsConfig.compilerOptions.paths[alias] = [serverRelativePath]; serverTsConfig.compilerOptions.paths[`${alias}/*`] = [`${serverRelativePath}/*`]; } } else { const path = stats?.isFile() ? await getPathSubstitution(absolutePath, typesDir) : aliases[alias]; tsConfig.compilerOptions.paths[alias] = [path]; if (inServer) serverTsConfig.compilerOptions.paths[alias] = [serverBasePath === basePath ? path : stats?.isFile() ? await getPathSubstitution(serverAbsolutePath, typesDir) : aliases[alias]]; } } const references = []; const nodeReferences = []; const sharedReferences = []; const serverReferences = []; await Promise.all([...nuxt.options.modules, ...nuxt.options._modules].map(async (id) => { if (typeof id !== "string") return; for (const parent of nestedModulesDirs) { const pkg = await readPackageJSON(id, { parent }).catch(() => null); if (pkg) { nodeReferences.push({ types: pkg.name ?? id }); references.push({ types: pkg.name ?? id }); return; } } nodeReferences.push({ types: id }); references.push({ types: id }); })); const declarations = []; await nuxt.callHook("prepare:types", { references, declarations, tsConfig, nodeTsConfig, nodeReferences, sharedTsConfig, sharedReferences, serverTsConfig, serverReferences }); const legacyTsConfig = defu({}, { ...tsConfig, include: [...tsConfig.include, ...legacyInclude], exclude: [...userExclude, ...legacyExclude] }); const nonRootLayerDirs = layerDirs.map((dirs) => dirs.root).filter((root) => !rootDirWithSlash.startsWith(root)); async function resolveConfig(tsConfig) { if (isV5OrHigher) Reflect.deleteProperty(tsConfig.compilerOptions, "baseUrl"); tsConfig.compilerOptions.paths ||= {}; for (const alias in tsConfig.compilerOptions.paths) { const paths = tsConfig.compilerOptions.paths[alias]; tsConfig.compilerOptions.paths[alias] = [...new Set(await Promise.all(paths.map(async (path) => { if (!isAbsolute(path)) return path; if ((await promises.stat(path).catch(() => null))?.isFile()) return getPathSubstitution(path, typesDir); const resolved = await resolveExtensionlessTarget(path); if (resolved) return relativeWithDot(typesDir, resolved); return relativeWithDot(typesDir, path); })))]; } tsConfig.compilerOptions.paths = sortTsPaths(tsConfig.compilerOptions.paths, nonRootLayerDirs, typesDir, nuxt.options.typescript?.hoist ?? []); tsConfig.include = [...new Set(tsConfig.include.map((p) => isAbsolute(p) ? relativeWithDot(typesDir, p) : p))]; tsConfig.exclude = [...new Set(tsConfig.exclude.map((p) => isAbsolute(p) ? relativeWithDot(typesDir, p) : p))]; } await Promise.all([ resolveConfig(tsConfig), resolveConfig(nodeTsConfig), resolveConfig(sharedTsConfig), resolveConfig(serverTsConfig), resolveConfig(legacyTsConfig) ]); const declaration = [ ...references.map((ref) => renderReference(ref, typesDir)), ...declarations, "", "export {}", "" ].join("\n"); const nodeDeclaration = [ ...nodeReferences.map((ref) => renderReference(ref, typesDir)), "", "export {}", "" ].join("\n"); return { declaration, sharedTsConfig, sharedDeclaration: [ ...sharedReferences.map((ref) => renderReference(ref, typesDir)), "", "export {}", "" ].join("\n"), serverTsConfig, serverDeclaration: [ ...serverReferences.map((ref) => renderReference(ref, typesDir)), "", "export {}", "" ].join("\n"), nodeTsConfig, nodeDeclaration, tsConfig, legacyTsConfig }; } /** * Writes the generated `tsconfig` and declaration files to `typesDir`. * * When a production build uses a `buildDir` other than `typesDir`, existing files are left untouched. */ async function writeTypes(nuxt) { const { tsConfig, nodeTsConfig, nodeDeclaration, declaration, legacyTsConfig, sharedDeclaration, sharedTsConfig, serverDeclaration, serverTsConfig } = await _generateTypes(nuxt); const typesDir = nuxt.options.typesDir || nuxt.options.buildDir; const appTsConfigPath = resolve(typesDir, "tsconfig.app.json"); const legacyTsConfigPath = resolve(typesDir, "tsconfig.json"); const nodeTsConfigPath = resolve(typesDir, "tsconfig.node.json"); const sharedTsConfigPath = resolve(typesDir, "tsconfig.shared.json"); const serverTsConfigPath = resolve(typesDir, "tsconfig.server.json"); const declarationPath = resolve(typesDir, "nuxt.d.ts"); const nodeDeclarationPath = resolve(typesDir, "nuxt.node.d.ts"); const sharedDeclarationPath = resolve(typesDir, "nuxt.shared.d.ts"); const serverDeclarationPath = resolve(typesDir, "nuxt.server.d.ts"); const writesServerTsConfig = nuxt.options._nitroMajor !== 2; const write = !nuxt.options._prepare && !nuxt.options.dev && typesDir !== nuxt.options.buildDir ? writeIfMissing : writeIfChanged; await promises.mkdir(typesDir, { recursive: true }); await Promise.all([ write(appTsConfigPath, JSON.stringify(tsConfig, null, 2)), write(legacyTsConfigPath, JSON.stringify(legacyTsConfig, null, 2)), write(nodeTsConfigPath, JSON.stringify(nodeTsConfig, null, 2)), write(sharedTsConfigPath, JSON.stringify(sharedTsConfig, null, 2)), writesServerTsConfig && write(serverTsConfigPath, JSON.stringify(serverTsConfig, null, 2)), write(declarationPath, declaration), write(nodeDeclarationPath, nodeDeclaration), write(sharedDeclarationPath, sharedDeclaration), writesServerTsConfig && write(serverDeclarationPath, serverDeclaration) ]); } /** * Types are regenerated on every start and are usually identical, so avoid * touching the files: an unchanged mtime keeps editors and `tsc --watch` from * redoing work they have already done. */ async function writeIfChanged(path, contents) { if (await promises.readFile(path, "utf8").catch(() => void 0) === contents) return; await promises.writeFile(path, contents); } async function writeIfMissing(path, contents) { if (existsSync(path)) return; await promises.writeFile(path, contents); } /** * Sort the paths in the tsconfig.json file, so * - Hoisted package paths stay at the top (`typescript.hoist`) * - Custom layer aliases follow, then generic `#layers/*` aliases * - Generic `~`/`@` aliases come after layer aliases * - `#build` alias is at the bottom (https://github.com/nuxt/nuxt/issues/30325) */ function sortTsPaths(paths, layerDirs, buildDir, hoist) { const hoistKeys = new Set(hoist); const hoistPaths = {}; const customLayerPaths = {}; const genericLayerPaths = {}; const otherPaths = {}; const buildPaths = {}; for (const pathKey in paths) { if (pathKey.startsWith("#build")) { buildPaths[pathKey] = paths[pathKey]; continue; } if (isHoistPathKey(pathKey, hoistKeys)) { hoistPaths[pathKey] = paths[pathKey]; continue; } if (layerDirs.length && paths[pathKey].some((target) => isPathUnderLayerDirs(target, buildDir, layerDirs))) { if (pathKey.startsWith("#layers")) genericLayerPaths[pathKey] = paths[pathKey]; else customLayerPaths[pathKey] = paths[pathKey]; } else otherPaths[pathKey] = paths[pathKey]; } return { ...hoistPaths, ...customLayerPaths, ...genericLayerPaths, ...otherPaths, ...buildPaths }; } const PATH_WILDCARD_RE = /\/?\*$/; function isHoistPathKey(pathKey, hoistKeys) { return hoistKeys.has(pathKey.replace(PATH_WILDCARD_RE, "")); } function isPathUnderLayerDirs(target, buildDir, layerDirs) { const absolute = withTrailingSlash(resolve(buildDir, target.replace(PATH_WILDCARD_RE, ""))); return layerDirs.some((dir) => absolute.startsWith(dir)); } function renderReference(ref, baseDir) { return `/// `; } const RELATIVE_WITH_DOT_RE = /^([^.])/; function relativeWithDot(from, to) { return relative(from, to).replace(RELATIVE_WITH_DOT_RE, "./$1") || "."; } function withTrailingSlash(dir) { return dir.replace(/[^/]$/, "$&/"); } //#endregion //#region src/layout.ts const LAYOUT_RE = /["']/g; function addLayout(template, name) { const nuxt = useNuxt(); const { filename, src } = addTemplate(template); const layoutName = kebabCase(name || parse(filename).name).replace(LAYOUT_RE, ""); nuxt.hook("app:templates", (app) => { if (layoutName in app.layouts) { const relativePath = reverseResolveAlias(app.layouts[layoutName].file, { ...nuxt?.options.alias || {}, ...strippedAtAliases }).pop() || app.layouts[layoutName].file; pageDiagnostics.NUXT_B4014({ layoutName, existingPath: relativePath, newPath: src || filename }); return; } app.layouts[layoutName] = { file: join("#build", filename), name: layoutName }; }); } const strippedAtAliases = { "@": "", "@@": "" }; //#endregion //#region src/pages.ts function extendPages(cb) { useNuxt().hook("pages:extend", cb); } function extendRouteRules(route, rule, options = {}) { const nuxt = useNuxt(); for (const opts of [nuxt.options, nuxt.options.nitro]) { opts.routeRules ||= {}; opts.routeRules[route] = options.override ? defu(rule, opts.routeRules[route]) : defu(opts.routeRules[route], rule); } } function addRouteMiddleware(input, options = {}) { const nuxt = useNuxt(); const middlewares = toArray(input); nuxt.hook("app:resolve", (app) => { for (const middleware of middlewares) { const find = app.middleware.findIndex((item) => item.name === middleware.name); if (find >= 0) { const foundPath = app.middleware[find].path; if (foundPath === middleware.path) continue; if (options.override === true) app.middleware[find] = { ...middleware }; else pageDiagnostics.NUXT_B4013({ name: middleware.name, foundPath }); } else if (options.prepend === true) app.middleware.unshift({ ...middleware }); else app.middleware.push({ ...middleware }); } }); } //#endregion //#region src/plugin.ts /** * Normalize a nuxt plugin object */ const pluginSymbol = Symbol.for("nuxt plugin"); function normalizePlugin(plugin) { if (typeof plugin === "string") plugin = { src: plugin }; else plugin = { ...plugin }; if (pluginSymbol in plugin) return plugin; if (!plugin.src) throw pluginDiagnostics.NUXT_B2011({ src: JSON.stringify(plugin) }); plugin.src = normalize(resolveAlias(plugin.src)); if (!existsSync(plugin.src) && isAbsolute$1(plugin.src)) try { plugin.src = resolveModulePath(plugin.src, { extensions: tryUseNuxt()?.options.extensions ?? DEFAULT_JS_FILE_EXTENSIONS$1 }); } catch {} if (plugin.ssr) plugin.mode = "server"; if (!plugin.mode) { const [, mode = "all"] = plugin.src.match(MODE_RE) || []; plugin.mode = mode; } plugin[pluginSymbol] = true; return plugin; } function addPlugin(_plugin, opts = {}) { const nuxt = useNuxt(); const plugin = normalizePlugin(_plugin); filterInPlace(nuxt.options.plugins, (p) => normalizePlugin(p).src !== plugin.src); nuxt.options.plugins[opts.append ? "push" : "unshift"](plugin); return plugin; } /** * Adds a template and registers as a nuxt plugin. */ function addPluginTemplate(plugin, opts = {}) { return addPlugin(typeof plugin === "string" ? { src: plugin } : { ...plugin, src: addTemplate(plugin).dst }, opts); } //#endregion //#region src/watch.ts const RECHECK_DELAY = 70; /** * A single write moves the mtime more than once (truncate, then write) and * chokidar may dispatch `change` off the first of those, so a mtime a hair * newer than the one recorded is the tail of a write that *was* reported * rather than one that was dropped. */ const MTIME_EPSILON = 10; const RECOVERY_FLAG = Symbol.for("nuxt:watch-recovery"); /** * chokidar suppresses a `change` event that lands within 50ms of the previous * `change` for the same path, and never replays it. A save that follows a fast * HMR round trip is therefore silently lost until the file is touched again, * which looks exactly like broken HMR. This is true of every chokidar major * Nuxt uses. * * Raw fs events are not throttled, so once chokidar has reported a file at * least once we can use them to notice a modification that never surfaced as a * `change` event, and re-emit it after the throttle window has passed. * * @param watcher the chokidar watcher to patch * @returns a disposer releasing the recovery state; call it when the watcher closes */ function recoverThrottledChanges(watcher) { if (watcher[RECOVERY_FLAG]) return () => {}; Object.defineProperty(watcher, RECOVERY_FLAG, { value: true, configurable: true }); const tracked = /* @__PURE__ */ new Map(); const pending = /* @__PURE__ */ new Map(); let disposed = false; /** * With `cwd` set, chokidar emits high-level events relative to it while raw * events carry an absolute `watchedPath`, so everything is keyed absolutely * and the emitted path is kept alongside to re-emit in chokidar's namespace. */ const cwd = watcher.options?.cwd; const toKey = (path) => cwd ? resolve$1(cwd, path) : path; /** * `watchedPath` is the (possibly relative) path chokidar handed to `fs.watch` * and `path` is the name `fs.watch` reported, which is a basename both when * the file itself is watched and when its parent directory is. The two are * indistinguishable for a directory containing a child of the same name, so * pick whichever candidate chokidar has already reported a modification time * for, and use native separators to match the paths chokidar emits. */ const resolveTracked = (path, details) => { const watched = typeof details?.watchedPath === "string" ? details.watchedPath : void 0; if (!watched) { const key = toKey(path); return tracked.has(key) ? key : void 0; } const child = toKey(join$1(watched, path)); if (tracked.has(child)) return child; const parent = toKey(watched); return tracked.has(parent) ? parent : void 0; }; const track = (path, stats) => { if (disposed) return; const key = toKey(path); if (stats) { tracked.set(key, { mtimeMs: stats.mtimeMs, path }); return; } stat(key).then((s) => { if (!disposed) tracked.set(key, { mtimeMs: s.mtimeMs, path }); }, () => {}); }; const forget = (path) => { const key = toKey(path); tracked.delete(key); const timeout = pending.get(key); if (timeout) { clearTimeout(timeout); pending.delete(key); } }; watcher.on("add", track); watcher.on("change", track); watcher.on("unlink", forget); watcher.on("raw", (event, path, details) => { if (disposed) return; if (event !== "change" && event !== "rename" && event !== "modified") return; if (typeof path !== "string" || !path) return; const file = resolveTracked(path, details); if (!file || pending.has(file)) return; const timeout = setTimeout(() => { pending.delete(file); if (disposed) return; stat(file).then((stats) => { if (disposed) return; const previous = tracked.get(file); if (!previous) return; tracked.set(file, { mtimeMs: stats.mtimeMs, path: previous.path }); if (stats.mtimeMs - previous.mtimeMs <= MTIME_EPSILON) return; watcher.emit("change", previous.path, stats); watcher.emit("all", "change", previous.path, stats); }, () => {}); }, RECHECK_DELAY); timeout.unref(); pending.set(file, timeout); }); return () => { disposed = true; for (const timeout of pending.values()) clearTimeout(timeout); pending.clear(); tracked.clear(); }; } //#endregion //#region src/index.ts /** @deprecated Internal. Import from `@nuxt/kit/internal` instead. */ const DEFAULT_JS_FILE_EXTENSIONS = DEFAULT_JS_FILE_EXTENSIONS$1; /** @deprecated Internal. Import from `@nuxt/kit/internal` instead. */ const DEFAULT_JSX_FILE_EXTENSIONS = DEFAULT_JSX_FILE_EXTENSIONS$1; //#endregion export { DEFAULT_JSX_FILE_EXTENSIONS, DEFAULT_JS_FILE_EXTENSIONS, addBuildPlugin, addComponent, addComponentExports, addComponentsDir, addDevServerHandler, addImports, addImportsDir, addImportsSources, addLayout, addNitroPlugin, addPlugin, addPluginTemplate, addPrerenderRoutes, addRouteMiddleware, addRspackPlugin, addServerHandler, addServerImports, addServerImportsDir, addServerPlugin, addServerScanDir, addServerTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, assertNuxtCompatibility, buildNuxt, checkNuxtCompatibility, createIsIgnored, createResolver, defineNuxtModule, diffNuxtConfig, directoryToURL, ensureDependencyInstalled, extendNuxtSchema, extendPages, extendRouteRules, extendRspackConfig, extendViteConfig, extendWebpackConfig, findPath, getAddDependencyCommand, getDirectory, getLayerDirectories, getNitroVersion, getNuxtCtx, getNuxtModuleVersion, getNuxtVersion, hasNuxtCompatibility, hasNuxtModule, hasNuxtModuleCompatibility, importModule, installModule, isIgnored, isNuxt2, isNuxt3, isNuxtMajorVersion, loadNuxt, loadNuxtConfig, loadNuxtModuleInstance, logger, normalizeModuleTranspilePath, normalizePlugin, normalizeSemanticVersion, normalizeTemplate, nuxtCtx, packageName, recoverThrottledChanges, requireModule, resolveAlias, resolveDeclarationPath, resolveFiles, resolveIgnorePatterns, resolveModule, resolveModuleWithOptions, resolveNuxtModule, resolvePath, resolveServerVariant, resolveTypePaths, runWithNuxtContext, setBuildOutput, setGlobalHead, tryImportModule, tryRequireModule, tryResolveModule, tryUseNitro, tryUseNuxt, updateAppConfig, updateRuntimeConfig, updateTemplates, useLogger, useNitro, useNuxt, useRuntimeConfig, useTerminal, writeTypes };