文件操作 - nuxt.CEIo1U5K.mjs
返回文件管理
返回主菜单
删除本文件
文件: /var/www/OLD/node_modules/nuxt/dist/shared/nuxt.CEIo1U5K.mjs
编辑文件内容
import fs, { promises, existsSync, readdirSync, writeFileSync, statSync, readFileSync, mkdirSync } from 'node:fs'; import { mkdir, readFile, readdir, writeFile, rm, stat, unlink, open } from 'node:fs/promises'; import { dirname, resolve, normalize, basename, extname, relative, isAbsolute, join } from 'pathe'; import { createHooks, createDebugger } from 'hookable'; import ignore from 'ignore'; import { tryUseNuxt, useLogger, resolveFiles, useNuxt, resolvePath as resolvePath$1, defineNuxtModule, findPath, addPlugin, addTemplate, addTypeTemplate, addComponent, useNitro, addBuildPlugin, addImportsSources, tryResolveModule, isIgnored, resolveAlias, addPluginTemplate, addVitePlugin, createIsIgnored, updateTemplates, normalizeModuleTranspilePath, resolveNuxtModule, resolveIgnorePatterns, logger as logger$1, createResolver, importModule, nuxtCtx, addWebpackPlugin, addServerPlugin, installModule, addRouteMiddleware, loadNuxtConfig, normalizeTemplate, compileTemplate, normalizePlugin, templateUtils } from '@nuxt/kit'; import { resolvePackageJSON, readPackageJSON } from 'pkg-types'; import { hash, objectHash, murmurHash } from 'ohash'; import consola, { consola as consola$1 } from 'consola'; import { colorize } from 'consola/utils'; import { updateConfig } from 'c12/update'; import { resolveCompatibilityDatesFromEnv, formatDate } from 'compatx'; import escapeRE from 'escape-string-regexp'; import { withTrailingSlash, parseURL, parseQuery, withLeadingSlash, joinURL, encodePath, withoutLeadingSlash } from 'ufo'; import { ImpoundPlugin } from 'impound'; import defu$1, { defu } from 'defu'; import { satisfies, gt } from 'semver'; import { isWindows, hasTTY, isCI } from 'std-env'; import { genArrayFromRaw, genSafeVariableName, genImport, genDynamicImport, genObjectFromRawEntries, genString, genExport } from 'knitwork'; import { createRoutesContext } from 'unplugin-vue-router'; import { resolveOptions } from 'unplugin-vue-router/options'; import { toRouteMatcher, createRouter, exportMatcher } from 'radix3'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { resolvePath, findStaticImports, findExports, parseStaticImport, parseNodeModulePath, lookupNodeModuleSubpath } from 'mlly'; import { runInNewContext } from 'node:vm'; import { filename } from 'pathe/utils'; import { transform } from 'esbuild'; import { klona } from 'klona'; import { walk as walk$1 } from 'estree-walker'; import { parse } from 'acorn'; import { splitByCase, kebabCase, pascalCase, camelCase } from 'scule'; import { createUnplugin } from 'unplugin'; import MagicString from 'magic-string'; import { stripLiteral } from 'strip-literal'; import { globby } from 'globby'; import { parse as parse$1, walk as walk$2, ELEMENT_NODE } from 'ultrahtml'; import { createUnimport, defineUnimportPreset, toExports, scanDirExports } from 'unimport'; import { parseQuery as parseQuery$1 } from 'vue-router'; import { createTransformer } from 'unctx/transform'; import { cpus } from 'node:os'; import { createNitro, scanHandlers, writeTypes, copyPublicAssets, prepare, build as build$1, prerender, createDevServer } from 'nitropack'; import { dynamicEventHandler } from 'h3'; import { watch as watch$1 } from 'chokidar'; import { debounce } from 'perfect-debounce'; import { resolveSchema, generateTypes } from 'untyped'; import untypedPlugin from 'untyped/babel-plugin'; import { createJiti } from 'jiti'; import { resolve as resolve$1 } from 'node:path'; import { glob } from 'tinyglobby'; import { parseTar, createTar } from 'nanotar'; let _distDir = dirname(fileURLToPath(import.meta.url)); if (_distDir.match(/(chunks|shared)$/)) { _distDir = dirname(_distDir); } const distDir = _distDir; const pkgDir = resolve(distDir, ".."); async function resolveTypePath(path, subpath, searchPaths = tryUseNuxt()?.options.modulesDir) { try { const r = await resolvePath(path, { url: searchPaths, conditions: ["types", "import", "require"] }); if (subpath) { return r.replace(/(?:\.d)?\.[mc]?[jt]s$/, ""); } const rootPath = await resolvePackageJSON(r); return dirname(rootPath); } catch { return null; } } function toArray(value) { return Array.isArray(value) ? value : [value]; } async function isDirectory$1(path) { return (await promises.lstat(path)).isDirectory(); } const logger = useLogger("nuxt"); function walk(ast, callback) { return walk$1(ast, { enter(node, parent, key, index) { callback.scopeTracker?.processNodeEnter(node); callback.enter?.call(this, node, parent, { key, index, ast }); }, leave(node, parent, key, index) { callback.scopeTracker?.processNodeLeave(node); callback.leave?.call(this, node, parent, { key, index, ast }); } }); } function parseAndWalk(code, _sourceFilename, callback) { const ast = parse(code, { sourceType: "module", ecmaVersion: "latest", locations: true }); walk(ast, typeof callback === "function" ? { enter: callback } : callback); return ast; } function withLocations(node) { return node; } function isChildScope(a, b) { return a.startsWith(b) && a.length > b.length; } class BaseNode { scope; node; constructor(node, scope) { this.node = node; this.scope = scope; } /** * Check if the node is defined under a specific scope. * @param scope */ isUnderScope(scope) { return isChildScope(this.scope, scope); } } class IdentifierNode extends BaseNode { type = "Identifier"; get start() { return this.node.start; } get end() { return this.node.end; } } class FunctionParamNode extends BaseNode { type = "FunctionParam"; fnNode; constructor(node, scope, fnNode) { super(node, scope); this.fnNode = fnNode; } get start() { return this.fnNode.start; } get end() { return this.fnNode.end; } } class FunctionNode extends BaseNode { type = "Function"; get start() { return this.node.start; } get end() { return this.node.end; } } class VariableNode extends BaseNode { type = "Variable"; variableNode; constructor(node, scope, variableNode) { super(node, scope); this.variableNode = variableNode; } get start() { return this.variableNode.start; } get end() { return this.variableNode.end; } } class ImportNode extends BaseNode { type = "Import"; importNode; constructor(node, scope, importNode) { super(node, scope); this.importNode = importNode; } get start() { return this.importNode.start; } get end() { return this.importNode.end; } } class CatchParamNode extends BaseNode { type = "CatchParam"; catchNode; constructor(node, scope, catchNode) { super(node, scope); this.catchNode = catchNode; } get start() { return this.catchNode.start; } get end() { return this.catchNode.end; } } class ScopeTracker { scopeIndexStack = []; scopeIndexKey = ""; scopes = /* @__PURE__ */ new Map(); options; isFrozen = false; constructor(options = {}) { this.options = options; } updateScopeIndexKey() { this.scopeIndexKey = this.scopeIndexStack.slice(0, -1).join("-"); } pushScope() { this.scopeIndexStack.push(0); this.updateScopeIndexKey(); } popScope() { this.scopeIndexStack.pop(); if (this.scopeIndexStack[this.scopeIndexStack.length - 1] !== undefined) { this.scopeIndexStack[this.scopeIndexStack.length - 1]++; } if (!this.options.keepExitedScopes) { this.scopes.delete(this.scopeIndexKey); } this.updateScopeIndexKey(); } declareIdentifier(name, data) { if (this.isFrozen) { return; } let scope = this.scopes.get(this.scopeIndexKey); if (!scope) { scope = /* @__PURE__ */ new Map(); this.scopes.set(this.scopeIndexKey, scope); } scope.set(name, data); } declareFunctionParameter(param, fn) { if (this.isFrozen) { return; } const identifiers = getPatternIdentifiers(param); for (const identifier of identifiers) { this.declareIdentifier(identifier.name, new FunctionParamNode(identifier, this.scopeIndexKey, fn)); } } declarePattern(pattern, parent) { if (this.isFrozen) { return; } const identifiers = getPatternIdentifiers(pattern); for (const identifier of identifiers) { this.declareIdentifier( identifier.name, parent.type === "VariableDeclaration" ? new VariableNode(identifier, this.scopeIndexKey, parent) : parent.type === "CatchClause" ? new CatchParamNode(identifier, this.scopeIndexKey, parent) : new FunctionParamNode(identifier, this.scopeIndexKey, parent) ); } } processNodeEnter(node) { switch (node.type) { case "Program": case "BlockStatement": case "StaticBlock": this.pushScope(); break; case "FunctionDeclaration": if (node.id?.name) { this.declareIdentifier(node.id.name, new FunctionNode(node, this.scopeIndexKey)); } this.pushScope(); for (const param of node.params) { this.declareFunctionParameter(withLocations(param), node); } break; case "FunctionExpression": this.pushScope(); if (node.id?.name) { this.declareIdentifier(node.id.name, new FunctionNode(node, this.scopeIndexKey)); } this.pushScope(); for (const param of node.params) { this.declareFunctionParameter(withLocations(param), node); } break; case "ArrowFunctionExpression": this.pushScope(); for (const param of node.params) { this.declareFunctionParameter(withLocations(param), node); } break; case "VariableDeclaration": for (const decl of node.declarations) { this.declarePattern(withLocations(decl.id), node); } break; case "ClassDeclaration": if (node.id?.name) { this.declareIdentifier(node.id.name, new IdentifierNode(withLocations(node.id), this.scopeIndexKey)); } break; case "ClassExpression": this.pushScope(); if (node.id?.name) { this.declareIdentifier(node.id.name, new IdentifierNode(withLocations(node.id), this.scopeIndexKey)); } break; case "ImportDeclaration": for (const specifier of node.specifiers) { this.declareIdentifier(specifier.local.name, new ImportNode(withLocations(specifier), this.scopeIndexKey, node)); } break; case "CatchClause": this.pushScope(); if (node.param) { this.declarePattern(withLocations(node.param), node); } break; case "ForStatement": case "ForOfStatement": case "ForInStatement": this.pushScope(); if (node.type === "ForStatement" && node.init?.type === "VariableDeclaration") { for (const decl of node.init.declarations) { this.declarePattern(withLocations(decl.id), withLocations(node.init)); } } else if ((node.type === "ForOfStatement" || node.type === "ForInStatement") && node.left.type === "VariableDeclaration") { for (const decl of node.left.declarations) { this.declarePattern(withLocations(decl.id), withLocations(node.left)); } } break; } } processNodeLeave(node) { switch (node.type) { case "Program": case "BlockStatement": case "CatchClause": case "FunctionDeclaration": case "ArrowFunctionExpression": case "StaticBlock": case "ClassExpression": case "ForStatement": case "ForOfStatement": case "ForInStatement": this.popScope(); break; case "FunctionExpression": this.popScope(); this.popScope(); break; } } isDeclared(name) { if (!this.scopeIndexKey) { return this.scopes.get("")?.has(name) || false; } const indices = this.scopeIndexKey.split("-").map(Number); for (let i = indices.length; i >= 0; i--) { if (this.scopes.get(indices.slice(0, i).join("-"))?.has(name)) { return true; } } return false; } getDeclaration(name) { if (!this.scopeIndexKey) { return this.scopes.get("")?.get(name) ?? null; } const indices = this.scopeIndexKey.split("-").map(Number); for (let i = indices.length; i >= 0; i--) { const node = this.scopes.get(indices.slice(0, i).join("-"))?.get(name); if (node) { return node; } } return null; } getCurrentScope() { return this.scopeIndexKey; } /** * Check if the current scope is a child of a specific scope. * @example * ```ts * // current scope is 0-1 * isCurrentScopeUnder('0') // true * isCurrentScopeUnder('0-1') // false * ``` * * @param scope the parent scope * @returns `true` if the current scope is a child of the specified scope, `false` otherwise (also when they are the same) */ isCurrentScopeUnder(scope) { return isChildScope(this.scopeIndexKey, scope); } /** * Freezes the scope tracker, preventing further declarations. * It also resets the scope index stack to its initial state, so that the scope tracker can be reused. * * This is useful for second passes through the AST. */ freeze() { this.isFrozen = true; this.scopeIndexStack = []; this.updateScopeIndexKey(); } } function getPatternIdentifiers(pattern) { const identifiers = []; function collectIdentifiers(pattern2) { switch (pattern2.type) { case "Identifier": identifiers.push(pattern2); break; case "AssignmentPattern": collectIdentifiers(withLocations(pattern2.left)); break; case "RestElement": collectIdentifiers(withLocations(pattern2.argument)); break; case "ArrayPattern": for (const element of pattern2.elements) { if (element) { collectIdentifiers(withLocations(element.type === "RestElement" ? element.argument : element)); } } break; case "ObjectPattern": for (const property of pattern2.properties) { collectIdentifiers(withLocations(property.type === "RestElement" ? property.argument : property.value)); } break; } } collectIdentifiers(pattern); return identifiers; } function isNotReferencePosition(node, parent) { if (!parent || node.type !== "Identifier") { return false; } switch (parent.type) { case "FunctionDeclaration": case "FunctionExpression": case "ArrowFunctionExpression": if (parent.type !== "ArrowFunctionExpression" && parent.id === node) { return true; } if (parent.params.length) { for (const param of parent.params) { const identifiers = getPatternIdentifiers(withLocations(param)); if (identifiers.includes(node)) { return true; } } } return false; case "ClassDeclaration": case "ClassExpression": return parent.id === node; case "MethodDefinition": return parent.key === node; case "PropertyDefinition": return parent.key === node; case "VariableDeclarator": return getPatternIdentifiers(withLocations(parent.id)).includes(node); case "CatchClause": if (!parent.param) { return false; } return getPatternIdentifiers(withLocations(parent.param)).includes(node); case "Property": return parent.key === node && parent.value !== node; case "MemberExpression": return parent.property === node; } return false; } function getUndeclaredIdentifiersInFunction(node) { const scopeTracker = new ScopeTracker({ keepExitedScopes: true }); const undeclaredIdentifiers = /* @__PURE__ */ new Set(); function isIdentifierUndeclared(node2, parent) { return !isNotReferencePosition(node2, parent) && !scopeTracker.isDeclared(node2.name); } walk(node, { scopeTracker }); scopeTracker.freeze(); walk(node, { scopeTracker, enter(node2, parent) { if (node2.type === "Identifier" && isIdentifierUndeclared(node2, parent)) { undeclaredIdentifiers.add(node2.name); } } }); return Array.from(undeclaredIdentifiers); } function getNameFromPath(path, relativeTo) { const relativePath = relativeTo ? normalize(path).replace(withTrailingSlash(normalize(relativeTo)), "") : basename(path); const prefixParts = splitByCase(dirname(relativePath)); const fileName = basename(relativePath, extname(relativePath)); const segments = resolveComponentNameSegments(fileName.toLowerCase() === "index" ? "" : fileName, prefixParts).filter(Boolean); return kebabCase(segments).replace(QUOTE_RE, ""); } function hasSuffix(path, suffix) { return basename(path, extname(path)).endsWith(suffix); } function resolveComponentNameSegments(fileName, prefixParts) { const fileNameParts = splitByCase(fileName); const fileNamePartsContent = fileNameParts.join("/").toLowerCase(); const componentNameParts = prefixParts.flatMap((p) => splitByCase(p)); let index = prefixParts.length - 1; const matchedSuffix = []; while (index >= 0) { const prefixPart = prefixParts[index]; matchedSuffix.unshift(...splitByCase(prefixPart).map((p) => p.toLowerCase())); const matchedSuffixContent = matchedSuffix.join("/"); if (fileNamePartsContent === matchedSuffixContent || fileNamePartsContent.startsWith(matchedSuffixContent + "/") || // e.g Item/Item/Item.vue -> Item prefixPart.toLowerCase() === fileNamePartsContent && prefixParts[index + 1] && prefixParts[index] === prefixParts[index + 1]) { componentNameParts.length = index; } index--; } return [...componentNameParts, ...fileNameParts]; } function isVue(id, opts = {}) { const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href)); if (id.endsWith(".vue") && !search) { return true; } if (!search) { return false; } const query = parseQuery(search); if (query.nuxt_component) { return false; } if (query.macro && (search === "?macro=true" || !opts.type || opts.type.includes("script"))) { return true; } const type = "setup" in query ? "script" : query.type; if (!("vue" in query) || opts.type && !opts.type.includes(type)) { return false; } return true; } const JS_RE$1 = /\.(?:[cm]?j|t)sx?$/; function isJS(id) { const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)); return JS_RE$1.test(pathname); } function getLoader(id) { const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)); const ext = extname(pathname); if (ext === ".vue") { return "vue"; } if (!JS_RE$1.test(ext)) { return null; } return ext.endsWith("x") ? "tsx" : "ts"; } function matchWithStringOrRegex(value, matcher) { if (typeof matcher === "string") { return value === matcher; } else if (matcher instanceof RegExp) { return matcher.test(value); } return false; } function uniqueBy(arr, key) { if (arr.length < 2) { return arr; } const res = []; const seen = /* @__PURE__ */ new Set(); for (const item of arr) { if (seen.has(item[key])) { continue; } seen.add(item[key]); res.push(item); } return res; } const QUOTE_RE = /["']/g; const EXTENSION_RE = /\b\.\w+$/g; const SX_RE = /\.[tj]sx$/; async function resolvePagesRoutes(nuxt = useNuxt()) { const pagesDirs = nuxt.options._layers.map( (layer) => resolve(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.pages || "pages") ); const scannedFiles = []; for (const dir of pagesDirs) { const files = await resolveFiles(dir, `**/*{${nuxt.options.extensions.join(",")}}`); scannedFiles.push(...files.map((file) => ({ relativePath: relative(dir, file), absolutePath: file }))); } scannedFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath, "en-US")); const allRoutes = generateRoutesFromFiles(uniqueBy(scannedFiles, "relativePath"), { shouldUseServerComponents: !!nuxt.options.experimental.componentIslands }); const pages = uniqueBy(allRoutes, "path"); const shouldAugment = nuxt.options.experimental.scanPageMeta || nuxt.options.experimental.typedPages; if (shouldAugment === false) { await nuxt.callHook("pages:extend", pages); return pages; } const augmentCtx = { extraExtractionKeys: nuxt.options.experimental.extraPageMetaExtractionKeys, fullyResolvedPaths: new Set(scannedFiles.map((file) => file.absolutePath)) }; if (shouldAugment === "after-resolve") { await nuxt.callHook("pages:extend", pages); await augmentPages(pages, nuxt.vfs, augmentCtx); } else { const augmentedPages = await augmentPages(pages, nuxt.vfs, augmentCtx); await nuxt.callHook("pages:extend", pages); await augmentPages(pages, nuxt.vfs, { pagesToSkip: augmentedPages, ...augmentCtx }); augmentedPages?.clear(); } await nuxt.callHook("pages:resolved", pages); return pages; } const INDEX_PAGE_RE = /\/index$/; function generateRoutesFromFiles(files, options = {}) { const routes = []; for (const file of files) { const segments = file.relativePath.replace(new RegExp(`${escapeRE(extname(file.relativePath))}$`), "").split("/"); const route = { name: "", path: "", file: file.absolutePath, children: [] }; let parent = routes; const lastSegment = segments[segments.length - 1]; if (lastSegment.endsWith(".server")) { segments[segments.length - 1] = lastSegment.replace(".server", ""); if (options.shouldUseServerComponents) { route.mode = "server"; } } else if (lastSegment.endsWith(".client")) { segments[segments.length - 1] = lastSegment.replace(".client", ""); route.mode = "client"; } for (let i = 0; i < segments.length; i++) { const segment = segments[i]; const tokens = parseSegment(segment, file.absolutePath); if (tokens.every((token) => token.type === 4 /* group */)) { continue; } const segmentName = tokens.map(({ value, type }) => type === 4 /* group */ ? "" : value).join(""); route.name += (route.name && "/") + segmentName; const path = withLeadingSlash(joinURL(route.path, getRoutePath(tokens).replace(INDEX_PAGE_RE, "/"))); const child = parent.find((parentRoute) => parentRoute.name === route.name && parentRoute.path === path); if (child && child.children) { parent = child.children; route.path = ""; } else if (segmentName === "index" && !route.path) { route.path += "/"; } else if (segmentName !== "index") { route.path += getRoutePath(tokens); } } parent.push(route); } return prepareRoutes(routes); } async function augmentPages(routes, vfs, ctx = {}) { ctx.augmentedPages ??= /* @__PURE__ */ new Set(); for (const route of routes) { if (route.file && !ctx.pagesToSkip?.has(route.file)) { const fileContent = route.file in vfs ? vfs[route.file] : fs.readFileSync(ctx.fullyResolvedPaths?.has(route.file) ? route.file : await resolvePath$1(route.file), "utf-8"); const routeMeta = await getRouteMeta(fileContent, route.file, ctx.extraExtractionKeys); if (route.meta) { routeMeta.meta = { ...routeMeta.meta, ...route.meta }; } Object.assign(route, routeMeta); ctx.augmentedPages.add(route.file); } if (route.children && route.children.length > 0) { await augmentPages(route.children, vfs, ctx); } } return ctx.augmentedPages; } const SFC_SCRIPT_RE = /<script(?<attrs>[^>]*)>(?<content>[\s\S]*?)<\/script[^>]*>/gi; function extractScriptContent(sfc) { const contents = []; for (const match of sfc.matchAll(SFC_SCRIPT_RE)) { if (match?.groups?.content) { contents.push({ loader: match.groups.attrs?.includes("tsx") ? "tsx" : "ts", code: match.groups.content.trim() }); } } return contents; } const PAGE_META_RE = /definePageMeta\([\s\S]*?\)/; const defaultExtractionKeys = ["name", "path", "props", "alias", "redirect"]; const DYNAMIC_META_KEY = "__nuxt_dynamic_meta_key"; const pageContentsCache = {}; const metaCache$1 = {}; async function getRouteMeta(contents, absolutePath, extraExtractionKeys = []) { if (!(absolutePath in pageContentsCache) || pageContentsCache[absolutePath] !== contents) { pageContentsCache[absolutePath] = contents; delete metaCache$1[absolutePath]; } if (absolutePath in metaCache$1 && metaCache$1[absolutePath]) { return klona(metaCache$1[absolutePath]); } const loader = getLoader(absolutePath); const scriptBlocks = !loader ? null : loader === "vue" ? extractScriptContent(contents) : [{ code: contents, loader }]; if (!scriptBlocks) { metaCache$1[absolutePath] = {}; return {}; } const extractedMeta = {}; const extractionKeys = /* @__PURE__ */ new Set([...defaultExtractionKeys, ...extraExtractionKeys]); for (const script of scriptBlocks) { if (!PAGE_META_RE.test(script.code)) { continue; } const js = await transform(script.code, { loader: script.loader }); const dynamicProperties = /* @__PURE__ */ new Set(); let foundMeta = false; parseAndWalk(js.code, absolutePath.replace(/\.\w+$/, "." + script.loader), (node) => { if (foundMeta) { return; } if (node.type !== "ExpressionStatement" || node.expression.type !== "CallExpression" || node.expression.callee.type !== "Identifier" || node.expression.callee.name !== "definePageMeta") { return; } foundMeta = true; const pageMetaArgument = node.expression.arguments[0]; if (pageMetaArgument?.type !== "ObjectExpression") { return; } for (const key of extractionKeys) { const property = pageMetaArgument.properties.find((property2) => property2.type === "Property" && property2.key.type === "Identifier" && property2.key.name === key); if (!property) { continue; } const propertyValue = withLocations(property.value); if (propertyValue.type === "ObjectExpression") { const valueString = js.code.slice(propertyValue.start, propertyValue.end); try { extractedMeta[key] = JSON.parse(runInNewContext(`JSON.stringify(${valueString})`, {})); } catch { logger.debug(`Skipping extraction of \`${key}\` metadata as it is not JSON-serializable (reading \`${absolutePath}\`).`); dynamicProperties.add(key); continue; } } if (propertyValue.type === "ArrayExpression") { const values = []; for (const element of propertyValue.elements) { if (!element) { continue; } if (element.type !== "Literal" || typeof element.value !== "string") { logger.debug(`Skipping extraction of \`${key}\` metadata as it is not an array of string literals (reading \`${absolutePath}\`).`); dynamicProperties.add(key); continue; } values.push(element.value); } extractedMeta[key] = values; continue; } if (propertyValue.type !== "Literal" || typeof propertyValue.value !== "string" && typeof propertyValue.value !== "boolean") { logger.debug(`Skipping extraction of \`${key}\` metadata as it is not a string literal or array of string literals (reading \`${absolutePath}\`).`); dynamicProperties.add(key); continue; } extractedMeta[key] = propertyValue.value; } for (const property of pageMetaArgument.properties) { if (property.type !== "Property") { continue; } const isIdentifierOrLiteral = property.key.type === "Literal" || property.key.type === "Identifier"; if (!isIdentifierOrLiteral) { continue; } const name = property.key.type === "Identifier" ? property.key.name : String(property.value); if (!extraExtractionKeys.includes(name)) { dynamicProperties.add("meta"); break; } } if (dynamicProperties.size) { extractedMeta.meta ??= {}; extractedMeta.meta[DYNAMIC_META_KEY] = dynamicProperties; } }); } metaCache$1[absolutePath] = extractedMeta; return klona(extractedMeta); } const COLON_RE = /:/g; function getRoutePath(tokens) { return tokens.reduce((path, token) => { return path + (token.type === 2 /* optional */ ? `:${token.value}?` : token.type === 1 /* dynamic */ ? `:${token.value}()` : token.type === 3 /* catchall */ ? `:${token.value}(.*)*` : token.type === 4 /* group */ ? "" : encodePath(token.value).replace(COLON_RE, "\\:")); }, "/"); } const PARAM_CHAR_RE = /[\w.]/; function parseSegment(segment, absolutePath) { let state = 0 /* initial */; let i = 0; let buffer = ""; const tokens = []; function consumeBuffer() { if (!buffer) { return; } if (state === 0 /* initial */) { throw new Error("wrong state"); } tokens.push({ type: state === 1 /* static */ ? 0 /* static */ : state === 2 /* dynamic */ ? 1 /* dynamic */ : state === 3 /* optional */ ? 2 /* optional */ : state === 4 /* catchall */ ? 3 /* catchall */ : 4 /* group */, value: buffer }); buffer = ""; } while (i < segment.length) { const c = segment[i]; switch (state) { case 0 /* initial */: buffer = ""; if (c === "[") { state = 2 /* dynamic */; } else if (c === "(") { state = 5 /* group */; } else { i--; state = 1 /* static */; } break; case 1 /* static */: if (c === "[") { consumeBuffer(); state = 2 /* dynamic */; } else if (c === "(") { consumeBuffer(); state = 5 /* group */; } else { buffer += c; } break; case 4 /* catchall */: case 2 /* dynamic */: case 3 /* optional */: case 5 /* group */: if (buffer === "...") { buffer = ""; state = 4 /* catchall */; } if (c === "[" && state === 2 /* dynamic */) { state = 3 /* optional */; } if (c === "]" && (state !== 3 /* optional */ || segment[i - 1] === "]")) { if (!buffer) { throw new Error("Empty param"); } else { consumeBuffer(); } state = 0 /* initial */; } else if (c === ")" && state === 5 /* group */) { if (!buffer) { throw new Error("Empty group"); } else { consumeBuffer(); } state = 0 /* initial */; } else if (c && PARAM_CHAR_RE.test(c)) { buffer += c; } else if (state === 2 /* dynamic */ || state === 3 /* optional */) { if (c !== "[" && c !== "]") { logger.warn(`'\`${c}\`' is not allowed in a dynamic route parameter and has been ignored. Consider renaming \`${absolutePath}\`.`); } } break; } i++; } if (state === 2 /* dynamic */) { throw new Error(`Unfinished param "${buffer}"`); } consumeBuffer(); return tokens; } function findRouteByName(name, routes) { for (const route of routes) { if (route.name === name) { return route; } } return findRouteByName(name, routes); } const NESTED_PAGE_RE = /\//g; function prepareRoutes(routes, parent, names = /* @__PURE__ */ new Set()) { for (const route of routes) { if (route.name) { route.name = route.name.replace(INDEX_PAGE_RE, "").replace(NESTED_PAGE_RE, "-"); if (names.has(route.name)) { const existingRoute = findRouteByName(route.name, routes); const extra = existingRoute?.name ? `is the same as \`${existingRoute.file}\`` : "is a duplicate"; logger.warn(`Route name generated for \`${route.file}\` ${extra}. You may wish to set a custom name using \`definePageMeta\` within the page file.`); } } if (parent && route.path[0] === "/") { route.path = route.path.slice(1); } if (route.children?.length) { route.children = prepareRoutes(route.children, route, names); } if (route.children?.find((childRoute) => childRoute.path === "")) { delete route.name; } if (route.name) { names.add(route.name); } } return routes; } function serializeRouteValue(value, skipSerialisation = false) { if (skipSerialisation || value === undefined) { return undefined; } return JSON.stringify(value); } function normalizeRoutes(routes, metaImports = /* @__PURE__ */ new Set(), options) { return { imports: metaImports, routes: genArrayFromRaw(routes.map((page) => { const markedDynamic = page.meta?.[DYNAMIC_META_KEY] ?? /* @__PURE__ */ new Set(); const metaFiltered = {}; let skipMeta = true; for (const key in page.meta || {}) { if (key !== DYNAMIC_META_KEY && page.meta[key] !== undefined) { skipMeta = false; metaFiltered[key] = page.meta[key]; } } const skipAlias = toArray(page.alias).every((val) => !val); const route = { path: serializeRouteValue(page.path), props: serializeRouteValue(page.props), name: serializeRouteValue(page.name), meta: serializeRouteValue(metaFiltered, skipMeta), alias: serializeRouteValue(toArray(page.alias), skipAlias), redirect: serializeRouteValue(page.redirect) }; for (const key of ["path", "props", "name", "meta", "alias", "redirect"]) { if (route[key] === undefined) { delete route[key]; } } if (page.children?.length) { route.children = normalizeRoutes(page.children, metaImports, options).routes; } if (!page.file) { return route; } const file = normalize(page.file); const pageImportName = genSafeVariableName(filename(file) + hash(file)); const metaImportName = pageImportName + "Meta"; metaImports.add(genImport(`${file}?macro=true`, [{ name: "default", as: metaImportName }])); if (page._sync) { metaImports.add(genImport(file, [{ name: "default", as: pageImportName }])); } const pageImport = page._sync && page.mode !== "client" ? pageImportName : genDynamicImport(file); const metaRoute = { name: `${metaImportName}?.name ?? ${route.name}`, path: `${metaImportName}?.path ?? ${route.path}`, props: `${metaImportName}?.props ?? ${route.props ?? false}`, meta: `${metaImportName} || {}`, alias: `${metaImportName}?.alias || []`, redirect: `${metaImportName}?.redirect`, component: page.mode === "server" ? `() => createIslandPage(${route.name})` : page.mode === "client" ? `() => createClientPage(${pageImport})` : pageImport }; if (page.mode === "server") { metaImports.add(` let _createIslandPage async function createIslandPage (name) { _createIslandPage ||= await import(${JSON.stringify(options?.serverComponentRuntime)}).then(r => r.createIslandPage) return _createIslandPage(name) };`); } else if (page.mode === "client") { metaImports.add(` let _createClientPage async function createClientPage(loader) { _createClientPage ||= await import(${JSON.stringify(options?.clientComponentRuntime)}).then(r => r.createClientPage) return _createClientPage(loader); }`); } if (route.children) { metaRoute.children = route.children; } if (route.meta) { metaRoute.meta = `{ ...(${metaImportName} || {}), ...${route.meta} }`; } if (options?.overrideMeta) { for (const key of ["name", "path"]) { if (markedDynamic.has(key)) { continue; } metaRoute[key] = route[key] ?? `${metaImportName}?.${key}`; } for (const key of ["meta", "alias", "redirect", "props"]) { if (markedDynamic.has(key)) { continue; } if (route[key] == null) { delete metaRoute[key]; continue; } metaRoute[key] = route[key]; } } else { if (route.alias != null) { metaRoute.alias = `${route.alias}.concat(${metaImportName}?.alias || [])`; } if (route.redirect != null) { metaRoute.redirect = route.redirect; } } return metaRoute; })) }; } const PATH_TO_NITRO_GLOB_RE = /\/[^:/]*:\w.*$/; function pathToNitroGlob(path) { if (!path) { return null; } if (path.indexOf(":") !== path.lastIndexOf(":")) { return null; } return path.replace(PATH_TO_NITRO_GLOB_RE, "/**"); } function resolveRoutePaths(page, parent = "/") { return [ joinURL(parent, page.path), ...page.children?.flatMap((child) => resolveRoutePaths(child, joinURL(parent, page.path))) || [] ]; } const ROUTE_RULE_RE = /\bdefineRouteRules\(/; const ruleCache = {}; async function extractRouteRules(code, path) { if (code in ruleCache) { return ruleCache[code] || null; } if (!ROUTE_RULE_RE.test(code)) { return null; } let rule = null; const loader = getLoader(path); if (!loader) { return null; } const contents = loader === "vue" ? extractScriptContent(code) : [{ code, loader }]; for (const script of contents) { if (rule) { break; } code = script?.code || code; const js = await transform(code, { loader: script?.loader || "ts" }); parseAndWalk(js.code, "file." + (script?.loader || "ts"), (node) => { if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } if (node.callee.name === "defineRouteRules") { const rulesString = js.code.slice(node.start, node.end); try { rule = JSON.parse(runInNewContext(rulesString.replace("defineRouteRules", "JSON.stringify"), {})); } catch { throw new Error("[nuxt] Error parsing route rules. They should be JSON-serializable."); } } }); } ruleCache[code] = rule; return rule; } function getMappedPages(pages, paths = {}, prefix = "") { for (const page of pages) { if (page.file) { const filename = normalize(page.file); paths[filename] = pathToNitroGlob(prefix + page.path); } if (page.children) { getMappedPages(page.children, paths, page.path + "/"); } } return paths; } const HAS_MACRO_RE = /\bdefinePageMeta\s*\(\s*/; const CODE_EMPTY = ` const __nuxt_page_meta = null export default __nuxt_page_meta `; const CODE_DEV_EMPTY = ` const __nuxt_page_meta = {} export default __nuxt_page_meta `; const CODE_HMR = ` // Vite if (import.meta.hot) { import.meta.hot.accept(mod => { Object.assign(__nuxt_page_meta, mod) }) } // webpack if (import.meta.webpackHot) { import.meta.webpackHot.accept((err) => { if (err) { window.location = window.location.href } }) }`; const PageMetaPlugin = (options = {}) => createUnplugin(() => { return { name: "nuxt:pages-macros-transform", enforce: "post", transformInclude(id) { return !!parseMacroQuery(id).macro; }, transform(code, id) { const query = parseMacroQuery(id); if (query.type && query.type !== "script") { return; } const s = new MagicString(code); function result() { if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } const hasMacro = HAS_MACRO_RE.test(code); const imports = findStaticImports(code); const scriptImport = imports.find((i) => parseMacroQuery(i.specifier).type === "script"); if (scriptImport) { const reorderedQuery = rewriteQuery(scriptImport.specifier); const quotedSpecifier = getQuotedSpecifier(scriptImport.code)?.replace(scriptImport.specifier, reorderedQuery) ?? JSON.stringify(reorderedQuery); s.overwrite(0, code.length, `export { default } from ${quotedSpecifier}`); return result(); } const currentExports = findExports(code); for (const match of currentExports) { if (match.type !== "default" || !match.specifier) { continue; } const reorderedQuery = rewriteQuery(match.specifier); const quotedSpecifier = getQuotedSpecifier(match.code)?.replace(match.specifier, reorderedQuery) ?? JSON.stringify(reorderedQuery); s.overwrite(0, code.length, `export { default } from ${quotedSpecifier}`); return result(); } if (!hasMacro && !code.includes("export { default }") && !code.includes("__nuxt_page_meta")) { if (!code) { s.append(options.dev ? CODE_DEV_EMPTY + CODE_HMR : CODE_EMPTY); const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)); logger.error(`The file \`${pathname}\` is not a valid page as it has no content.`); } else { s.overwrite(0, code.length, options.dev ? CODE_DEV_EMPTY + CODE_HMR : CODE_EMPTY); } return result(); } const importMap = /* @__PURE__ */ new Map(); const addedImports = /* @__PURE__ */ new Set(); for (const i of imports) { const parsed = parseStaticImport(i); for (const name of [ parsed.defaultImport, ...Object.values(parsed.namedImports || {}), parsed.namespacedImport ].filter(Boolean)) { importMap.set(name, i); } } function isStaticIdentifier(name) { return !!(name && importMap.has(name)); } function addImport(name) { if (!isStaticIdentifier(name)) { return; } const importValue = importMap.get(name).code.trim(); if (!addedImports.has(importValue)) { addedImports.add(importValue); } } const declarationNodes = []; const addedDeclarations = /* @__PURE__ */ new Set(); function addDeclaration(node) { const codeSectionKey = `${node.start}-${node.end}`; if (addedDeclarations.has(codeSectionKey)) { return; } addedDeclarations.add(codeSectionKey); declarationNodes.push(node); } function addImportOrDeclaration(name, node) { if (isStaticIdentifier(name)) { addImport(name); } else { const declaration = scopeTracker.getDeclaration(name); if (declaration && declaration !== node) { processDeclaration(declaration); } } } const scopeTracker = new ScopeTracker({ keepExitedScopes: true }); function processDeclaration(scopeTrackerNode) { if (scopeTrackerNode?.type === "Variable") { addDeclaration(scopeTrackerNode); for (const decl of scopeTrackerNode.variableNode.declarations) { if (!decl.init) { continue; } walk(decl.init, { enter: (node, parent) => { if (node.type === "AwaitExpression") { logger.error(`Await expressions are not supported in definePageMeta. File: '${id}'`); throw new Error("await in definePageMeta"); } if (isNotReferencePosition(node, parent) || node.type !== "Identifier") { return; } addImportOrDeclaration(node.name, scopeTrackerNode); } }); } } else if (scopeTrackerNode?.type === "Function") { if (scopeTrackerNode.node.type === "ArrowFunctionExpression") { return; } const name = scopeTrackerNode.node.id?.name; if (!name) { return; } addDeclaration(scopeTrackerNode); const undeclaredIdentifiers = getUndeclaredIdentifiersInFunction(scopeTrackerNode.node); for (const name2 of undeclaredIdentifiers) { addImportOrDeclaration(name2); } } } const ast = parseAndWalk(code, id, { scopeTracker }); scopeTracker.freeze(); walk(ast, { scopeTracker, enter: (node) => { if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } if (!("name" in node.callee) || node.callee.name !== "definePageMeta") { return; } const meta = withLocations(node.arguments[0]); if (!meta) { return; } const definePageMetaScope = scopeTracker.getCurrentScope(); walk(meta, { scopeTracker, enter(node2, parent) { if (isNotReferencePosition(node2, parent) || node2.type !== "Identifier") { return; } const declaration = scopeTracker.getDeclaration(node2.name); if (declaration) { if (declaration.isUnderScope(definePageMetaScope) && (scopeTracker.isCurrentScopeUnder(declaration.scope) || declaration.start < node2.start)) { return; } } if (isStaticIdentifier(node2.name)) { addImport(node2.name); } else if (declaration) { processDeclaration(declaration); } } }); const importStatements = Array.from(addedImports).join("\n"); const declarations = declarationNodes.sort((a, b) => a.start - b.start).map((node2) => code.slice(node2.start, node2.end)).join("\n"); const extracted = [ importStatements, declarations, `const __nuxt_page_meta = ${code.slice(meta.start, meta.end) || "null"} export default __nuxt_page_meta` + (options.dev ? CODE_HMR : "") ].join("\n"); s.overwrite(0, code.length, extracted.trim()); } }); if (!s.hasChanged() && !code.includes("__nuxt_page_meta")) { s.overwrite(0, code.length, options.dev ? CODE_DEV_EMPTY + CODE_HMR : CODE_EMPTY); } return result(); }, vite: { handleHotUpdate: { order: "post", handler: ({ file, modules, server }) => { if (options.routesPath && options.isPage?.(file)) { const macroModule = server.moduleGraph.getModuleById(file + "?macro=true"); const routesModule = server.moduleGraph.getModuleById("virtual:nuxt:" + encodeURIComponent(options.routesPath)); return [ ...modules, ...macroModule ? [macroModule] : [], ...routesModule ? [routesModule] : [] ]; } } } } }; }); const QUERY_START_RE = /^\?/; const MACRO_RE = /¯o=true/; function rewriteQuery(id) { return id.replace(/\?.+$/, (r) => "?macro=true&" + r.replace(QUERY_START_RE, "").replace(MACRO_RE, "")); } function parseMacroQuery(id) { const { search } = parseURL(decodeURIComponent(isAbsolute(id) ? pathToFileURL(id).href : id).replace(/\?macro=true$/, "")); const query = parseQuery(search); if (id.includes("?macro=true")) { return { macro: "true", ...query }; } return query; } const QUOTED_SPECIFIER_RE = /(["']).*\1/; function getQuotedSpecifier(id) { return id.match(QUOTED_SPECIFIER_RE)?.[0]; } const INJECTION_RE_TEMPLATE = /\b_ctx\.\$route\b/g; const INJECTION_RE_SCRIPT = /\bthis\.\$route\b/g; const INJECTION_SINGLE_RE = /\bthis\.\$route\b|\b_ctx\.\$route\b/; const RouteInjectionPlugin = (nuxt) => createUnplugin(() => { return { name: "nuxt:route-injection-plugin", enforce: "post", transformInclude(id) { return isVue(id, { type: ["template", "script"] }); }, transform(code) { if (!INJECTION_SINGLE_RE.test(code) || code.includes("_ctx._.provides[__nuxt_route_symbol") || code.includes("this._.provides[__nuxt_route_symbol")) { return; } let replaced = false; const s = new MagicString(code); const strippedCode = stripLiteral(code); const replaceMatches = (regExp, replacement) => { for (const match of strippedCode.matchAll(regExp)) { const start = match.index; const end = start + match[0].length; s.overwrite(start, end, replacement); if (!replaced) { replaced = true; } } }; replaceMatches(INJECTION_RE_TEMPLATE, "(_ctx._.provides[__nuxt_route_symbol] || _ctx.$route)"); replaceMatches(INJECTION_RE_SCRIPT, "(this._.provides[__nuxt_route_symbol] || this.$route)"); if (replaced) { s.prepend("import { PageRouteSymbol as __nuxt_route_symbol } from '#app/components/injections';\n"); } if (s.hasChanged()) { return { code: s.toString(), map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : undefined }; } } }; }); const OPTIONAL_PARAM_RE = /^\/?:.*(?:\?|\(\.\*\)\*)$/; const pagesModule = defineNuxtModule({ meta: { name: "nuxt:pages", configKey: "pages" }, async setup(_options, nuxt) { const useExperimentalTypedPages = nuxt.options.experimental.typedPages; const runtimeDir = resolve(distDir, "pages/runtime"); const pagesDirs = nuxt.options._layers.map( (layer) => resolve(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.pages || "pages") ); nuxt.options.alias["#vue-router"] = "vue-router"; const routerPath = await resolveTypePath("vue-router", "", nuxt.options.modulesDir) || "vue-router"; nuxt.hook("prepare:types", ({ tsConfig }) => { tsConfig.compilerOptions ||= {}; tsConfig.compilerOptions.paths ||= {}; tsConfig.compilerOptions.paths["#vue-router"] = [routerPath]; delete tsConfig.compilerOptions.paths["#vue-router/*"]; }); const builtInRouterOptions = await findPath(resolve(runtimeDir, "router.options")) || resolve(runtimeDir, "router.options"); async function resolveRouterOptions() { const context = { files: [] }; for (const layer of nuxt.options._layers) { const path = await findPath(resolve(layer.config.srcDir, layer.config.dir?.app || "app", "router.options")); if (path) { context.files.unshift({ path }); } } context.files.unshift({ path: builtInRouterOptions, optional: true }); await nuxt.callHook("pages:routerOptions", context); return context.files; } const isNonEmptyDir = (dir) => existsSync(dir) && readdirSync(dir).length; const userPreference = nuxt.options.pages; const isPagesEnabled = async () => { if (typeof userPreference === "boolean") { return userPreference; } const routerOptionsFiles = await resolveRouterOptions(); if (routerOptionsFiles.filter((p) => !p.optional).length > 0) { return true; } if (pagesDirs.some((dir) => isNonEmptyDir(dir))) { return true; } const pages = await resolvePagesRoutes(nuxt); if (pages.length) { if (nuxt.apps.default) { nuxt.apps.default.pages = pages; } return true; } return false; }; nuxt.options.pages = await isPagesEnabled(); if (nuxt.options.dev && nuxt.options.pages) { addPlugin(resolve(runtimeDir, "plugins/check-if-page-unused")); } nuxt.hook("app:templates", (app) => { if (!nuxt.options.ssr && app.pages?.some((p) => p.mode === "server")) { logger.warn("Using server pages with `ssr: false` is not supported with auto-detected component islands. Set `experimental.componentIslands` to `true`."); } }); const restartPaths = nuxt.options._layers.flatMap((layer) => { const pagesDir = (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.pages || "pages"; return [ resolve(layer.config.srcDir || layer.cwd, layer.config.dir?.app || "app", "router.options.ts"), resolve(layer.config.srcDir || layer.cwd, pagesDir) ]; }); nuxt.hooks.hook("builder:watch", async (event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (restartPaths.some((p) => p === path || path.startsWith(p + "/"))) { const newSetting = await isPagesEnabled(); if (nuxt.options.pages !== newSetting) { logger.info("Pages", newSetting ? "enabled" : "disabled"); return nuxt.callHook("restart"); } } }); if (!nuxt.options.pages) { addPlugin(resolve(distDir, "app/plugins/router")); addTemplate({ filename: "pages.mjs", getContents: () => [ "export { useRoute } from '#app/composables/router'", "export const START_LOCATION = Symbol('router:start-location')" ].join("\n") }); addTemplate({ filename: "router.options.mjs", getContents: () => { return [ "export const hashMode = false", "export default {}" ].join("\n"); } }); addTypeTemplate({ filename: "types/middleware.d.ts", getContents: () => [ "declare module 'nitropack' {", " interface NitroRouteConfig {", " appMiddleware?: string | string[] | Record<string, boolean>", " }", "}", "export {}" ].join("\n") }); addComponent({ name: "NuxtPage", priority: 10, // built-in that we do not expect the user to override filePath: resolve(distDir, "pages/runtime/page-placeholder") }); nuxt.hook("nitro:init", (nitro) => { if (nuxt.options.dev || !nuxt.options.ssr || !nitro.options.static || !nitro.options.prerender.crawlLinks) { return; } nitro.options.prerender.routes.push("/"); }); return; } if (useExperimentalTypedPages) { const declarationFile = "./types/typed-router.d.ts"; const options = { routesFolder: [], dts: resolve(nuxt.options.buildDir, declarationFile), logs: nuxt.options.debug, async beforeWriteFiles(rootPage) { rootPage.children.forEach((child) => child.delete()); const pages = nuxt.apps.default?.pages || await resolvePagesRoutes(nuxt); if (nuxt.apps.default) { nuxt.apps.default.pages = pages; } const addedPagePaths = /* @__PURE__ */ new Set(); function addPage(parent, page) { const absolutePagePath = joinURL(parent.path, page.path); const route = addedPagePaths.has(absolutePagePath) ? parent : parent.insert(page.path, page.file); addedPagePaths.add(absolutePagePath); if (page.meta) { route.addToMeta(page.meta); } if (page.alias) { route.addAlias(page.alias); } if (page.name) { route.name = page.name; } if (page.children) { page.children.forEach((child) => addPage(route, child)); } } for (const page of pages) { addPage(rootPage, page); } } }; nuxt.hook("prepare:types", ({ references }) => { references.push({ path: declarationFile }); references.push({ types: "unplugin-vue-router/client" }); }); const context = createRoutesContext(resolveOptions(options)); const dtsFile = resolve(nuxt.options.buildDir, declarationFile); await mkdir(dirname(dtsFile), { recursive: true }); await context.scanPages(false); if (nuxt.options._prepare || !nuxt.options.dev) { const dts = await readFile(dtsFile, "utf-8"); addTemplate({ filename: "types/typed-router.d.ts", getContents: () => dts }); } nuxt.hook("app:templatesGenerated", async (_app, _templates, options2) => { if (!options2?.filter || options2.filter({ filename: "routes.mjs" })) { await context.scanPages(); } }); } nuxt.hook("prepare:types", ({ references }) => { references.push({ types: useExperimentalTypedPages ? "vue-router/auto-routes" : "vue-router" }); }); nuxt.hook("imports:sources", (sources) => { const routerImports = sources.find((s) => s.from === "#app/composables/router" && s.imports.includes("onBeforeRouteLeave")); if (routerImports) { routerImports.from = "vue-router"; } }); const updateTemplatePaths = nuxt.options._layers.flatMap((l) => { const dir = (l.config.rootDir === nuxt.options.rootDir ? nuxt.options : l.config).dir; return [ resolve(l.config.srcDir || l.cwd, dir?.pages || "pages") + "/", resolve(l.config.srcDir || l.cwd, dir?.layouts || "layouts") + "/", resolve(l.config.srcDir || l.cwd, dir?.middleware || "middleware") + "/" ]; }); function isPage(file, pages = nuxt.apps.default?.pages) { if (!pages) { return false; } return pages.some((page) => page.file === file) || pages.some((page) => page.children && isPage(file, page.children)); } nuxt.hooks.hookOnce("app:templates", async (app) => { if (!app.pages) { app.pages = await resolvePagesRoutes(nuxt); } }); nuxt.hook("builder:watch", async (event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); const shouldAlwaysRegenerate = nuxt.options.experimental.scanPageMeta && isPage(path); if (event === "change" && !shouldAlwaysRegenerate) { return; } if (shouldAlwaysRegenerate || updateTemplatePaths.some((dir) => path.startsWith(dir))) { nuxt.apps.default.pages = await resolvePagesRoutes(nuxt); } }); nuxt.hook("app:resolve", (app) => { if (app.mainComponent === resolve(nuxt.options.appDir, "components/welcome.vue")) { app.mainComponent = resolve(runtimeDir, "app.vue"); } app.middleware.unshift({ name: "validate", path: resolve(runtimeDir, "validate"), global: true }); }); nuxt.hook("app:resolve", (app) => { const nitro = useNitro(); if (nitro.options.prerender.crawlLinks || Object.values(nitro.options.routeRules).some((rule) => rule.prerender)) { app.plugins.push({ src: resolve(runtimeDir, "plugins/prerender.server"), mode: "server" }); } }); const prerenderRoutes = /* @__PURE__ */ new Set(); function processPages(pages, currentPath = "/") { for (const page of pages) { if (OPTIONAL_PARAM_RE.test(page.path) && !page.children?.length) { prerenderRoutes.add(currentPath); } if (page.path.includes(":")) { continue; } const route = joinURL(currentPath, page.path); prerenderRoutes.add(route); if (page.children) { processPages(page.children, route); } } } nuxt.hook("pages:extend", (pages) => { if (nuxt.options.dev) { return; } prerenderRoutes.clear(); processPages(pages); }); nuxt.hook("nitro:build:before", (nitro) => { if (nuxt.options.dev || nuxt.options.router.options.hashMode) { return; } if (!nitro.options.static && !nitro.options.prerender.crawlLinks) { const routeRulesMatcher = toRouteMatcher(createRouter({ routes: nitro.options.routeRules })); for (const route of prerenderRoutes) { const rules = defu({}, ...routeRulesMatcher.matchAll(route).reverse()); if (rules.prerender) { nitro.options.prerender.routes.push(route); } } } if (!nitro.options.static || !nitro.options.prerender.crawlLinks) { return; } if (nuxt.options.ssr) { const [firstPage] = [...prerenderRoutes].sort(); nitro.options.prerender.routes.push(firstPage || "/"); return; } for (const route of nitro.options.prerender.routes || []) { prerenderRoutes.add(route); } nitro.options.prerender.routes = Array.from(prerenderRoutes); }); nuxt.hook("imports:extend", (imports) => { imports.push( { name: "definePageMeta", as: "definePageMeta", from: resolve(runtimeDir, "composables") }, { name: "useLink", as: "useLink", from: "vue-router" } ); if (nuxt.options.experimental.inlineRouteRules) { imports.push({ name: "defineRouteRules", as: "defineRouteRules", from: resolve(runtimeDir, "composables") }); } }); if (nuxt.options.experimental.inlineRouteRules) { let pageToGlobMap = {}; nuxt.hook("pages:extend", (pages) => { pageToGlobMap = getMappedPages(pages); }); const inlineRules = {}; let updateRouteConfig; nuxt.hook("nitro:init", (nitro) => { updateRouteConfig = () => nitro.updateConfig({ routeRules: defu(inlineRules, nitro.options._config.routeRules) }); }); const updatePage = async function updatePage2(path) { const glob = pageToGlobMap[path]; const code = path in nuxt.vfs ? nuxt.vfs[path] : await readFile(path, "utf-8"); try { const extractedRule = await extractRouteRules(code, path); if (extractedRule) { if (!glob) { const relativePath = relative(nuxt.options.srcDir, path); logger.error(`Could not set inline route rules in \`~/${relativePath}\` as it could not be mapped to a Nitro route.`); return; } inlineRules[glob] = extractedRule; } else if (glob) { delete inlineRules[glob]; } } catch (e) { if (e.toString().includes("Error parsing route rules")) { const relativePath = relative(nuxt.options.srcDir, path); logger.error(`Error parsing route rules within \`~/${relativePath}\`. They should be JSON-serializable.`); } else { logger.error(e); } } }; nuxt.hook("builder:watch", async (event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (!(path in pageToGlobMap)) { return; } if (event === "unlink") { delete inlineRules[path]; delete pageToGlobMap[path]; } else { await updatePage(path); } await updateRouteConfig?.(); }); nuxt.hooks.hookOnce("pages:extend", async () => { for (const page in pageToGlobMap) { await updatePage(page); } await updateRouteConfig?.(); }); } const componentStubPath = await resolvePath$1(resolve(runtimeDir, "component-stub")); if (nuxt.options.test && nuxt.options.dev) { nuxt.hook("pages:extend", (routes) => { routes.push({ _sync: true, path: "/__nuxt_component_test__/:pathMatch(.*)", file: componentStubPath }); }); } if (nuxt.options.experimental.appManifest) { nuxt.hook("pages:extend", (routes) => { const nitro = useNitro(); let resolvedRoutes; for (const [path, rule] of Object.entries(nitro.options.routeRules)) { if (!rule.redirect) { continue; } resolvedRoutes ||= routes.flatMap((route) => resolveRoutePaths(route)); if (resolvedRoutes.includes(path)) { continue; } routes.push({ _sync: true, path: path.replace(/\/[^/]*\*\*/, "/:pathMatch(.*)"), file: componentStubPath }); } }); } nuxt.hook("modules:done", () => { addBuildPlugin(PageMetaPlugin({ dev: nuxt.options.dev, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, isPage, routesPath: resolve(nuxt.options.buildDir, "routes.mjs") })); }); addPlugin(resolve(runtimeDir, "plugins/prefetch.client")); if (nuxt.options.experimental.templateRouteInjection) { addBuildPlugin(RouteInjectionPlugin(nuxt), { server: false }); } addPlugin(resolve(runtimeDir, "plugins/router")); const getSources = (pages) => pages.filter((p) => Boolean(p.file)).flatMap( (p) => [relative(nuxt.options.srcDir, p.file), ...p.children?.length ? getSources(p.children) : []] ); nuxt.hook("build:manifest", (manifest) => { if (nuxt.options.dev) { return; } const sourceFiles = nuxt.apps.default?.pages?.length ? getSources(nuxt.apps.default.pages) : []; for (const [key, chunk] of Object.entries(manifest)) { if (chunk.src && Object.values(nuxt.apps).some((app) => app.pages?.some((page) => page.mode === "server" && page.file === join(nuxt.options.srcDir, chunk.src)))) { delete manifest[key]; continue; } if (chunk.isEntry) { chunk.dynamicImports = chunk.dynamicImports?.filter((i) => !sourceFiles.includes(i)); } } }); const serverComponentRuntime = await findPath(join(distDir, "components/runtime/server-component")) ?? join(distDir, "components/runtime/server-component"); const clientComponentRuntime = await findPath(join(distDir, "components/runtime/client-component")) ?? join(distDir, "components/runtime/client-component"); addTemplate({ filename: "routes.mjs", getContents({ app }) { if (!app.pages) { return ROUTES_HMR_CODE + "export default []"; } const { routes, imports } = normalizeRoutes(app.pages, /* @__PURE__ */ new Set(), { serverComponentRuntime, clientComponentRuntime, overrideMeta: !!nuxt.options.experimental.scanPageMeta }); return ROUTES_HMR_CODE + [...imports, `export default ${routes}`].join("\n"); } }); addTemplate({ filename: "pages.mjs", getContents: () => "export { START_LOCATION, useRoute } from 'vue-router'" }); nuxt.options.vite.resolve ||= {}; nuxt.options.vite.resolve.dedupe ||= []; nuxt.options.vite.resolve.dedupe.push("vue-router"); addTemplate({ filename: "router.options.mjs", getContents: async () => { const routerOptionsFiles = await resolveRouterOptions(); const configRouterOptions = genObjectFromRawEntries(Object.entries(nuxt.options.router.options).map(([key, value]) => [key, genString(value)])); return [ ...routerOptionsFiles.map((file, index) => genImport(file.path, `routerOptions${index}`)), `const configRouterOptions = ${configRouterOptions}`, `export const hashMode = ${[...routerOptionsFiles.filter((o) => o.path !== builtInRouterOptions).map((_, index) => `routerOptions${index}.hashMode`).reverse(), nuxt.options.router.options.hashMode].join(" ?? ")}`, "export default {", "...configRouterOptions,", ...routerOptionsFiles.map((_, index) => `...routerOptions${index},`), "}" ].join("\n"); } }); addTypeTemplate({ filename: "types/middleware.d.ts", getContents: ({ nuxt: nuxt2, app }) => { const composablesFile = relative(join(nuxt2.options.buildDir, "types"), resolve(runtimeDir, "composables")); const namedMiddleware = app.middleware.filter((mw) => !mw.global); return [ "import type { NavigationGuard } from 'vue-router'", `export type MiddlewareKey = ${namedMiddleware.map((mw) => genString(mw.name)).join(" | ") || "never"}`, `declare module ${genString(composablesFile)} {`, " interface PageMeta {", " middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>", " }", "}", "declare module 'nitropack' {", " interface NitroRouteConfig {", " appMiddleware?: MiddlewareKey | MiddlewareKey[] | Record<MiddlewareKey, boolean>", " }", "}" ].join("\n"); } }); addTypeTemplate({ filename: "types/layouts.d.ts", getContents: ({ nuxt: nuxt2, app }) => { const composablesFile = relative(join(nuxt2.options.buildDir, "types"), resolve(runtimeDir, "composables")); return [ "import type { ComputedRef, MaybeRef } from 'vue'", `export type LayoutKey = ${Object.keys(app.layouts).map((name) => genString(name)).join(" | ") || "string"}`, `declare module ${genString(composablesFile)} {`, " interface PageMeta {", " layout?: MaybeRef<LayoutKey | false> | ComputedRef<LayoutKey | false>", " }", "}" ].join("\n"); } }); if (nuxt.options.experimental.viewTransition) { addTypeTemplate({ filename: "types/view-transitions.d.ts", getContents: ({ nuxt: nuxt2 }) => { const runtimeDir2 = resolve(distDir, "pages/runtime"); const composablesFile = relative(join(nuxt2.options.buildDir, "types"), resolve(runtimeDir2, "composables")); return [ "import type { ComputedRef, MaybeRef } from 'vue'", `declare module ${genString(composablesFile)} {`, " interface PageMeta {", " viewTransition?: boolean | 'always'", " }", "}" ].join("\n"); } }); } addComponent({ name: "NuxtPage", priority: 10, // built-in that we do not expect the user to override filePath: resolve(distDir, "pages/runtime/page") }); } }); const ROUTES_HMR_CODE = ( /* js */ ` if (import.meta.hot) { import.meta.hot.accept((mod) => { const router = import.meta.hot.data.router const generateRoutes = import.meta.hot.data.generateRoutes if (!router || !generateRoutes) { import.meta.hot.invalidate('[nuxt] Cannot replace routes because there is no active router. Reloading.') return } router.clearRoutes() const routes = generateRoutes(mod.default || mod) function addRoutes (routes) { for (const route of routes) { router.addRoute(route) } router.replace(router.currentRoute.value.fullPath) } if (routes && 'then' in routes) { routes.then(addRoutes) } else { addRoutes(routes) } }) } export function handleHotUpdate(_router, _generateRoutes) { if (import.meta.hot) { import.meta.hot.data ||= {} import.meta.hot.data.router = _router import.meta.hot.data.generateRoutes = _generateRoutes } } ` ); const components = ["NoScript", "Link", "Base", "Title", "Meta", "Style", "Head", "Html", "Body"]; const metaModule = defineNuxtModule({ meta: { name: "nuxt:meta", configKey: "unhead" }, async setup(options, nuxt) { const runtimeDir = resolve(distDir, "head/runtime"); nuxt.options.build.transpile.push("@unhead/vue"); const componentsPath = resolve(runtimeDir, "components"); for (const componentName of components) { addComponent({ name: componentName, filePath: componentsPath, export: componentName, // built-in that we do not expect the user to override priority: 10, // kebab case version of these tags is not valid kebabName: componentName }); } if (!nuxt.options.dev) { nuxt.options.optimization.treeShake.composables.client["@unhead/vue"] = [ "useServerHead", "useServerSeoMeta", "useServerHeadSafe" ]; } addImportsSources({ from: "@unhead/vue", // hard-coded for now we so don't support auto-imports on the deprecated composables imports: [ "injectHead", "useHead", "useSeoMeta", "useHeadSafe", "useServerHead", "useServerSeoMeta", "useServerHeadSafe" ] }); const unheadVue = await tryResolveModule("@unhead/vue", nuxt.options.modulesDir) || "@unhead/vue"; if (nuxt.options.experimental.polyfillVueUseHead) { nuxt.options.alias["@vueuse/head"] = unheadVue; addPlugin({ src: resolve(runtimeDir, "plugins/vueuse-head-polyfill") }); } addTemplate({ filename: "unhead-plugins.mjs", getContents() { if (!nuxt.options.experimental.headNext) { return "export default []"; } return `import { CapoPlugin } from ${JSON.stringify(unheadVue)}; export default import.meta.server ? [CapoPlugin({ track: true })] : [];`; } }); addTemplate({ filename: "unhead.config.mjs", getContents() { return [ `export const renderSSRHeadOptions = ${JSON.stringify(options.renderSSRHeadOptions || {})}` ].join("\n"); } }); nuxt.hooks.hook("nitro:config", (config) => { config.virtual["#internal/unhead-plugins.mjs"] = () => nuxt.vfs["#build/unhead-plugins.mjs"]; config.virtual["#internal/unhead.config.mjs"] = () => nuxt.vfs["#build/unhead.config.mjs"]; }); addPlugin({ src: resolve(runtimeDir, "plugins/unhead") }); } }); const createImportMagicComments = (options) => { const { chunkName, prefetch, preload } = options; return [ `webpackChunkName: "${chunkName}"`, prefetch === true || typeof prefetch === "number" ? `webpackPrefetch: ${prefetch}` : false, preload === true || typeof preload === "number" ? `webpackPreload: ${preload}` : false ].filter(Boolean).join(", "); }; const emptyComponentsPlugin = ` import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:global-components', }) `; const componentsPluginTemplate = { filename: "components.plugin.mjs", getContents({ app }) { const lazyGlobalComponents = /* @__PURE__ */ new Set(); const syncGlobalComponents = /* @__PURE__ */ new Set(); for (const component of app.components) { if (component.global === "sync") { syncGlobalComponents.add(component.pascalName); } else if (component.global) { lazyGlobalComponents.add(component.pascalName); } } if (!lazyGlobalComponents.size && !syncGlobalComponents.size) { return emptyComponentsPlugin; } const lazyComponents = [...lazyGlobalComponents]; const syncComponents = [...syncGlobalComponents]; return `import { defineNuxtPlugin } from '#app/nuxt' import { ${[...lazyComponents.map((c) => "Lazy" + c), ...syncComponents].join(", ")} } from '#components' const lazyGlobalComponents = [ ${lazyComponents.map((c) => `["${c}", Lazy${c}]`).join(",\n")}, ${syncComponents.map((c) => `["${c}", ${c}]`).join(",\n")} ] export default defineNuxtPlugin({ name: 'nuxt:global-components', setup (nuxtApp) { for (const [name, component] of lazyGlobalComponents) { nuxtApp.vueApp.component(name, component) nuxtApp.vueApp.component('Lazy' + name, component) } } }) `; } }; const componentNamesTemplate = { filename: "component-names.mjs", getContents({ app }) { return `export const componentNames = ${JSON.stringify(app.components.filter((c) => !c.island).map((c) => c.pascalName))}`; } }; const componentsIslandsTemplate = { // components.islands.mjs' getContents({ app, nuxt }) { if (!nuxt.options.experimental.componentIslands) { return "export const islandComponents = {}"; } const components = app.components; const pages = app.pages; const islands = components.filter( (component) => component.island || // .server components without a corresponding .client component will need to be rendered as an island component.mode === "server" && !components.some((c) => c.pascalName === component.pascalName && c.mode === "client") ); const pageExports = pages?.filter((p) => p.mode === "server" && p.file && p.name).map((p) => { return `"page:${p.name}": defineAsyncComponent(${genDynamicImport(p.file)}.then(c => c.default || c))`; }) || []; return [ "import { defineAsyncComponent } from 'vue'", "export const islandComponents = import.meta.client ? {} : {", islands.map( (c) => { const exp = c.export === "default" ? "c.default || c" : `c['${c.export}']`; const comment = createImportMagicComments(c); return ` "${c.pascalName}": defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`; } ).concat(pageExports).join(",\n"), "}" ].join("\n"); } }; const NON_VUE_RE = /\b\.(?!vue)\w+$/g; const componentsTypeTemplate = { filename: "components.d.ts", getContents: ({ app, nuxt }) => { const buildDir = nuxt.options.buildDir; const componentTypes = app.components.filter((c) => !c.island).map((c) => { const type = `typeof ${genDynamicImport(isAbsolute(c.filePath) ? relative(buildDir, c.filePath).replace(NON_VUE_RE, "") : c.filePath.replace(NON_VUE_RE, ""), { wrapper: false })}['${c.export}']`; return [ c.pascalName, c.island || c.mode === "server" ? `IslandComponent<${type}>` : type ]; }); const islandType = "type IslandComponent<T extends DefineComponent> = T & DefineComponent<{}, {refresh: () => Promise<void>}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, SlotsType<{ fallback: { error: unknown } }>>"; return ` import type { DefineComponent, SlotsType } from 'vue' ${nuxt.options.experimental.componentIslands ? islandType : ""} interface _GlobalComponents { ${componentTypes.map(([pascalName, type]) => ` '${pascalName}': ${type}`).join("\n")} ${componentTypes.map(([pascalName, type]) => ` 'Lazy${pascalName}': ${type}`).join("\n")} } declare module 'vue' { export interface GlobalComponents extends _GlobalComponents { } } ${componentTypes.map(([pascalName, type]) => `export const ${pascalName}: ${type}`).join("\n")} ${componentTypes.map(([pascalName, type]) => `export const Lazy${pascalName}: ${type}`).join("\n")} export const componentNames: string[] `; } }; const componentsMetadataTemplate = { filename: "components.json", write: true, getContents: ({ app }) => JSON.stringify(app.components, null, 2) }; const ISLAND_RE = /\.island(?:\.global)?$/; const GLOBAL_RE = /\.global(?:\.island)?$/; const COMPONENT_MODE_RE = /(?<=\.)(client|server)(\.global|\.island)*$/; const MODE_REPLACEMENT_RE = /(\.(client|server))?(\.global|\.island)*$/; async function scanComponents(dirs, srcDir) { const components = []; const filePaths = /* @__PURE__ */ new Set(); const scannedPaths = []; for (const dir of dirs) { if (dir.enabled === false) { continue; } const resolvedNames = /* @__PURE__ */ new Map(); const files = (await globby(dir.pattern, { cwd: dir.path, ignore: dir.ignore })).sort(); if (files.length) { const siblings = await readdir(dirname(dir.path)).catch(() => []); const directory = basename(dir.path); if (!siblings.includes(directory)) { const directoryLowerCase = directory.toLowerCase(); const caseCorrected = siblings.find((sibling) => sibling.toLowerCase() === directoryLowerCase); if (caseCorrected) { const nuxt = useNuxt(); const original = relative(nuxt.options.srcDir, dir.path); const corrected = relative(nuxt.options.srcDir, join(dirname(dir.path), caseCorrected)); logger.warn(`Components not scanned from \`~/${corrected}\`. Did you mean to name the directory \`~/${original}\` instead?`); continue; } } } for (const _file of files) { const filePath = join(dir.path, _file); if (scannedPaths.find((d) => filePath.startsWith(withTrailingSlash(d))) || isIgnored(filePath)) { continue; } if (filePaths.has(filePath)) { continue; } filePaths.add(filePath); const prefixParts = [].concat( dir.prefix ? splitByCase(dir.prefix) : [], dir.pathPrefix !== false ? splitByCase(relative(dir.path, dirname(filePath))) : [] ); let fileName = basename(filePath, extname(filePath)); const island = ISLAND_RE.test(fileName) || dir.island; const global = GLOBAL_RE.test(fileName) || dir.global; const mode = island ? "server" : fileName.match(COMPONENT_MODE_RE)?.[1] || "all"; fileName = fileName.replace(MODE_REPLACEMENT_RE, ""); if (fileName.toLowerCase() === "index") { fileName = dir.pathPrefix === false ? basename(dirname(filePath)) : ""; } const suffix = mode !== "all" ? `-${mode}` : ""; const componentNameSegments = resolveComponentNameSegments(fileName.replace(QUOTE_RE, ""), prefixParts); const pascalName = pascalCase(componentNameSegments); if (LAZY_COMPONENT_NAME_REGEX.test(pascalName)) { logger.warn(`The component \`${pascalName}\` (in \`${filePath}\`) is using the reserved "Lazy" prefix used for dynamic imports, which may cause it to break at runtime.`); } if (resolvedNames.has(pascalName + suffix) || resolvedNames.has(pascalName)) { warnAboutDuplicateComponent(pascalName, filePath, resolvedNames.get(pascalName) || resolvedNames.get(pascalName + suffix)); continue; } resolvedNames.set(pascalName + suffix, filePath); const kebabName = kebabCase(componentNameSegments); const shortPath = relative(srcDir, filePath); const chunkName = "components/" + kebabName + suffix; let component = { // inheritable from directory configuration mode, global, island, prefetch: Boolean(dir.prefetch), preload: Boolean(dir.preload), // specific to the file filePath, pascalName, kebabName, chunkName, shortPath, export: "default", // by default, give priority to scanned components priority: dir.priority ?? 1, // @ts-expect-error untyped property _scanned: true }; if (typeof dir.extendComponent === "function") { component = await dir.extendComponent(component) || component; } if (!pascalName) { logger.warn(`Component did not resolve to a file name in \`~/${relative(srcDir, filePath)}\`.`); continue; } const existingComponent = components.find((c) => c.pascalName === component.pascalName && ["all", component.mode].includes(c.mode)); if (existingComponent) { const existingPriority = existingComponent.priority ?? 0; const newPriority = component.priority ?? 0; if (newPriority > existingPriority) { components.splice(components.indexOf(existingComponent), 1, component); } if (newPriority > 0 && newPriority === existingPriority) { warnAboutDuplicateComponent(pascalName, filePath, existingComponent.filePath); } continue; } components.push(component); } scannedPaths.push(dir.path); } return components; } function warnAboutDuplicateComponent(componentName, filePath, duplicatePath) { logger.warn( `Two component files resolving to the same name \`${componentName}\`: - ${filePath} - ${duplicatePath}` ); } const LAZY_COMPONENT_NAME_REGEX = /^Lazy(?=[A-Z])/; const REPLACE_COMPONENT_TO_DIRECT_IMPORT_RE = /(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy(?=[A-Z]))?([^'"]*)["'][^)]*\)/g; const LoaderPlugin = (options) => createUnplugin(() => { const exclude = options.transform?.exclude || []; const include = options.transform?.include || []; const nuxt = tryUseNuxt(); return { name: "nuxt:components-loader", enforce: "post", transformInclude(id) { if (exclude.some((pattern) => pattern.test(id))) { return false; } if (include.some((pattern) => pattern.test(id))) { return true; } return isVue(id, { type: ["template", "script"] }) || !!id.match(SX_RE); }, transform(code, id) { const components = options.getComponents(); let num = 0; const imports = /* @__PURE__ */ new Set(); const map = /* @__PURE__ */ new Map(); const s = new MagicString(code); s.replace(REPLACE_COMPONENT_TO_DIRECT_IMPORT_RE, (full, lazy, name) => { const component = findComponent(components, name, options.mode); if (component) { const internalInstall = component._internal_install; if (internalInstall && nuxt?.options.test === false) { if (!nuxt.options.dev) { const relativePath = relative(nuxt.options.rootDir, id); throw new Error(`[nuxt] \`~/${relativePath}\` is using \`${component.pascalName}\` which requires \`${internalInstall}\``); } import('../chunks/features.mjs').then(({ installNuxtModule }) => installNuxtModule(internalInstall)); } let identifier = map.get(component) || `__nuxt_component_${num++}`; map.set(component, identifier); const isServerOnly = !component._raw && component.mode === "server" && !components.some((c) => c.pascalName === component.pascalName && c.mode === "client"); if (isServerOnly) { imports.add(genImport(options.serverComponentRuntime, [{ name: "createServerComponent" }])); imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(component.pascalName)})`); if (!options.experimentalComponentIslands) { logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`); } return identifier; } const isClientOnly = !component._raw && component.mode === "client"; if (isClientOnly) { imports.add(genImport("#app/components/client-only", [{ name: "createClientOnly" }])); identifier += "_client"; } if (lazy) { imports.add(genImport("vue", [{ name: "defineAsyncComponent", as: "__defineAsyncComponent" }])); identifier += "_lazy"; imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? "default"} || c)${isClientOnly ? ".then(c => createClientOnly(c))" : ""})`); } else { imports.add(genImport(component.filePath, [{ name: component._raw ? "default" : component.export, as: identifier }])); if (isClientOnly) { imports.add(`const ${identifier}_wrapped = createClientOnly(${identifier})`); identifier += "_wrapped"; } } return identifier; } return full; }); if (imports.size) { s.prepend([...imports, ""].join("\n")); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); function findComponent(components, name, mode) { const id = pascalCase(name).replace(QUOTE_RE, ""); const component = components.find((component2) => id === component2.pascalName && ["all", mode, undefined].includes(component2.mode)); if (component) { return component; } const otherModeComponent = components.find((component2) => id === component2.pascalName); if (mode === "server" && otherModeComponent) { return components.find((c) => c.pascalName === "ServerPlaceholder"); } return otherModeComponent; } const SCRIPT_RE$1 = /<script[^>]*>/gi; const HAS_SLOT_OR_CLIENT_RE = /<slot[^>]*>|nuxt-client/; const TEMPLATE_RE = /<template>([\s\S]*)<\/template>/; const NUXTCLIENT_ATTR_RE = /\s:?nuxt-client(="[^"]*")?/g; const IMPORT_CODE = "\nimport { mergeProps as __mergeProps } from 'vue'\nimport { vforToArray as __vforToArray } from '#app/components/utils'\nimport NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'\nimport NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'"; const EXTRACTED_ATTRS_RE = /v-(?:if|else-if|else)(="[^"]*")?/g; const KEY_RE = /:?key="[^"]"/g; function wrapWithVForDiv(code, vfor) { return `<div v-for="${vfor}" style="display: contents;">${code}</div>`; } const IslandsTransformPlugin = (options) => createUnplugin((_options, meta) => { const isVite = meta.framework === "vite"; return { name: "nuxt:server-only-component-transform", enforce: "pre", transformInclude(id) { if (!isVue(id)) { return false; } if (isVite && options.selectiveClient === "deep") { return true; } const components = options.getComponents(); const islands = components.filter( (component) => component.island || component.mode === "server" && !components.some((c) => c.pascalName === component.pascalName && c.mode === "client") ); const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)); return islands.some((c) => c.filePath === pathname); }, async transform(code, id) { if (!HAS_SLOT_OR_CLIENT_RE.test(code)) { return; } const template = code.match(TEMPLATE_RE); if (!template) { return; } const startingIndex = template.index || 0; const s = new MagicString(code); if (!code.match(SCRIPT_RE$1)) { s.prepend("<script setup>" + IMPORT_CODE + "<\/script>"); } else { s.replace(SCRIPT_RE$1, (full) => { return full + IMPORT_CODE; }); } let hasNuxtClient = false; const ast = parse$1(template[0]); await walk$2(ast, (node) => { if (node.type !== ELEMENT_NODE) { return; } if (node.name === "slot") { const { attributes: attributes2, children, loc: loc2 } = node; const slotName = attributes2.name ?? "default"; if (attributes2.name) { delete attributes2.name; } if (attributes2["v-bind"]) { attributes2._bind = extractAttributes(attributes2, ["v-bind"])["v-bind"]; } const teleportAttributes = extractAttributes(attributes2, ["v-if", "v-else-if", "v-else"]); const bindings = getPropsToString(attributes2); s.appendLeft(startingIndex + loc2[0].start, `<NuxtTeleportSsrSlot${attributeToString(teleportAttributes)} name="${slotName}" :props="${bindings}">`); if (children.length) { const attrString = attributeToString(attributes2); const slice = code.slice(startingIndex + loc2[0].end, startingIndex + loc2[1].start).replaceAll(KEY_RE, ""); s.overwrite(startingIndex + loc2[0].start, startingIndex + loc2[1].end, `<slot${attrString.replaceAll(EXTRACTED_ATTRS_RE, "")}/><template #fallback>${attributes2["v-for"] ? wrapWithVForDiv(slice, attributes2["v-for"]) : slice}</template>`); } else { s.overwrite(startingIndex + loc2[0].start, startingIndex + loc2[0].end, code.slice(startingIndex + loc2[0].start, startingIndex + loc2[0].end).replaceAll(EXTRACTED_ATTRS_RE, "")); } s.appendRight(startingIndex + loc2[1].end, "</NuxtTeleportSsrSlot>"); return; } if (!("nuxt-client" in node.attributes) && !(":nuxt-client" in node.attributes)) { return; } hasNuxtClient = true; if (!isVite || !options.selectiveClient) { return; } const { loc, attributes } = node; const attributeValue = attributes[":nuxt-client"] || attributes["nuxt-client"] || "true"; const wrapperAttributes = extractAttributes(attributes, ["v-if", "v-else-if", "v-else"]); let startTag = code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replace(NUXTCLIENT_ATTR_RE, ""); { startTag = startTag.replaceAll(EXTRACTED_ATTRS_RE, ""); } s.appendLeft(startingIndex + loc[0].start, `<NuxtTeleportIslandComponent${attributeToString(wrapperAttributes)} :nuxt-client="${attributeValue}">`); s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, startTag); s.appendRight(startingIndex + loc[1].end, "</NuxtTeleportIslandComponent>"); }); if (hasNuxtClient) { if (!options.selectiveClient) { console.warn(`The \`nuxt-client\` attribute and client components within islands are only supported when \`experimental.componentIslands.selectiveClient\` is enabled. file: ${id}`); } else if (!isVite) { console.warn(`The \`nuxt-client\` attribute and client components within islands are only supported with Vite. file: ${id}`); } } if (s.hasChanged()) { return { code: s.toString(), map: s.generateMap({ source: id, includeContent: true }) }; } } }; }); function extractAttributes(attributes, names) { const extracted = {}; for (const name of names) { if (name in attributes) { extracted[name] = attributes[name]; delete attributes[name]; } } return extracted; } function attributeToString(attributes) { return Object.entries(attributes).map(([name, value]) => value ? ` ${name}="${value}"` : ` ${name}`).join(""); } function isBinding(attr) { return attr.startsWith(":"); } function getPropsToString(bindings) { const vfor = bindings["v-for"]?.split(" in ").map((v) => v.trim()); if (Object.keys(bindings).length === 0) { return "undefined"; } const content = Object.entries(bindings).filter((b) => b[0] && (b[0] !== "_bind" && b[0] !== "v-for")).map(([name, value]) => isBinding(name) ? `[\`${name.slice(1)}\`]: ${value}` : `[\`${name}\`]: \`${value}\``).join(","); const data = bindings._bind ? `__mergeProps(${bindings._bind}, { ${content} })` : `{ ${content} }`; if (!vfor) { return `[${data}]`; } else { return `__vforToArray(${vfor[1]}).map(${vfor[0]} => (${data}))`; } } const ComponentsChunkPlugin = createUnplugin((options) => { const { buildDir } = options; return { name: "nuxt:components-chunk", vite: { async config(config) { const components = options.getComponents(); config.build = defu$1(config.build, { rollupOptions: { input: {}, output: {} } }); const rollupOptions = config.build.rollupOptions; if (typeof rollupOptions.input === "string") { rollupOptions.input = { entry: rollupOptions.input }; } else if (typeof rollupOptions.input === "object" && Array.isArray(rollupOptions.input)) { rollupOptions.input = rollupOptions.input.reduce((acc, input) => { acc[input] = input; return acc; }, {}); } rollupOptions.preserveEntrySignatures = "allow-extension"; for (const component of components) { if (component.mode === "client" || component.mode === "all") { rollupOptions.input[component.pascalName] = await resolvePath$1(component.filePath); } } }, async generateBundle(_opts, bundle) { const components = options.getComponents().filter((c) => c.mode === "client" || c.mode === "all"); const pathAssociation = {}; for (const [chunkPath, chunkInfo] of Object.entries(bundle)) { if (chunkInfo.type !== "chunk") { continue; } for (const component of components) { if (chunkInfo.facadeModuleId && chunkInfo.exports.length > 0) { const { pathname } = parseURL(decodeURIComponent(pathToFileURL(chunkInfo.facadeModuleId).href)); const isPath = await resolvePath$1(component.filePath) === pathname; if (isPath) { chunkInfo.isEntry = false; pathAssociation[component.pascalName] = chunkPath; } } } } fs.writeFileSync(join(buildDir, "components-chunk.mjs"), `export const paths = ${JSON.stringify(pathAssociation, null, 2)}`); } } }; }); const COMPONENT_QUERY_RE = /[?&]nuxt_component=/; function TransformPlugin$1(nuxt, options) { const componentUnimport = createUnimport({ imports: [ { name: "componentNames", from: "#build/component-names" } ], virtualImports: ["#components"], injectAtEnd: true }); function getComponentsImports() { const components = options.getComponents(options.mode); return components.flatMap((c) => { const withMode = (mode2) => mode2 ? `${c.filePath}${c.filePath.includes("?") ? "&" : "?"}nuxt_component=${mode2}&nuxt_component_name=${c.pascalName}&nuxt_component_export=${c.export || "default"}` : c.filePath; const mode = !c._raw && c.mode && ["client", "server"].includes(c.mode) ? c.mode : undefined; return [ { as: c.pascalName, from: withMode(mode), name: c.export || "default" }, { as: "Lazy" + c.pascalName, from: withMode([mode, "async"].filter(Boolean).join(",")), name: c.export || "default" } ]; }); } return createUnplugin(() => ({ name: "nuxt:components:imports", enforce: "post", transformInclude(id) { id = normalize(id); return id.startsWith("virtual:") || id.startsWith("\0virtual:") || id.startsWith(nuxt.options.buildDir) || !isIgnored(id, undefined, nuxt); }, async transform(code, id) { if (COMPONENT_QUERY_RE.test(id)) { const { search } = parseURL(id); const query = parseQuery$1(search); const mode = query.nuxt_component; const bare = id.replace(/\?.*/, ""); const componentExport = query.nuxt_component_export || "default"; const exportWording = componentExport === "default" ? "export default" : `export const ${componentExport} =`; if (mode === "async") { return { code: [ 'import { defineAsyncComponent } from "vue"', `${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => r[${JSON.stringify(componentExport)}] || r.default || r))` ].join("\n"), map: null }; } else if (mode === "client") { return { code: [ genImport(bare, [{ name: componentExport, as: "__component" }]), 'import { createClientOnly } from "#app/components/client-only"', `${exportWording} createClientOnly(__component)` ].join("\n"), map: null }; } else if (mode === "client,async") { return { code: [ 'import { defineAsyncComponent } from "vue"', 'import { createClientOnly } from "#app/components/client-only"', `${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => createClientOnly(r[${JSON.stringify(componentExport)}] || r.default || r)))` ].join("\n"), map: null }; } else if (mode === "server" || mode === "server,async") { const name = query.nuxt_component_name; return { code: [ `import { createServerComponent } from ${JSON.stringify(options.serverComponentRuntime)}`, `${exportWording} createServerComponent(${JSON.stringify(name)})` ].join("\n"), map: null }; } else { throw new Error(`Unknown component mode: ${mode}, this might be an internal bug of Nuxt.`); } } if (!code.includes("#components")) { return; } componentUnimport.modifyDynamicImports((imports) => { imports.length = 0; imports.push(...getComponentsImports()); return imports; }); const result = await componentUnimport.injectImports(code, id, { autoImport: false, transformVirtualImports: true }); if (!result) { return; } return { code: result.code, map: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client ? result.s.generateMap({ hires: true }) : undefined }; } })); } const SSR_RENDER_RE = /ssrRenderComponent/; const PLACEHOLDER_EXACT_RE = /^(?:fallback|placeholder)$/; const CLIENT_ONLY_NAME_RE = /^(?:_unref\()?(?:_component_)?(?:Lazy|lazy_)?(?:client_only|ClientOnly\)?)$/; const TreeShakeTemplatePlugin = (options) => createUnplugin(() => { const regexpMap = /* @__PURE__ */ new WeakMap(); return { name: "nuxt:tree-shake-template", enforce: "post", transformInclude(id) { const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)); return pathname.endsWith(".vue"); }, transform(code, id) { const components = options.getComponents(); if (!regexpMap.has(components)) { const serverPlaceholderPath = resolve(distDir, "app/components/server-placeholder"); const clientOnlyComponents = components.filter((c) => c.mode === "client" && !components.some((other) => other.mode !== "client" && other.pascalName === c.pascalName && !other.filePath.startsWith(serverPlaceholderPath))).flatMap((c) => [c.pascalName, c.kebabName.replaceAll("-", "_")]).concat(["ClientOnly", "client_only"]); regexpMap.set(components, [new RegExp(`(${clientOnlyComponents.join("|")})`), new RegExp(`^(${clientOnlyComponents.map((c) => `(?:(?:_unref\\()?(?:_component_)?(?:Lazy|lazy_)?${c}\\)?)`).join("|")})$`), clientOnlyComponents]); } const s = new MagicString(code); const [COMPONENTS_RE, COMPONENTS_IDENTIFIERS_RE] = regexpMap.get(components); if (!COMPONENTS_RE.test(code)) { return; } const componentsToRemoveSet = /* @__PURE__ */ new Set(); const ast = parseAndWalk(code, id, (node) => { if (!isSsrRender(node)) { return; } const [componentCall, _, children] = node.arguments; if (!componentCall) { return; } if (componentCall.type === "Identifier" || componentCall.type === "MemberExpression" || componentCall.type === "CallExpression") { const componentName = getComponentName(node); if (!componentName || !COMPONENTS_IDENTIFIERS_RE.test(componentName) || children?.type !== "ObjectExpression") { return; } const isClientOnlyComponent = CLIENT_ONLY_NAME_RE.test(componentName); const slotsToRemove = isClientOnlyComponent ? children.properties.filter((prop) => prop.type === "Property" && prop.key.type === "Identifier" && !PLACEHOLDER_EXACT_RE.test(prop.key.name)) : children.properties; for (const _slot of slotsToRemove) { const slot = withLocations(_slot); s.remove(slot.start, slot.end + 1); const removedCode = `({${code.slice(slot.start, slot.end + 1)}})`; const currentState = s.toString(); parseAndWalk(removedCode, id, (node2) => { if (!isSsrRender(node2)) { return; } const name = getComponentName(node2); if (!name) { return; } const nameToRemove = isComponentNotCalledInSetup(currentState, id, name); if (nameToRemove) { componentsToRemoveSet.add(nameToRemove); } }); } } }); const componentsToRemove = [...componentsToRemoveSet]; const removedNodes = /* @__PURE__ */ new WeakSet(); for (const componentName of componentsToRemove) { removeImportDeclaration(ast, componentName, s); removeVariableDeclarator(ast, componentName, s, removedNodes); removeFromSetupReturn(ast, componentName, s); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); function removeFromSetupReturn(codeAst, name, magicString) { let walkedInSetup = false; walk(codeAst, { enter(node) { if (walkedInSetup) { this.skip(); } else if (node.type === "Property" && node.key.type === "Identifier" && node.key.name === "setup" && (node.value.type === "FunctionExpression" || node.value.type === "ArrowFunctionExpression")) { walkedInSetup = true; if (node.value.body?.type === "BlockStatement") { const returnStatement = node.value.body.body.find((statement) => statement.type === "ReturnStatement"); if (returnStatement && returnStatement.argument?.type === "ObjectExpression") { removePropertyFromObject(returnStatement.argument, name, magicString); } const variableList = node.value.body.body.filter((statement) => statement.type === "VariableDeclaration"); const returnedVariableDeclaration = variableList.find((declaration) => declaration.declarations[0]?.id.type === "Identifier" && declaration.declarations[0]?.id.name === "__returned__" && declaration.declarations[0]?.init?.type === "ObjectExpression"); if (returnedVariableDeclaration) { const init = returnedVariableDeclaration.declarations[0]?.init; if (init) { removePropertyFromObject(init, name, magicString); } } } } } }); } function removePropertyFromObject(node, name, magicString) { for (const property of node.properties) { if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === name) { const _property = withLocations(property); magicString.remove(_property.start, _property.end + 1); return true; } } return false; } function isSsrRender(node) { return node.type === "CallExpression" && node.callee.type === "Identifier" && SSR_RENDER_RE.test(node.callee.name); } function removeImportDeclaration(ast, importName, magicString) { for (const node of ast.body) { if (node.type !== "ImportDeclaration" || !node.specifiers) { continue; } const specifierIndex = node.specifiers.findIndex((s) => s.local.name === importName); if (specifierIndex > -1) { if (node.specifiers.length > 1) { const specifier = withLocations(node.specifiers[specifierIndex]); magicString.remove(specifier.start, specifier.end + 1); node.specifiers.splice(specifierIndex, 1); } else { const specifier = withLocations(node); magicString.remove(specifier.start, specifier.end); } return true; } } return false; } function isComponentNotCalledInSetup(code, id, name) { if (!name) { return; } let found = false; parseAndWalk(code, id, function(node) { if (node.type === "Property" && node.key.type === "Identifier" && node.value.type === "FunctionExpression" && node.key.name === "setup" || node.type === "FunctionDeclaration" && (node.id?.name === "_sfc_ssrRender" || node.id?.name === "ssrRender")) { walk(node, { enter(node2) { if (found || node2.type === "VariableDeclaration") { this.skip(); } else if (node2.type === "Identifier" && node2.name === name) { found = true; } else if (node2.type === "MemberExpression") { found = node2.property.type === "Literal" && node2.property.value === name || node2.property.type === "Identifier" && node2.property.name === name; } } }); } }); if (!found) { return name; } } function getComponentName(ssrRenderNode) { const componentCall = ssrRenderNode.arguments[0]; if (!componentCall) { return; } if (componentCall.type === "Identifier") { return componentCall.name; } else if (componentCall.type === "MemberExpression") { if (componentCall.property.type === "Literal") { return componentCall.property.value; } } else if (componentCall.type === "CallExpression") { return getComponentName(componentCall); } } function removeVariableDeclarator(codeAst, name, magicString, removedNodes) { walk(codeAst, { enter(node) { if (node.type !== "VariableDeclaration") { return; } for (const declarator of node.declarations) { const toRemove = withLocations(findMatchingPatternToRemove(declarator.id, node, name, removedNodes)); if (toRemove) { magicString.remove(toRemove.start, toRemove.end + 1); removedNodes.add(toRemove); } } } }); } function findMatchingPatternToRemove(node, toRemoveIfMatched, name, removedNodeSet) { if (node.type === "Identifier") { if (node.name === name) { return toRemoveIfMatched; } } else if (node.type === "ArrayPattern") { const elements = node.elements.filter((e) => e !== null && !removedNodeSet.has(e)); for (const element of elements) { const matched = findMatchingPatternToRemove(element, elements.length > 1 ? element : toRemoveIfMatched, name, removedNodeSet); if (matched) { return matched; } } } else if (node.type === "ObjectPattern") { const properties = node.properties.filter((e) => e.type === "Property" && !removedNodeSet.has(e)); for (const [index, property] of properties.entries()) { let nodeToRemove = property; if (properties.length < 2) { nodeToRemove = toRemoveIfMatched; } const matched = findMatchingPatternToRemove(property.value, nodeToRemove, name, removedNodeSet); if (matched) { if (matched === property) { properties.splice(index, 1); } return matched; } } } else if (node.type === "AssignmentPattern") { const matched = findMatchingPatternToRemove(node.left, toRemoveIfMatched, name, removedNodeSet); if (matched) { return matched; } } } const FILENAME_RE = /([^/\\]+)\.\w+$/; const ComponentNamePlugin = (options) => createUnplugin(() => { return { name: "nuxt:component-name-plugin", enforce: "post", transformInclude(id) { return isVue(id) || !!id.match(SX_RE); }, transform(code, id) { const filename = id.match(FILENAME_RE)?.[1]; if (!filename) { return; } const component = options.getComponents().find((c) => c.filePath === id); if (!component) { return; } const NAME_RE = new RegExp(`__name:\\s*['"]${filename}['"]`); const s = new MagicString(code); s.replace(NAME_RE, `__name: ${JSON.stringify(component.pascalName)}`); if (!s.hasChanged()) { parseAndWalk(code, id, function(node) { if (node.type !== "ExportDefaultDeclaration") { return; } const { start, end } = withLocations(node.declaration); s.overwrite(start, end, `Object.assign(${code.slice(start, end)}, { __name: ${JSON.stringify(component.pascalName)} })`); this.skip(); }); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const isPureObjectOrString = (val) => !Array.isArray(val) && typeof val === "object" || typeof val === "string"; const isDirectory = (p) => { try { return statSync(p).isDirectory(); } catch { return false; } }; const SLASH_SEPARATOR_RE = /[\\/]/; function compareDirByPathLength({ path: pathA }, { path: pathB }) { return pathB.split(SLASH_SEPARATOR_RE).filter(Boolean).length - pathA.split(SLASH_SEPARATOR_RE).filter(Boolean).length; } const DEFAULT_COMPONENTS_DIRS_RE = /\/components(?:\/(?:global|islands))?$/; const STARTER_DOT_RE = /^\./g; const componentsModule = defineNuxtModule({ meta: { name: "nuxt:components", configKey: "components" }, defaults: { dirs: [] }, async setup(componentOptions, nuxt) { let componentDirs = []; const context = { components: [] }; const getComponents = (mode) => { return mode && mode !== "all" ? context.components.filter((c) => c.mode === mode || c.mode === "all" || c.mode === "server" && !context.components.some((otherComponent) => otherComponent.mode !== "server" && otherComponent.pascalName === c.pascalName)) : context.components; }; if (nuxt.options.experimental.normalizeComponentNames) { addBuildPlugin(ComponentNamePlugin({ sourcemap: !!nuxt.options.sourcemap.client, getComponents }), { server: false }); addBuildPlugin(ComponentNamePlugin({ sourcemap: !!nuxt.options.sourcemap.server, getComponents }), { client: false }); } const normalizeDirs = (dir, cwd, options) => { if (Array.isArray(dir)) { return dir.map((dir2) => normalizeDirs(dir2, cwd, options)).flat().sort(compareDirByPathLength); } if (dir === true || dir === undefined) { return [ { priority: options?.priority || 0, path: resolve(cwd, "components/islands"), island: true }, { priority: options?.priority || 0, path: resolve(cwd, "components/global"), global: true }, { priority: options?.priority || 0, path: resolve(cwd, "components") } ]; } if (typeof dir === "string") { return [ { priority: options?.priority || 0, path: resolve(cwd, resolveAlias(dir)) } ]; } if (!dir) { return []; } const dirs = (dir.dirs || [dir]).map((dir2) => typeof dir2 === "string" ? { path: dir2 } : dir2).filter((_dir) => _dir.path); return dirs.map((_dir) => ({ priority: options?.priority || 0, ..._dir, path: resolve(cwd, resolveAlias(_dir.path)) })); }; nuxt.hook("app:resolve", async () => { const allDirs = nuxt.options._layers.map((layer) => normalizeDirs(layer.config.components, layer.config.srcDir, { priority: layer.config.srcDir === nuxt.options.srcDir ? 1 : 0 })).flat(); await nuxt.callHook("components:dirs", allDirs); componentDirs = allDirs.filter(isPureObjectOrString).map((dir) => { const dirOptions = typeof dir === "object" ? dir : { path: dir }; const dirPath = resolveAlias(dirOptions.path); const transpile = typeof dirOptions.transpile === "boolean" ? dirOptions.transpile : "auto"; const extensions = (dirOptions.extensions || nuxt.options.extensions).map((e) => e.replace(STARTER_DOT_RE, "")); const present = isDirectory(dirPath); if (!present && !DEFAULT_COMPONENTS_DIRS_RE.test(dirOptions.path)) { logger.warn("Components directory not found: `" + dirPath + "`"); } return { global: componentOptions.global, ...dirOptions, // TODO: https://github.com/nuxt/framework/pull/251 enabled: true, path: dirPath, extensions, pattern: dirOptions.pattern || `**/*.{${extensions.join(",")},}`, ignore: [ "**/*{M,.m,-m}ixin.{js,ts,jsx,tsx}", // ignore mixins "**/*.d.{cts,mts,ts}", // .d.ts files ...dirOptions.ignore || [] ], transpile: transpile === "auto" ? dirPath.includes("node_modules") : transpile }; }).filter((d) => d.enabled); componentDirs = [ ...componentDirs.filter((dir) => !dir.path.includes("node_modules")), ...componentDirs.filter((dir) => dir.path.includes("node_modules")) ]; nuxt.options.build.transpile.push(...componentDirs.filter((dir) => dir.transpile).map((dir) => dir.path)); }); addTypeTemplate(componentsTypeTemplate); addPluginTemplate(componentsPluginTemplate); addTemplate(componentNamesTemplate); addTemplate({ ...componentsIslandsTemplate, filename: "components.islands.mjs" }); if (componentOptions.generateMetadata) { addTemplate(componentsMetadataTemplate); } const serverComponentRuntime = await findPath(join(distDir, "components/runtime/server-component")) ?? join(distDir, "components/runtime/server-component"); addBuildPlugin(TransformPlugin$1(nuxt, { getComponents, serverComponentRuntime, mode: "server" }), { server: true, client: false }); addBuildPlugin(TransformPlugin$1(nuxt, { getComponents, serverComponentRuntime, mode: "client" }), { server: false, client: true }); nuxt.hook("build:manifest", (manifest) => { const sourceFiles = getComponents().filter((c) => c.global).map((c) => relative(nuxt.options.srcDir, c.filePath)); for (const chunk of Object.values(manifest)) { if (chunk.isEntry) { chunk.dynamicImports = chunk.dynamicImports?.filter((i) => !sourceFiles.includes(i)); } } }); nuxt.hook("builder:watch", (event, relativePath) => { if (!["addDir", "unlinkDir"].includes(event)) { return; } const path = resolve(nuxt.options.srcDir, relativePath); if (componentDirs.some((dir) => dir.path === path)) { logger.info(`Directory \`${relativePath}/\` ${event === "addDir" ? "created" : "removed"}`); return nuxt.callHook("restart"); } }); const serverPlaceholderPath = await findPath(join(distDir, "app/components/server-placeholder")) ?? join(distDir, "app/components/server-placeholder"); nuxt.hook("app:templates", async (app) => { const newComponents = await scanComponents(componentDirs, nuxt.options.srcDir); await nuxt.callHook("components:extend", newComponents); for (const component of newComponents) { if (!component._scanned && !(component.filePath in nuxt.vfs) && isAbsolute(component.filePath) && !existsSync(component.filePath)) { component.filePath = await resolvePath$1(component.filePath, { fallbackToOriginal: true }); } if (component.mode === "client" && !newComponents.some((c) => c.pascalName === component.pascalName && c.mode === "server")) { newComponents.push({ ...component, _raw: true, mode: "server", filePath: serverPlaceholderPath, chunkName: "components/" + component.kebabName }); } if (component.mode === "server" && !nuxt.options.ssr && !newComponents.some((other) => other.pascalName === component.pascalName && other.mode === "client")) { logger.warn(`Using server components with \`ssr: false\` is not supported with auto-detected component islands. If you need to use server component \`${component.pascalName}\`, set \`experimental.componentIslands\` to \`true\`.`); } } context.components = newComponents; app.components = newComponents; }); nuxt.hook("prepare:types", ({ tsConfig }) => { tsConfig.compilerOptions.paths["#components"] = [resolve(nuxt.options.buildDir, "components")]; }); if (nuxt.options.experimental.treeshakeClientOnly) { addBuildPlugin(TreeShakeTemplatePlugin({ sourcemap: !!nuxt.options.sourcemap.server, getComponents }), { client: false }); } const sharedLoaderOptions = { getComponents, serverComponentRuntime, transform: typeof nuxt.options.components === "object" && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, experimentalComponentIslands: !!nuxt.options.experimental.componentIslands }; addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.client, mode: "client" }), { server: false }); addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.server, mode: "server" }), { client: false }); if (nuxt.options.experimental.componentIslands) { const selectiveClient = typeof nuxt.options.experimental.componentIslands === "object" && nuxt.options.experimental.componentIslands.selectiveClient; addVitePlugin({ name: "nuxt-server-component-hmr", handleHotUpdate(ctx) { const components = getComponents(); const filePath = normalize(ctx.file); const comp = components.find((c) => c.filePath === filePath); if (comp?.mode === "server") { ctx.server.ws.send({ event: `nuxt-server-component:${comp.pascalName}`, type: "custom" }); } } }, { server: false }); addBuildPlugin(IslandsTransformPlugin({ getComponents, selectiveClient }), { client: false }); nuxt.hook("vite:extendConfig", (config, { isClient }) => { config.plugins ||= []; if (isClient && selectiveClient) { writeFileSync(join(nuxt.options.buildDir, "components-chunk.mjs"), "export const paths = {}"); if (!nuxt.options.dev) { config.plugins.push(ComponentsChunkPlugin.vite({ getComponents, buildDir: nuxt.options.buildDir })); } else { writeFileSync(join(nuxt.options.buildDir, "components-chunk.mjs"), `export const paths = ${JSON.stringify( getComponents().filter((c) => c.mode === "client" || c.mode === "all").reduce((acc, c) => { if (c.filePath.endsWith(".vue") || c.filePath.endsWith(".js") || c.filePath.endsWith(".ts")) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }); } const filePath = existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts`; return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` }); }, {}) )}`); } } }); for (const key of ["rspack:config", "webpack:config"]) { nuxt.hook(key, (configs) => { configs.forEach((config) => { const mode = config.name === "client" ? "client" : "server"; config.plugins ||= []; if (mode !== "server") { writeFileSync(join(nuxt.options.buildDir, "components-chunk.mjs"), "export const paths = {}"); } }); }); } } } }); const NODE_MODULES_RE$1 = /[\\/]node_modules[\\/]/; const IMPORTS_RE = /(['"])#imports\1/; const TransformPlugin = ({ ctx, options, sourcemap }) => createUnplugin(() => { return { name: "nuxt:imports-transform", enforce: "post", transformInclude(id) { if (options.transform?.include?.some((pattern) => pattern.test(id))) { return true; } if (options.transform?.exclude?.some((pattern) => pattern.test(id))) { return false; } if (isVue(id, { type: ["script", "template"] })) { return true; } return isJS(id); }, async transform(code, id) { id = normalize(id); const isNodeModule = NODE_MODULES_RE$1.test(id) && !options.transform?.include?.some((pattern) => pattern.test(id)); if (isNodeModule && !IMPORTS_RE.test(code)) { return; } const { s, imports } = await ctx.injectImports(code, id, { autoImport: options.autoImport && !isNodeModule }); if (imports.some((i) => i.from === "#app/composables/script-stubs") && tryUseNuxt()?.options.test === false) { import('../chunks/features.mjs').then(({ installNuxtModule }) => installNuxtModule("@nuxt/scripts")); } if (s.hasChanged()) { return { code: s.toString(), map: sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const commonPresets = [ // vue-demi (mocked) defineUnimportPreset({ from: "vue-demi", imports: [ "isVue2", "isVue3" ] }) ]; const granularAppPresets = [ { from: "#app/components/nuxt-link", imports: ["defineNuxtLink"] }, { imports: ["useNuxtApp", "tryUseNuxtApp", "defineNuxtPlugin", "definePayloadPlugin", "useRuntimeConfig", "defineAppConfig"], from: "#app/nuxt" }, { imports: ["requestIdleCallback", "cancelIdleCallback"], from: "#app/compat/idle-callback" }, { imports: ["setInterval"], from: "#app/compat/interval" }, { imports: ["useAppConfig", "updateAppConfig"], from: "#app/config" }, { imports: ["defineNuxtComponent"], from: "#app/composables/component" }, { imports: ["useAsyncData", "useLazyAsyncData", "useNuxtData", "refreshNuxtData", "clearNuxtData"], from: "#app/composables/asyncData" }, { imports: ["useHydration"], from: "#app/composables/hydrate" }, { imports: ["callOnce"], from: "#app/composables/once" }, { imports: ["useState", "clearNuxtState"], from: "#app/composables/state" }, { imports: ["clearError", "createError", "isNuxtError", "showError", "useError"], from: "#app/composables/error" }, { imports: ["useFetch", "useLazyFetch"], from: "#app/composables/fetch" }, { imports: ["useCookie", "refreshCookie"], from: "#app/composables/cookie" }, { imports: ["onPrehydrate", "prerenderRoutes", "useRequestHeader", "useRequestHeaders", "useResponseHeader", "useRequestEvent", "useRequestFetch", "setResponseStatus"], from: "#app/composables/ssr" }, { imports: ["onNuxtReady"], from: "#app/composables/ready" }, { imports: ["preloadComponents", "prefetchComponents", "preloadRouteComponents"], from: "#app/composables/preload" }, { imports: ["abortNavigation", "addRouteMiddleware", "defineNuxtRouteMiddleware", "setPageLayout", "navigateTo", "useRoute", "useRouter"], from: "#app/composables/router" }, { imports: ["isPrerendered", "loadPayload", "preloadPayload", "definePayloadReducer", "definePayloadReviver"], from: "#app/composables/payload" }, { imports: ["useLoadingIndicator"], from: "#app/composables/loading-indicator" }, { imports: ["getAppManifest", "getRouteRules"], from: "#app/composables/manifest" }, { imports: ["reloadNuxtApp"], from: "#app/composables/chunk" }, { imports: ["useRequestURL"], from: "#app/composables/url" }, { imports: ["usePreviewMode"], from: "#app/composables/preview" }, { imports: ["useRouteAnnouncer"], from: "#app/composables/route-announcer" }, { imports: ["useRuntimeHook"], from: "#app/composables/runtime-hook" } ]; const scriptsStubsPreset = { imports: [ "useScriptTriggerConsent", "useScriptEventPage", "useScriptTriggerElement", "useScript", "useScriptGoogleAnalytics", "useScriptPlausibleAnalytics", "useScriptClarity", "useScriptCloudflareWebAnalytics", "useScriptFathomAnalytics", "useScriptMatomoAnalytics", "useScriptGoogleTagManager", "useScriptGoogleAdsense", "useScriptSegment", "useScriptMetaPixel", "useScriptXPixel", "useScriptIntercom", "useScriptHotjar", "useScriptStripe", "useScriptLemonSqueezy", "useScriptVimeoPlayer", "useScriptYouTubePlayer", "useScriptGoogleMaps", "useScriptNpm", "useScriptCrisp" ], priority: -1, from: "#app/composables/script-stubs" }; const routerPreset = defineUnimportPreset({ imports: ["onBeforeRouteLeave", "onBeforeRouteUpdate"], from: "#app/composables/router" }); const vuePreset = defineUnimportPreset({ from: "vue", imports: [ // <script setup> "withCtx", "withDirectives", "withKeys", "withMemo", "withModifiers", "withScopeId", // Lifecycle "onActivated", "onBeforeMount", "onBeforeUnmount", "onBeforeUpdate", "onDeactivated", "onErrorCaptured", "onMounted", "onRenderTracked", "onRenderTriggered", "onServerPrefetch", "onUnmounted", "onUpdated", // Reactivity "computed", "customRef", "isProxy", "isReactive", "isReadonly", "isRef", "markRaw", "proxyRefs", "reactive", "readonly", "ref", "shallowReactive", "shallowReadonly", "shallowRef", "toRaw", "toRef", "toRefs", "triggerRef", "unref", "watch", "watchEffect", "watchPostEffect", "watchSyncEffect", "isShallow", // effect "effect", "effectScope", "getCurrentScope", "onScopeDispose", // Component "defineComponent", "defineAsyncComponent", "resolveComponent", "getCurrentInstance", "h", "inject", "hasInjectionContext", "nextTick", "provide", "mergeModels", "toValue", "useModel", "useAttrs", "useCssModule", "useCssVars", "useSlots", "useTransitionState", "useId", "useTemplateRef", "useShadowRoot", "useCssVars" ] }); const vueTypesPreset = defineUnimportPreset({ from: "vue", type: true, imports: [ "Component", "ComponentPublicInstance", "ComputedRef", "DirectiveBinding", "ExtractDefaultPropTypes", "ExtractPropTypes", "ExtractPublicPropTypes", "InjectionKey", "PropType", "Ref", "MaybeRef", "MaybeRefOrGetter", "VNode", "WritableComputedRef" ] }); const defaultPresets = [ ...commonPresets, ...granularAppPresets, routerPreset, vuePreset, vueTypesPreset ]; const importsModule = defineNuxtModule({ meta: { name: "nuxt:imports", configKey: "imports" }, defaults: (nuxt) => ({ autoImport: true, scan: true, presets: defaultPresets, global: false, imports: [], dirs: [], transform: { include: [ new RegExp("^" + escapeRE(nuxt.options.buildDir)) ], exclude: undefined }, virtualImports: ["#imports"] }), async setup(options, nuxt) { const presets = JSON.parse(JSON.stringify(options.presets)); await nuxt.callHook("imports:sources", presets); const { addons: inlineAddons, ...rest } = options; const [addons, addonsOptions] = Array.isArray(inlineAddons) ? [inlineAddons] : [[], inlineAddons]; const ctx = createUnimport({ injectAtEnd: true, ...rest, addons: { addons, vueTemplate: options.autoImport, vueDirectives: options.autoImport === false ? undefined : true, ...addonsOptions }, presets }); await nuxt.callHook("imports:context", ctx); const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4; let composablesDirs = []; if (options.scan) { for (const layer of nuxt.options._layers) { if (layer.config?.imports?.scan === false) { continue; } composablesDirs.push(resolve(layer.config.srcDir, "composables")); composablesDirs.push(resolve(layer.config.srcDir, "utils")); if (isNuxtV4) { composablesDirs.push(resolve(layer.config.rootDir, "shared", "utils")); composablesDirs.push(resolve(layer.config.rootDir, "shared", "types")); } for (const dir of layer.config.imports?.dirs ?? []) { if (!dir) { continue; } composablesDirs.push(resolve(layer.config.srcDir, dir)); } } await nuxt.callHook("imports:dirs", composablesDirs); composablesDirs = composablesDirs.map((dir) => normalize(dir)); nuxt.hook("builder:watch", (event, relativePath) => { if (!["addDir", "unlinkDir"].includes(event)) { return; } const path = resolve(nuxt.options.srcDir, relativePath); if (composablesDirs.includes(path)) { logger.info(`Directory \`${relativePath}/\` ${event === "addDir" ? "created" : "removed"}`); return nuxt.callHook("restart"); } }); } addTemplate({ filename: "imports.mjs", getContents: async () => toExports(await ctx.getImports()) + '\nif (import.meta.dev) { console.warn("[nuxt] `#imports` should be transformed with real imports. There seems to be something wrong with the imports plugin.") }' }); nuxt.options.alias["#imports"] = join(nuxt.options.buildDir, "imports"); addBuildPlugin(TransformPlugin({ ctx, options, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client })); const priorities = nuxt.options._layers.map((layer, i) => [layer.config.srcDir, -i]).sort(([a], [b]) => b.length - a.length); const IMPORTS_TEMPLATE_RE = /\/imports\.(?:d\.ts|mjs)$/; function isImportsTemplate(template) { return IMPORTS_TEMPLATE_RE.test(template.filename); } const isIgnored = createIsIgnored(nuxt); const regenerateImports = async () => { await ctx.modifyDynamicImports(async (imports) => { imports.length = 0; if (options.scan) { const scannedImports = await scanDirExports(composablesDirs, { fileFilter: (file) => !isIgnored(file) }); for (const i of scannedImports) { i.priority = i.priority || priorities.find(([dir]) => i.from.startsWith(dir))?.[1]; } imports.push(...scannedImports); } await nuxt.callHook("imports:extend", imports); return imports; }); await updateTemplates({ filter: isImportsTemplate }); }; await regenerateImports(); addDeclarationTemplates(ctx, options); nuxt.hook("builder:watch", async (_, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (options.scan && composablesDirs.some((dir) => dir === path || path.startsWith(dir + "/"))) { await regenerateImports(); } }); nuxt.hook("app:templatesGenerated", async (_app, templates) => { if (templates.some((t) => !isImportsTemplate(t))) { await regenerateImports(); } }); } }); function addDeclarationTemplates(ctx, options) { const nuxt = useNuxt(); const resolvedImportPathMap = /* @__PURE__ */ new Map(); const r = ({ from }) => resolvedImportPathMap.get(from); const SUPPORTED_EXTENSION_RE = new RegExp(`\\.(${nuxt.options.extensions.map((i) => i.replace(".", "")).join("|")})$`); async function cacheImportPaths(imports) { const importSource = Array.from(new Set(imports.map((i) => i.from))); await Promise.all(importSource.map(async (from) => { if (resolvedImportPathMap.has(from) || nuxt._dependencies?.has(from)) { return; } let path = resolveAlias(from); if (!isAbsolute(path)) { path = await tryResolveModule(from, nuxt.options.modulesDir).then(async (r2) => { if (!r2) { return r2; } const { dir, name } = parseNodeModulePath(r2); if (name && nuxt._dependencies?.has(name)) { return from; } if (!dir || !name) { return r2; } const subpath = await lookupNodeModuleSubpath(r2); return join(dir, name, subpath || ""); }) ?? path; } if (existsSync(path) && !await isDirectory$1(path)) { path = path.replace(SUPPORTED_EXTENSION_RE, ""); } if (isAbsolute(path)) { path = relative(join(nuxt.options.buildDir, "types"), path); } resolvedImportPathMap.set(from, path); })); } addTypeTemplate({ filename: "imports.d.ts", getContents: async ({ nuxt: nuxt2 }) => toExports(await ctx.getImports(), nuxt2.options.buildDir, true) }); addTypeTemplate({ filename: "types/imports.d.ts", getContents: async () => { const imports = await ctx.getImports(); await cacheImportPaths(imports); return "// Generated by auto imports\n" + (options.autoImport ? await ctx.generateTypeDeclarations({ resolvePath: r }) : "// Implicit auto importing is disabled, you can use explicitly import from `#imports` instead."); } }); } const version = "3.15.3"; const createImportProtectionPatterns = (nuxt, options) => { const patterns = []; const context = contextFlags[options.context]; patterns.push([ /^(nuxt|nuxt3|nuxt-nightly)$/, `\`nuxt\`, or \`nuxt-nightly\` cannot be imported directly in ${context}.` + (options.context === "nuxt-app" ? " Instead, import runtime Nuxt composables from `#app` or `#imports`." : "") ]); patterns.push([ /^((~|~~|@|@@)?\/)?nuxt\.config(\.|$)/, "Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module." ]); patterns.push([/(^|node_modules\/)@vue\/composition-api/]); for (const mod of nuxt.options.modules.filter((m) => typeof m === "string")) { patterns.push([ new RegExp(`^${escapeRE(mod)}$`), "Importing directly from module entry-points is not allowed." ]); } for (const i of [/(^|node_modules\/)@nuxt\/(cli|kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nitro(?:pack)?(?:-nightly)?(?:$|\/)(?!(?:dist\/)?(?:node_modules|presets|runtime|types))/, /(^|node_modules\/)nuxt\/(config|kit|schema)/]) { patterns.push([i, `This module cannot be imported in ${context}.`]); } if (options.context === "nitro-app" || options.context === "shared") { for (const i of ["#app", /^#build(\/|$)/]) { patterns.push([i, `Vue app aliases are not allowed in ${context}.`]); } } if (options.context === "nuxt-app" || options.context === "shared") { patterns.push([ new RegExp(escapeRE(relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, nuxt.options.serverDir || "server"))) + "\\/(api|routes|middleware|plugins)\\/"), `Importing from server is not allowed in ${context}.` ]); } return patterns; }; const contextFlags = { "nitro-app": "server runtime", "nuxt-app": "the Vue part of your app", "shared": "the #shared directory" }; const TRANSFORM_MARKER = "/* _processed_nuxt_unctx_transform */\n"; const UnctxTransformPlugin = (options) => createUnplugin(() => { const transformer = createTransformer(options.transformerOptions); return { name: "unctx:transform", enforce: "post", transformInclude(id) { return isVue(id, { type: ["template", "script"] }) || isJS(id); }, transform(code) { if (code.startsWith(TRANSFORM_MARKER) || !transformer.shouldTransform(code)) { return; } const result = transformer.transform(code); if (result) { return { code: TRANSFORM_MARKER + result.code, map: options.sourcemap ? result.magicString.generateMap({ hires: true }) : undefined }; } } }; }); const TreeShakeComposablesPlugin = (options) => createUnplugin(() => { const composableNames = Object.values(options.composables).flat(); const regexp = `(^\\s*)(${composableNames.join("|")})(?=\\((?!\\) \\{))`; const COMPOSABLE_RE = new RegExp(regexp, "m"); const COMPOSABLE_RE_GLOBAL = new RegExp(regexp, "gm"); return { name: "nuxt:tree-shake-composables:transform", enforce: "post", transformInclude(id) { return isVue(id, { type: ["script"] }) || isJS(id); }, transform(code) { if (!COMPOSABLE_RE.test(code)) { return; } const s = new MagicString(code); const strippedCode = stripLiteral(code); for (const match of strippedCode.matchAll(COMPOSABLE_RE_GLOBAL)) { s.overwrite(match.index, match.index + match[0].length, `${match[1]} false && /*@__PURE__*/ ${match[2]}`); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const DEVONLY_COMP_SINGLE_RE = /<(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>[\s\S]*?<\/(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>/; const DEVONLY_COMP_RE = /<(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>[\s\S]*?<\/(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>/g; const DevOnlyPlugin = (options) => createUnplugin(() => { return { name: "nuxt:server-devonly:transform", enforce: "pre", transformInclude(id) { return isVue(id, { type: ["template"] }); }, transform(code) { if (!DEVONLY_COMP_SINGLE_RE.test(code)) { return; } const s = new MagicString(code); for (const match of code.matchAll(DEVONLY_COMP_RE)) { const ast = parse$1(match[0]).children[0]; const fallback = ast.children?.find((n) => n.name === "template" && Object.values(n.attributes).includes("#fallback")); const replacement = fallback ? match[0].slice(fallback.loc[0].end, fallback.loc[fallback.loc.length - 1].start) : ""; s.overwrite(match.index, match.index + match[0].length, replacement); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const ALIAS_RE = /(?<=['"])[~@]{1,2}(?=\/)/g; const ALIAS_RE_SINGLE = /(?<=['"])[~@]{1,2}(?=\/)/; const LayerAliasingPlugin = (options) => createUnplugin((_options, meta) => { const aliases = {}; for (const layer of options.layers) { const srcDir = layer.config.srcDir || layer.cwd; const rootDir = layer.config.rootDir || layer.cwd; aliases[srcDir] = { "~": layer.config?.alias?.["~"] || srcDir, "@": layer.config?.alias?.["@"] || srcDir, "~~": layer.config?.alias?.["~~"] || rootDir, "@@": layer.config?.alias?.["@@"] || rootDir }; } const layers = Object.keys(aliases).sort((a, b) => b.length - a.length); return { name: "nuxt:layer-aliasing", enforce: "pre", vite: { resolveId: { order: "pre", async handler(id, importer) { if (!importer) { return; } const layer = layers.find((l) => importer.startsWith(l)); if (!layer) { return; } const resolvedId = resolveAlias(id, aliases[layer]); if (resolvedId !== id) { return await this.resolve(resolvedId, importer, { skipSelf: true }); } } } }, // webpack-only transform transformInclude: (id) => { if (meta.framework === "vite") { return false; } const _id = normalize(id); return layers.some((dir) => _id.startsWith(dir)); }, transform(code, id) { if (meta.framework === "vite") { return; } const _id = normalize(id); const layer = layers.find((l) => _id.startsWith(l)); if (!layer || !ALIAS_RE_SINGLE.test(code)) { return; } const s = new MagicString(code); s.replace(ALIAS_RE, (r) => aliases[layer]?.[r] || r); if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const addModuleTranspiles = (opts = {}) => { const nuxt = useNuxt(); const modules = [ ...opts.additionalModules || [], ...nuxt.options.modules, ...nuxt.options._modules ].map((m) => typeof m === "string" ? m : Array.isArray(m) ? m[0] : m.src).filter((m) => typeof m === "string").map(normalizeModuleTranspilePath); nuxt.options.build.transpile = nuxt.options.build.transpile.map((m) => typeof m === "string" ? m.split("node_modules/").pop() : m).filter((x) => !!x); function isTranspilePresent(mod) { return nuxt.options.build.transpile.some((t) => !(t instanceof Function) && (t instanceof RegExp ? t.test(mod) : new RegExp(t).test(mod))); } for (const module of modules) { if (!isTranspilePresent(module)) { nuxt.options.build.transpile.push(module); } } }; const template = () => { return '<svg xmlns="http://www.w3.org/2000/svg" width="80" fill="none" class="nuxt-spa-loading" viewBox="0 0 37 25"><path d="M24.236 22.006h10.742L25.563 5.822l-8.979 14.31a4 4 0 0 1-3.388 1.874H2.978l11.631-20 5.897 10.567"/></svg><style>.nuxt-spa-loading{left:50%;position:fixed;top:50%;transform:translate(-50%,-50%)}.nuxt-spa-loading>path{fill:none;stroke:#00dc82;stroke-width:4px;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:128;stroke-dashoffset:128;animation:nuxt-spa-loading-move 3s linear infinite}@keyframes nuxt-spa-loading-move{to{stroke-dashoffset:-128}}</style>'; }; const logLevelMapReverse = { silent: 0, info: 3, verbose: 3 }; const NODE_MODULES_RE = /(?<=\/)node_modules\/(.+)$/; const PNPM_NODE_MODULES_RE = /\.pnpm\/.+\/node_modules\/(.+)$/; async function initNitro(nuxt) { const excludePaths = nuxt.options._layers.flatMap((l) => [ l.cwd.match(NODE_MODULES_RE)?.[1], l.cwd.match(PNPM_NODE_MODULES_RE)?.[1] ]).filter((dir) => Boolean(dir)).map((dir) => escapeRE(dir)); const excludePattern = excludePaths.length ? [new RegExp(`node_modules\\/(?!${excludePaths.join("|")})`)] : [/node_modules/]; const rootDirWithSlash = withTrailingSlash(nuxt.options.rootDir); const modules = await resolveNuxtModule( rootDirWithSlash, nuxt.options._installedModules.filter((m) => m.entryPath).map((m) => m.entryPath) ); const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4; const nitroConfig = defu(nuxt.options.nitro, { debug: nuxt.options.debug, rootDir: nuxt.options.rootDir, workspaceDir: nuxt.options.workspaceDir, srcDir: nuxt.options.serverDir, dev: nuxt.options.dev, buildDir: nuxt.options.buildDir, experimental: { asyncContext: nuxt.options.experimental.asyncContext, typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === "bundler" || nuxt.options.nitro.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === "bundler" }, framework: { name: "nuxt", version: version }, imports: { autoImport: nuxt.options.imports.autoImport, dirs: isNuxtV4 ? [ resolve(nuxt.options.rootDir, "shared", "utils"), resolve(nuxt.options.rootDir, "shared", "types") ] : [], imports: [ { as: "__buildAssetsURL", name: "buildAssetsURL", from: resolve(distDir, "core/runtime/nitro/paths") }, { as: "__publicAssetsURL", name: "publicAssetsURL", from: resolve(distDir, "core/runtime/nitro/paths") }, { // TODO: Remove after https://github.com/nitrojs/nitro/issues/1049 as: "defineAppConfig", name: "defineAppConfig", from: resolve(distDir, "core/runtime/nitro/config"), priority: -1 } ], exclude: [...excludePattern, /[\\/]\.git[\\/]/] }, esbuild: { options: { exclude: excludePattern } }, analyze: !nuxt.options.test && nuxt.options.build.analyze && (nuxt.options.build.analyze === true || nuxt.options.build.analyze.enabled) ? { template: "treemap", projectRoot: nuxt.options.rootDir, filename: join(nuxt.options.analyzeDir, "{name}.html") } : false, scanDirs: nuxt.options._layers.map((layer) => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, "server"))).filter(Boolean), renderer: resolve(distDir, "core/runtime/nitro/renderer"), errorHandler: resolve(distDir, "core/runtime/nitro/error"), nodeModulesDirs: nuxt.options.modulesDir, handlers: nuxt.options.serverHandlers, devHandlers: [], baseURL: nuxt.options.app.baseURL, virtual: { "#internal/nuxt.config.mjs": () => nuxt.vfs["#build/nuxt.config.mjs"], "#spa-template": async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}` }, routeRules: { "/__nuxt_error": { cache: false } }, appConfig: nuxt.options.appConfig, appConfigFiles: nuxt.options._layers.map( (layer) => resolve(layer.config.srcDir, "app.config") ), typescript: { strict: true, generateTsConfig: true, tsconfigPath: "tsconfig.server.json", tsConfig: { compilerOptions: { lib: ["esnext", "webworker", "dom.iterable"] }, include: [ join(nuxt.options.buildDir, "types/nitro-nuxt.d.ts"), ...modules.map((m) => join(relativeWithDot(nuxt.options.buildDir, m), "runtime/server")) ], exclude: [ ...nuxt.options.modulesDir.map((m) => relativeWithDot(nuxt.options.buildDir, m)), // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, "dist")) ] } }, publicAssets: [ nuxt.options.dev ? { dir: resolve(nuxt.options.buildDir, "dist/client") } : { dir: join(nuxt.options.buildDir, "dist/client", nuxt.options.app.buildAssetsDir), maxAge: 31536e3, baseURL: nuxt.options.app.buildAssetsDir }, ...nuxt.options._layers.map((layer) => resolve(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.public || "public")).filter((dir) => existsSync(dir)).map((dir) => ({ dir })) ], prerender: { failOnError: true, concurrency: cpus().length * 4 || 4, routes: [].concat(nuxt.options.generate.routes) }, sourceMap: nuxt.options.sourcemap.server, externals: { inline: [ ...nuxt.options.dev ? [] : [ ...nuxt.options.experimental.externalVue ? [] : ["vue", "@vue/"], "@nuxt/", nuxt.options.buildDir ], ...nuxt.options.build.transpile.filter((i) => typeof i === "string"), "nuxt/dist", "nuxt3/dist", "nuxt-nightly/dist", distDir, // Ensure app config files have auto-imports injected even if they are pure .js files ...nuxt.options._layers.map((layer) => resolve(layer.config.srcDir, "app.config")) ], traceInclude: [ // force include files used in generated code from the runtime-compiler ...nuxt.options.vue.runtimeCompiler && !nuxt.options.experimental.externalVue ? [ ...nuxt.options.modulesDir.reduce((targets, path) => { const serverRendererPath = resolve(path, "vue/server-renderer/index.js"); if (existsSync(serverRendererPath)) { targets.push(serverRendererPath); } return targets; }, []) ] : [] ] }, alias: { // Vue 3 mocks ...nuxt.options.vue.runtimeCompiler || nuxt.options.experimental.externalVue ? {} : { "estree-walker": "unenv/runtime/mock/proxy", "@babel/parser": "unenv/runtime/mock/proxy", "@vue/compiler-core": "unenv/runtime/mock/proxy", "@vue/compiler-dom": "unenv/runtime/mock/proxy", "@vue/compiler-ssr": "unenv/runtime/mock/proxy" }, "@vue/devtools-api": "vue-devtools-stub", // Nuxt aliases ...nuxt.options.alias, // Paths "#internal/nuxt/paths": resolve(distDir, "core/runtime/nitro/paths") }, replace: { "process.env.NUXT_NO_SSR": nuxt.options.ssr === false, "process.env.NUXT_EARLY_HINTS": nuxt.options.experimental.writeEarlyHints !== false, "process.env.NUXT_NO_SCRIPTS": !!nuxt.options.features.noScripts && !nuxt.options.dev, "process.env.NUXT_INLINE_STYLES": !!nuxt.options.features.inlineStyles, "process.env.NUXT_JSON_PAYLOADS": !!nuxt.options.experimental.renderJsonPayloads, "process.env.NUXT_ASYNC_CONTEXT": !!nuxt.options.experimental.asyncContext, "process.env.NUXT_SHARED_DATA": !!nuxt.options.experimental.sharedPrerenderData, "process.dev": nuxt.options.dev, "__VUE_PROD_DEVTOOLS__": false }, rollupConfig: { output: {}, plugins: [] }, logLevel: logLevelMapReverse[nuxt.options.logLevel] }); nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir); nitroConfig.ignore ||= []; nitroConfig.ignore.push( ...resolveIgnorePatterns(nitroConfig.srcDir), `!${join(nuxt.options.buildDir, "dist/client", nuxt.options.app.buildAssetsDir, "**/*")}` ); nitroConfig.plugins = nitroConfig.plugins?.map((plugin) => plugin ? resolveAlias(plugin, nuxt.options.alias) : plugin); if (nuxt.options.experimental.appManifest) { const buildId = nuxt.options.runtimeConfig.app.buildId ||= nuxt.options.buildId; const buildTimestamp = Date.now(); const manifestPrefix = joinURL(nuxt.options.app.buildAssetsDir, "builds"); const tempDir = join(nuxt.options.buildDir, "manifest"); nitroConfig.prerender ||= {}; nitroConfig.prerender.ignore ||= []; nitroConfig.prerender.ignore.push(joinURL(nuxt.options.app.baseURL, manifestPrefix)); nitroConfig.publicAssets.unshift( // build manifest { dir: join(tempDir, "meta"), maxAge: 31536e3, baseURL: joinURL(manifestPrefix, "meta") }, // latest build { dir: tempDir, maxAge: 1, baseURL: manifestPrefix } ); nuxt.options.alias["#app-manifest"] = join(tempDir, `meta/${buildId}.json`); if (!nuxt.options.dev) { nuxt.hook("build:before", async () => { await promises.mkdir(join(tempDir, "meta"), { recursive: true }); await promises.writeFile(join(tempDir, `meta/${buildId}.json`), JSON.stringify({})); }); } nuxt.hook("nitro:config", (config) => { config.alias ||= {}; config.alias["#app-manifest"] = join(tempDir, `meta/${buildId}.json`); const rules = config.routeRules; for (const rule in rules) { if (!rules[rule].appMiddleware) { continue; } const value = rules[rule].appMiddleware; if (typeof value === "string") { rules[rule].appMiddleware = { [value]: true }; } else if (Array.isArray(value)) { const normalizedRules = {}; for (const middleware of value) { normalizedRules[middleware] = true; } rules[rule].appMiddleware = normalizedRules; } } }); nuxt.hook("nitro:init", (nitro2) => { nitro2.hooks.hook("rollup:before", async (nitro3) => { const routeRules = {}; const _routeRules = nitro3.options.routeRules; for (const key in _routeRules) { if (key === "/__nuxt_error") { continue; } let hasRules = false; const filteredRules = {}; for (const routeKey in _routeRules[key]) { const value = _routeRules[key][routeKey]; if (["prerender", "redirect", "appMiddleware"].includes(routeKey) && value) { if (routeKey === "redirect") { filteredRules[routeKey] = typeof value === "string" ? value : value.to; } else { filteredRules[routeKey] = value; } hasRules = true; } } if (hasRules) { routeRules[key] = filteredRules; } } const prerenderedRoutes = /* @__PURE__ */ new Set(); const routeRulesMatcher = toRouteMatcher( createRouter({ routes: routeRules }) ); if (nitro3._prerenderedRoutes?.length) { const payloadSuffix = nuxt.options.experimental.renderJsonPayloads ? "/_payload.json" : "/_payload.js"; for (const route of nitro3._prerenderedRoutes) { if (!route.error && route.route.endsWith(payloadSuffix)) { const url = route.route.slice(0, -payloadSuffix.length) || "/"; const rules = defu({}, ...routeRulesMatcher.matchAll(url).reverse()); if (!rules.prerender) { prerenderedRoutes.add(url); } } } } const manifest = { id: buildId, timestamp: buildTimestamp, matcher: exportMatcher(routeRulesMatcher), prerendered: nuxt.options.dev ? [] : [...prerenderedRoutes] }; await promises.mkdir(join(tempDir, "meta"), { recursive: true }); await promises.writeFile(join(tempDir, "latest.json"), JSON.stringify({ id: buildId, timestamp: buildTimestamp })); await promises.writeFile(join(tempDir, `meta/${buildId}.json`), JSON.stringify(manifest)); }); }); } if (!nuxt.options.experimental.appManifest) { nuxt.options.alias["#app-manifest"] = "unenv/runtime/mock/proxy"; } const FORWARD_SLASH_RE = /\//g; if (!nuxt.options.ssr) { nitroConfig.virtual["#build/dist/server/server.mjs"] = "export default () => {}"; if (process.platform === "win32") { nitroConfig.virtual["#build/dist/server/server.mjs".replace(FORWARD_SLASH_RE, "\\")] = "export default () => {}"; } } if (nuxt.options.dev || nuxt.options.builder === "@nuxt/webpack-builder" || nuxt.options.builder === "@nuxt/rspack-builder") { nitroConfig.virtual["#build/dist/server/styles.mjs"] = "export default {}"; if (process.platform === "win32") { nitroConfig.virtual["#build/dist/server/styles.mjs".replace(FORWARD_SLASH_RE, "\\")] = "export default {}"; } } if (nuxt.options.experimental.respectNoSSRHeader) { nitroConfig.handlers = nitroConfig.handlers || []; nitroConfig.handlers.push({ handler: resolve(distDir, "core/runtime/nitro/no-ssr"), middleware: true }); } nitroConfig.rollupConfig.plugins = await nitroConfig.rollupConfig.plugins || []; nitroConfig.rollupConfig.plugins = toArray(nitroConfig.rollupConfig.plugins); const sharedDir = withTrailingSlash(resolve(nuxt.options.rootDir, nuxt.options.dir.shared)); const relativeSharedDir = withTrailingSlash(relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, nuxt.options.dir.shared))); const sharedPatterns = [/^#shared\//, new RegExp("^" + escapeRE(sharedDir)), new RegExp("^" + escapeRE(relativeSharedDir))]; nitroConfig.rollupConfig.plugins.push( ImpoundPlugin.rollup({ cwd: nuxt.options.rootDir, include: sharedPatterns, patterns: createImportProtectionPatterns(nuxt, { context: "shared" }) }), ImpoundPlugin.rollup({ cwd: nuxt.options.rootDir, patterns: createImportProtectionPatterns(nuxt, { context: "nitro-app" }), exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/, ...sharedPatterns] }) ); await nuxt.callHook("nitro:config", nitroConfig); const excludedAlias = [/^@vue\/.*$/, "#imports", "vue-demi", /^#app/]; const basePath = nitroConfig.typescript.tsConfig.compilerOptions?.baseUrl ? resolve(nuxt.options.buildDir, nitroConfig.typescript.tsConfig.compilerOptions?.baseUrl) : nuxt.options.buildDir; const aliases = nitroConfig.alias; const tsConfig = nitroConfig.typescript.tsConfig; tsConfig.compilerOptions ||= {}; tsConfig.compilerOptions.paths ||= {}; for (const _alias in aliases) { const alias = _alias; if (excludedAlias.some((pattern) => typeof pattern === "string" ? alias === pattern : pattern.test(alias))) { continue; } if (alias in tsConfig.compilerOptions.paths) { continue; } const absolutePath = resolve(basePath, aliases[alias]); const stats = await promises.stat(absolutePath).catch( () => null /* file does not exist */ ); if (stats?.isDirectory()) { tsConfig.compilerOptions.paths[alias] = [absolutePath]; tsConfig.compilerOptions.paths[`${alias}/*`] = [`${absolutePath}/*`]; } else { tsConfig.compilerOptions.paths[alias] = [absolutePath.replace(EXTENSION_RE, "")]; } } const nitro = await createNitro(nitroConfig, { compatibilityDate: nuxt.options.compatibilityDate }); const spaLoadingTemplateFilePath = await spaLoadingTemplatePath(nuxt); nuxt.hook("builder:watch", async (_event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (path === spaLoadingTemplateFilePath) { await nitro.hooks.callHook("rollup:reload"); } }); const cacheDir = resolve(nuxt.options.buildDir, "cache/nitro/prerender"); const cacheDriverPath = join(distDir, "core/runtime/nitro/cache-driver.js"); await promises.rm(cacheDir, { recursive: true, force: true }).catch(() => { }); nitro.options._config.storage = defu(nitro.options._config.storage, { "internal:nuxt:prerender": { // TODO: resolve upstream where file URLs are not being resolved/inlined correctly driver: isWindows ? pathToFileURL(cacheDriverPath).href : cacheDriverPath, base: cacheDir } }); nuxt._nitro = nitro; await nuxt.callHook("nitro:init", nitro); nitro.vfs = nuxt.vfs = nitro.vfs || nuxt.vfs || {}; nuxt.hook("close", () => nitro.hooks.callHook("close")); nitro.hooks.hook("prerender:routes", (routes) => { return nuxt.callHook("prerender:routes", { routes }); }); if (nuxt.options.vue.runtimeCompiler) { nuxt.hook("vite:extendConfig", (config, { isClient }) => { if (isClient) { if (Array.isArray(config.resolve.alias)) { config.resolve.alias.push({ find: "vue", replacement: "vue/dist/vue.esm-bundler" }); } else { config.resolve.alias = { ...config.resolve.alias, vue: "vue/dist/vue.esm-bundler" }; } } }); for (const hook of ["webpack:config", "rspack:config"]) { nuxt.hook(hook, (configuration) => { const clientConfig = configuration.find((config) => config.name === "client"); if (!clientConfig.resolve) { clientConfig.resolve.alias = {}; } if (Array.isArray(clientConfig.resolve.alias)) { clientConfig.resolve.alias.push({ name: "vue", alias: "vue/dist/vue.esm-bundler" }); } else { clientConfig.resolve.alias.vue = "vue/dist/vue.esm-bundler"; } }); } } const devMiddlewareHandler = dynamicEventHandler(); nitro.options.devHandlers.unshift({ handler: devMiddlewareHandler }); nitro.options.devHandlers.push(...nuxt.options.devServerHandlers); nitro.options.handlers.unshift({ route: "/__nuxt_error", lazy: true, handler: resolve(distDir, "core/runtime/nitro/renderer") }); if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) { nitro.hooks.hook("rollup:before", (nitro2) => { if (nitro2.options.preset === "nitro-prerender") { return; } const nuxtErrorHandler = nitro2.options.handlers.findIndex((h) => h.route === "/__nuxt_error"); if (nuxtErrorHandler >= 0) { nitro2.options.handlers.splice(nuxtErrorHandler, 1); } nitro2.options.renderer = undefined; nitro2.options.errorHandler = "#internal/nitro/error"; }); } nuxt.hook("prepare:types", async (opts) => { if (!nuxt.options.dev) { await scanHandlers(nitro); await writeTypes(nitro); } opts.tsConfig.exclude ||= []; opts.tsConfig.exclude.push(relative(nuxt.options.buildDir, resolve(nuxt.options.rootDir, nitro.options.output.dir))); opts.references.push({ path: resolve(nuxt.options.buildDir, "types/nitro.d.ts") }); }); if (nitro.options.static) { nitro.hooks.hook("prerender:routes", (routes) => { for (const route of ["/200.html", "/404.html"]) { routes.add(route); } if (!nuxt.options.ssr) { routes.add("/index.html"); } }); } if (!nuxt.options.dev) { nitro.hooks.hook("rollup:before", async (nitro2) => { await copyPublicAssets(nitro2); await nuxt.callHook("nitro:build:public-assets", nitro2); }); } async function symlinkDist() { if (nitro.options.static) { const distDir2 = resolve(nuxt.options.rootDir, "dist"); if (!existsSync(distDir2)) { await promises.symlink(nitro.options.output.publicDir, distDir2, "junction").catch(() => { }); } } } nuxt.hook("build:done", async () => { await nuxt.callHook("nitro:build:before", nitro); await prepare(nitro); if (nuxt.options.dev) { return build$1(nitro); } await prerender(nitro); logger$1.restoreAll(); await build$1(nitro); logger$1.wrapAll(); await symlinkDist(); }); if (nuxt.options.dev) { for (const builder of ["webpack", "rspack"]) { nuxt.hook(`${builder}:compile`, ({ name, compiler }) => { if (name === "server") { const memfs = compiler.outputFileSystem; nitro.options.virtual["#build/dist/server/server.mjs"] = () => memfs.readFileSync(join(nuxt.options.buildDir, "dist/server/server.mjs"), "utf-8"); } }); nuxt.hook(`${builder}:compiled`, () => { nuxt.server.reload(); }); } nuxt.hook("vite:compiled", () => { nuxt.server.reload(); }); nuxt.hook("server:devHandler", (h) => { devMiddlewareHandler.set(h); }); nuxt.server = createDevServer(nitro); const waitUntilCompile = new Promise((resolve2) => nitro.hooks.hook("compiled", () => resolve2())); nuxt.hook("build:done", () => waitUntilCompile); } } const RELATIVE_RE = /^([^.])/; function relativeWithDot(from, to) { return relative(from, to).replace(RELATIVE_RE, "./$1") || "."; } async function spaLoadingTemplatePath(nuxt) { if (typeof nuxt.options.spaLoadingTemplate === "string") { return resolve(nuxt.options.srcDir, nuxt.options.spaLoadingTemplate); } const possiblePaths = nuxt.options._layers.map((layer) => resolve(layer.config.srcDir, layer.config.dir?.app || "app", "spa-loading-template.html")); return await findPath(possiblePaths) ?? resolve(nuxt.options.srcDir, nuxt.options.dir?.app || "app", "spa-loading-template.html"); } async function spaLoadingTemplate(nuxt) { if (nuxt.options.spaLoadingTemplate === false) { return ""; } const spaLoadingTemplate2 = await spaLoadingTemplatePath(nuxt); try { if (existsSync(spaLoadingTemplate2)) { return readFileSync(spaLoadingTemplate2, "utf-8").trim(); } } catch { } if (nuxt.options.spaLoadingTemplate === true) { return template(); } if (nuxt.options.spaLoadingTemplate) { logger$1.warn(`Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${nuxt.options.spaLoadingTemplate}\`.`); } return ""; } const schemaModule = defineNuxtModule({ meta: { name: "nuxt:nuxt-config-schema" }, async setup(_, nuxt) { if (!nuxt.options.experimental.configSchema) { return; } const resolver = createResolver(import.meta.url); const _resolveSchema = createJiti(fileURLToPath(import.meta.url), { cache: false, transformOptions: { babel: { plugins: [untypedPlugin] } } }); nuxt.hook("prepare:types", async (ctx) => { ctx.references.push({ path: "schema/nuxt.schema.d.ts" }); if (nuxt.options._prepare) { await writeSchema(schema); } }); let schema; nuxt.hook("modules:done", async () => { schema = await resolveSchema$1(); }); nuxt.hooks.hook("build:done", () => writeSchema(schema)); if (nuxt.options.dev) { const onChange = debounce(async () => { schema = await resolveSchema$1(); await writeSchema(schema); }); if (nuxt.options.experimental.watcher === "parcel") { const watcherPath = await tryResolveModule("@parcel/watcher", [nuxt.options.rootDir, ...nuxt.options.modulesDir]); if (watcherPath) { const { subscribe } = await importModule(watcherPath); for (const layer of nuxt.options._layers) { const subscription = await subscribe(layer.config.rootDir, onChange, { ignore: ["!nuxt.schema.*"] }); nuxt.hook("close", () => subscription.unsubscribe()); } return; } logger.warn("Falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project."); } const isIgnored = createIsIgnored(nuxt); const dirsToWatch = nuxt.options._layers.map((layer) => resolver.resolve(layer.config.rootDir)); const SCHEMA_RE = /(?:^|\/)nuxt.schema.\w+$/; const watcher = watch$1(dirsToWatch, { ...nuxt.options.watchers.chokidar, depth: 1, ignored: [ (path, stats) => stats && !stats.isFile() || !SCHEMA_RE.test(path), isIgnored, /[\\/]node_modules[\\/]/ ], ignoreInitial: true }); watcher.on("all", onChange); nuxt.hook("close", () => watcher.close()); } async function resolveSchema$1() { globalThis.defineNuxtSchema = (val) => val; const schemaDefs = [nuxt.options.$schema]; for (const layer of nuxt.options._layers) { const filePath = await resolver.resolvePath(resolve(layer.config.rootDir, "nuxt.schema")); if (filePath && existsSync(filePath)) { let loadedConfig; try { loadedConfig = await _resolveSchema.import(filePath, { default: true }); } catch (err) { logger.warn( "Unable to load schema from", filePath, err ); continue; } schemaDefs.push(loadedConfig); } } await nuxt.hooks.callHook("schema:extend", schemaDefs); const schemas = await Promise.all( schemaDefs.map((schemaDef) => resolveSchema(schemaDef)) ); const schema2 = defu(...schemas); await nuxt.hooks.callHook("schema:resolved", schema2); return schema2; } async function writeSchema(schema2) { await nuxt.hooks.callHook("schema:beforeWrite", schema2); await mkdir(resolve(nuxt.options.buildDir, "schema"), { recursive: true }); await writeFile( resolve(nuxt.options.buildDir, "schema/nuxt.schema.json"), JSON.stringify(schema2, null, 2), "utf8" ); const _types = generateTypes(schema2, { addExport: true, interfaceName: "NuxtCustomSchema", partial: true, allowExtraKeys: false }); const types = _types + ` export type CustomAppConfig = Exclude<NuxtCustomSchema['appConfig'], undefined> type _CustomAppConfig = CustomAppConfig declare module '@nuxt/schema' { interface NuxtConfig extends Omit<NuxtCustomSchema, 'appConfig'> {} interface NuxtOptions extends Omit<NuxtCustomSchema, 'appConfig'> {} interface CustomAppConfig extends _CustomAppConfig {} } declare module 'nuxt/schema' { interface NuxtConfig extends Omit<NuxtCustomSchema, 'appConfig'> {} interface NuxtOptions extends Omit<NuxtCustomSchema, 'appConfig'> {} interface CustomAppConfig extends _CustomAppConfig {} } `; const typesPath = resolve( nuxt.options.buildDir, "schema/nuxt.schema.d.ts" ); await writeFile(typesPath, types, "utf8"); await nuxt.hooks.callHook("schema:written"); } } }); const internalOrderMap = { // -50: pre-all (nuxt) "nuxt-pre-all": -50, // -40: custom payload revivers (user) "user-revivers": -40, // -30: payload reviving (nuxt) "nuxt-revivers": -30, // -20: pre (user) <-- pre mapped to this "user-pre": -20, // -10: default (nuxt) "nuxt-default": -10, // 0: default (user) <-- default behavior "user-default": 0, // +10: post (nuxt) "nuxt-post": 10, // +20: post (user) <-- post mapped to this "user-post": 20, // +30: post-all (nuxt) "nuxt-post-all": 30 }; const orderMap = { pre: internalOrderMap["user-pre"], default: internalOrderMap["user-default"], post: internalOrderMap["user-post"] }; const metaCache = {}; async function extractMetadata(code, loader = "ts") { let meta = {}; if (metaCache[code]) { return metaCache[code]; } if (code.match(/defineNuxtPlugin\s*\([\w(]/)) { return {}; } const js = await transform(code, { loader }); parseAndWalk(js.code, `file.${loader}`, (node) => { if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } const name = "name" in node.callee && node.callee.name; if (name !== "defineNuxtPlugin" && name !== "definePayloadPlugin") { return; } if (name === "definePayloadPlugin") { meta.order = internalOrderMap["user-revivers"]; } const metaArg = node.arguments[1]; if (metaArg) { if (metaArg.type !== "ObjectExpression") { throw new Error("Invalid plugin metadata"); } meta = extractMetaFromObject(metaArg.properties); } const plugin = node.arguments[0]; if (plugin?.type === "ObjectExpression") { meta = defu(extractMetaFromObject(plugin.properties), meta); } meta.order = meta.order || orderMap[meta.enforce || "default"] || orderMap.default; delete meta.enforce; }); metaCache[code] = meta; return meta; } const keys = { name: "name", order: "order", enforce: "enforce", dependsOn: "dependsOn" }; function isMetadataKey(key) { return key in keys; } function extractMetaFromObject(properties) { const meta = {}; for (const property of properties) { if (property.type === "SpreadElement" || !("name" in property.key)) { throw new Error("Invalid plugin metadata"); } const propertyKey = property.key.name; if (!isMetadataKey(propertyKey)) { continue; } if (property.value.type === "Literal") { meta[propertyKey] = property.value.value; } if (property.value.type === "UnaryExpression" && property.value.argument.type === "Literal") { meta[propertyKey] = JSON.parse(property.value.operator + property.value.argument.raw); } if (propertyKey === "dependsOn" && property.value.type === "ArrayExpression") { if (property.value.elements.some((e) => !e || e.type !== "Literal" || typeof e.value !== "string")) { throw new Error("dependsOn must take an array of string literals"); } meta[propertyKey] = property.value.elements.map((e) => e.value); } } return meta; } const RemovePluginMetadataPlugin = (nuxt) => createUnplugin(() => { return { name: "nuxt:remove-plugin-metadata", transform(code, id) { id = normalize(id); const plugin = nuxt.apps.default?.plugins.find((p) => p.src === id); if (!plugin) { return; } if (!code.trim()) { logger.warn(`Plugin \`${plugin.src}\` has no content.`); return { code: "export default () => {}", map: null }; } const exports = findExports(code); const defaultExport = exports.find((e) => e.type === "default" || e.name === "default"); if (!defaultExport) { logger.warn(`Plugin \`${plugin.src}\` has no default export and will be ignored at build time. Add \`export default defineNuxtPlugin(() => {})\` to your plugin.`); return { code: "export default () => {}", map: null }; } const s = new MagicString(code); let wrapped = false; const wrapperNames = /* @__PURE__ */ new Set(["defineNuxtPlugin", "definePayloadPlugin"]); try { parseAndWalk(code, id, (node) => { if (node.type === "ImportSpecifier" && node.imported.type === "Identifier" && (node.imported.name === "defineNuxtPlugin" || node.imported.name === "definePayloadPlugin")) { wrapperNames.add(node.local.name); } if (node.type === "ExportDefaultDeclaration" && (node.declaration.type === "FunctionDeclaration" || node.declaration.type === "ArrowFunctionExpression")) { if ("params" in node.declaration && node.declaration.params.length > 1) { logger.warn(`Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`); s.overwrite(0, code.length, "export default () => {}"); wrapped = true; return; } } if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } const name = "name" in node.callee && node.callee.name; if (!name || !wrapperNames.has(name)) { return; } wrapped = true; if (node.arguments[0] && node.arguments[0].type !== "ObjectExpression") { if ("params" in node.arguments[0] && node.arguments[0].params.length > 1) { logger.warn(`Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`); s.overwrite(0, code.length, "export default () => {}"); return; } } if (!("order" in plugin) && !("name" in plugin)) { return; } for (const [argIndex, arg] of node.arguments.entries()) { if (arg.type !== "ObjectExpression") { continue; } for (const [propertyIndex, property] of arg.properties.entries()) { if (property.type === "SpreadElement" || !("name" in property.key)) { continue; } const propertyKey = property.key.name; if (propertyKey === "order" || propertyKey === "enforce" || propertyKey === "name") { const nextNode = arg.properties[propertyIndex + 1] || node.arguments[argIndex + 1]; const nextIndex = withLocations(nextNode)?.start || withLocations(arg).end - 1; s.remove(withLocations(property).start, nextIndex); } } } }); } catch (e) { logger.error(e); return; } if (!wrapped) { logger.warn(`Plugin \`${plugin.src}\` is not wrapped in \`defineNuxtPlugin\`. It is advised to wrap your plugins as in the future this may enable enhancements.`); } if (s.hasChanged()) { return { code: s.toString(), map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null }; } } }; }); const AsyncContextInjectionPlugin = (nuxt) => createUnplugin(() => { return { name: "nuxt:vue-async-context", transformInclude(id) { return isVue(id, { type: ["template", "script"] }); }, transform(code) { if (!code.includes("_withAsyncContext")) { return; } const s = new MagicString(code); s.prepend('import { withAsyncContext as _withAsyncContext } from "#app/composables/asyncContext";\n'); s.replace(/withAsyncContext as _withAsyncContext,?/, ""); if (s.hasChanged()) { return { code: s.toString(), map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : undefined }; } } }; }); const stringTypes = ["Literal", "TemplateLiteral"]; const NUXT_LIB_RE = /node_modules\/(?:nuxt|nuxt3|nuxt-nightly)\//; const SUPPORTED_EXT_RE = /\.(?:m?[jt]sx?|vue)/; const SCRIPT_RE = /(?<=<script[^>]*>)[\s\S]*?(?=<\/script>)/i; const ComposableKeysPlugin = (options) => createUnplugin(() => { const composableMeta = {}; const composableLengths = /* @__PURE__ */ new Set(); const keyedFunctions = /* @__PURE__ */ new Set(); for (const { name, ...meta } of options.composables) { composableMeta[name] = meta; keyedFunctions.add(name); composableLengths.add(meta.argumentLength); } const maxLength = Math.max(...composableLengths); const KEYED_FUNCTIONS_RE = new RegExp(`\\b(${[...keyedFunctions].map((f) => escapeRE(f)).join("|")})\\b`); return { name: "nuxt:composable-keys", enforce: "post", transformInclude(id) { const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href)); return !NUXT_LIB_RE.test(pathname) && SUPPORTED_EXT_RE.test(pathname) && parseQuery(search).type !== "style" && !parseQuery(search).macro; }, transform(code, id) { if (!KEYED_FUNCTIONS_RE.test(code)) { return; } const { 0: script = code, index: codeIndex = 0 } = code.match(SCRIPT_RE) || { index: 0, 0: code }; const s = new MagicString(code); let imports; let count = 0; const relativeID = isAbsolute(id) ? relative(options.rootDir, id) : id; const { pathname: relativePathname } = parseURL(relativeID); const scopeTracker = new ScopeTracker({ keepExitedScopes: true }); const ast = parseAndWalk(script, id, { scopeTracker }); scopeTracker.freeze(); walk(ast, { scopeTracker, enter(node) { if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } const name = node.callee.name; if (!name || !keyedFunctions.has(name) || node.arguments.length >= maxLength) { return; } imports = imports || detectImportNames(script, composableMeta); if (imports.has(name)) { return; } const meta = composableMeta[name]; const declaration = scopeTracker.getDeclaration(name); if (declaration && declaration.type !== "Import") { let skip = true; if (meta.source) { skip = !matchWithStringOrRegex(relativePathname, meta.source); } if (skip) { return; } } if (node.arguments.length >= meta.argumentLength) { return; } switch (name) { case "useState": if (stringTypes.includes(node.arguments[0]?.type)) { return; } break; case "useFetch": case "useLazyFetch": if (stringTypes.includes(node.arguments[1]?.type)) { return; } break; case "useAsyncData": case "useLazyAsyncData": if (stringTypes.includes(node.arguments[0]?.type) || stringTypes.includes(node.arguments[node.arguments.length - 1]?.type)) { return; } break; } const newCode = code.slice(codeIndex + node.start, codeIndex + node.end - 1).trim(); const endsWithComma = newCode[newCode.length - 1] === ","; s.appendLeft( codeIndex + node.end - 1, (node.arguments.length && !endsWithComma ? ", " : "") + "'$" + hash(`${relativeID}-${++count}`) + "'" ); } }); if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } }; }); const NUXT_IMPORT_RE = /nuxt|#app|#imports/; function detectImportNames(code, composableMeta) { const names = /* @__PURE__ */ new Set(); function addName(name, specifier) { const source = composableMeta[name]?.source; if (source && matchWithStringOrRegex(specifier, source)) { return; } names.add(name); } for (const i of findStaticImports(code)) { if (NUXT_IMPORT_RE.test(i.specifier)) { continue; } const { namedImports = {}, defaultImport, namespacedImport } = parseStaticImport(i); for (const name in namedImports) { addName(namedImports[name], i.specifier); } if (defaultImport) { addName(defaultImport, i.specifier); } if (namespacedImport) { addName(namespacedImport, i.specifier); } } return names; } function resolveDeepImportsPlugin(nuxt) { const exclude = ["virtual:", "\0virtual:", "/__skip_vite", "@vitest/"]; let conditions; return { name: "nuxt:resolve-bare-imports", enforce: "post", configResolved(config) { conditions = config.mode === "test" ? [...config.resolve.conditions, "import", "require"] : config.resolve.conditions; }, async resolveId(id, importer) { if (!importer || isAbsolute(id) || !isAbsolute(importer) && !importer.startsWith("virtual:") && !importer.startsWith("\0virtual:") || exclude.some((e) => id.startsWith(e))) { return; } const normalisedId = resolveAlias(normalize(id), nuxt.options.alias); const normalisedImporter = importer.replace(/^\0?virtual:(?:nuxt:)?/, ""); const dir = parseNodeModulePath(normalisedImporter).dir || pkgDir; return await this.resolve?.(normalisedId, dir, { skipSelf: true }) ?? await resolvePath(id, { url: [dir, ...nuxt.options.modulesDir], conditions }).catch(() => { logger.debug("Could not resolve id", id, importer); return null; }); } }; } function PrehydrateTransformPlugin(options = {}) { return createUnplugin(() => ({ name: "nuxt:prehydrate-transform", transformInclude(id) { return isJS(id) || isVue(id, { type: ["script"] }); }, async transform(code, id) { if (!code.includes("onPrehydrate(")) { return; } const s = new MagicString(code); const promises = []; parseAndWalk(code, id, (node) => { if (node.type !== "CallExpression" || node.callee.type !== "Identifier") { return; } if (node.callee.name === "onPrehydrate") { const callback = withLocations(node.arguments[0]); if (!callback) { return; } if (callback.type !== "ArrowFunctionExpression" && callback.type !== "FunctionExpression") { return; } const needsAttr = callback.params.length > 0; const p = transform(`forEach(${code.slice(callback.start, callback.end)})`, { loader: "ts", minify: true }); promises.push(p.then(({ code: result }) => { const cleaned = result.slice("forEach".length).replace(/;\s+$/, ""); const args = [JSON.stringify(cleaned)]; if (needsAttr) { args.push(JSON.stringify(hash(result))); } s.overwrite(callback.start, callback.end, args.join(", ")); })); } }); await Promise.all(promises).catch((e) => { console.error(`[nuxt] Could not transform onPrehydrate in \`${id}\`:`, e); }); if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ hires: true }) : undefined }; } } })); } const PREFIX = "virtual:nuxt:"; const RELATIVE_ID_RE = /^\.{1,2}[\\/]/; const VirtualFSPlugin = (nuxt, options) => createUnplugin(() => { const extensions = ["", ...nuxt.options.extensions]; const alias = { ...nuxt.options.alias, ...options.alias }; const resolveWithExt = (id) => { for (const suffix of ["", "." + options.mode]) { for (const ext of extensions) { const rId = id + suffix + ext; if (rId in nuxt.vfs) { return rId; } } } }; return { name: "nuxt:virtual", resolveId(id, importer) { id = resolveAlias(id, alias); if (process.platform === "win32" && isAbsolute(id)) { id = resolve(id); } const resolvedId = resolveWithExt(id); if (resolvedId) { return PREFIX + encodeURIComponent(resolvedId); } if (importer && RELATIVE_ID_RE.test(id)) { const path = resolve(dirname(withoutPrefix(decodeURIComponent(importer))), id); const resolved = resolveWithExt(path); if (resolved) { return PREFIX + encodeURIComponent(resolved); } } }, loadInclude(id) { return id.startsWith(PREFIX) && withoutPrefix(decodeURIComponent(id)) in nuxt.vfs; }, load(id) { return { code: nuxt.vfs[withoutPrefix(decodeURIComponent(id))] || "", map: null }; } }; }); function withoutPrefix(id) { return id.startsWith(PREFIX) ? id.slice(PREFIX.length) : id; } function createNuxt(options) { const hooks = createHooks(); const nuxt = { _version: version, options, hooks, callHook: hooks.callHook, addHooks: hooks.addHooks, hook: hooks.hook, ready: () => initNuxt(nuxt), close: () => hooks.callHook("close", nuxt), vfs: {}, apps: {} }; hooks.hookOnce("close", () => { hooks.removeAllHooks(); }); return nuxt; } const fallbackCompatibilityDate = "2024-04-03"; const nightlies = { "nitropack": "nitropack-nightly", "h3": "h3-nightly", "nuxt": "nuxt-nightly", "@nuxt/schema": "@nuxt/schema-nightly", "@nuxt/kit": "@nuxt/kit-nightly" }; const keyDependencies = [ "@nuxt/kit", "@nuxt/schema" ]; let warnedAboutCompatDate = false; async function initNuxt(nuxt) { for (const config of nuxt.options._layers.map((layer) => layer.config).reverse()) { if (config.hooks) { nuxt.hooks.addHooks(config.hooks); } } nuxt.options.compatibilityDate = resolveCompatibilityDatesFromEnv(nuxt.options.compatibilityDate); if (!nuxt.options.compatibilityDate.default) { const todaysDate = formatDate(/* @__PURE__ */ new Date()); nuxt.options.compatibilityDate.default = fallbackCompatibilityDate; const shouldShowPrompt = nuxt.options.dev && hasTTY && !isCI; if (!shouldShowPrompt) { logger.info(`Using \`${fallbackCompatibilityDate}\` as fallback compatibility date.`); } async function promptAndUpdate() { const result = await consola.prompt(`Do you want to update your ${colorize("cyan", "nuxt.config")} to set ${colorize("cyan", `compatibilityDate: '${todaysDate}'`)}?`, { type: "confirm", default: true }); if (result !== true) { logger.info(`Using \`${fallbackCompatibilityDate}\` as fallback compatibility date.`); return; } try { const res = await updateConfig({ configFile: "nuxt.config", cwd: nuxt.options.rootDir, async onCreate({ configFile }) { const shallCreate = await consola.prompt(`Do you want to create ${colorize("cyan", relative(nuxt.options.rootDir, configFile))}?`, { type: "confirm", default: true }); if (shallCreate !== true) { return false; } return _getDefaultNuxtConfig(); }, onUpdate(config) { config.compatibilityDate = todaysDate; } }); if (res?.configFile) { nuxt.options.compatibilityDate = resolveCompatibilityDatesFromEnv(todaysDate); consola.success(`Compatibility date set to \`${todaysDate}\` in \`${relative(nuxt.options.rootDir, res.configFile)}\``); return; } } catch (err) { const message = err instanceof Error ? err.message : err; consola.error(`Failed to update config: ${message}`); } logger.info(`Using \`${fallbackCompatibilityDate}\` as fallback compatibility date.`); } nuxt.hooks.hookOnce("nitro:init", (nitro2) => { if (warnedAboutCompatDate) { return; } nitro2.hooks.hookOnce("compiled", () => { warnedAboutCompatDate = true; logger.info(`Nuxt now supports pinning the behavior of provider and deployment presets with a compatibility date. We recommend you specify a \`compatibilityDate\` in your \`nuxt.config\` file, or set an environment variable, such as \`COMPATIBILITY_DATE=${todaysDate}\`.`); if (shouldShowPrompt) { promptAndUpdate(); } }); }); } const layersDir = withTrailingSlash(resolve(nuxt.options.rootDir, "layers")); nuxt.hook("builder:watch", (event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (event === "addDir" || event === "unlinkDir") { if (path.startsWith(layersDir)) { return nuxt.callHook("restart", { hard: true }); } } }); nuxtCtx.set(nuxt); nuxt.hook("close", () => nuxtCtx.unset()); const coreTypePackages = nuxt.options.typescript.hoist || []; if (nuxt.options.typescript.builder !== false) { const envMap = { // defaults from `builder` based on package name "@nuxt/rspack-builder": "@rspack/core/module", "@nuxt/vite-builder": "vite/client", "@nuxt/webpack-builder": "webpack/module", // simpler overrides from `typescript.builder` for better DX "rspack": "@rspack/core/module", "vite": "vite/client", "webpack": "webpack/module", // default 'merged' builder environment for module authors "shared": "@nuxt/schema/builder-env" }; const overrideEnv = nuxt.options.typescript.builder && envMap[nuxt.options.typescript.builder]; const defaultEnv = typeof nuxt.options.builder === "string" ? envMap[nuxt.options.builder] : false; const environmentTypes = overrideEnv || defaultEnv; if (environmentTypes) { nuxt.options.typescript.hoist.push(environmentTypes); addTypeTemplate({ filename: "types/builder-env.d.ts", getContents: () => genImport(environmentTypes) }); } } const packageJSON = await readPackageJSON(nuxt.options.rootDir).catch(() => ({})); const NESTED_PKG_RE = /^[^@]+\//; nuxt._dependencies = /* @__PURE__ */ new Set([...Object.keys(packageJSON.dependencies || {}), ...Object.keys(packageJSON.devDependencies || {})]); const paths = Object.fromEntries(await Promise.all(coreTypePackages.map(async (pkg) => { const [_pkg = pkg, _subpath] = NESTED_PKG_RE.test(pkg) ? pkg.split("/") : [pkg]; const subpath = _subpath ? "/" + _subpath : ""; if (nuxt._dependencies?.has(_pkg) && !(_pkg in nightlies)) { return []; } if (_pkg in nightlies) { const nightly = nightlies[_pkg]; const path2 = await resolveTypePath(nightly + subpath, subpath, nuxt.options.modulesDir); if (path2) { return [[pkg, [path2]], [nightly + subpath, [path2]]]; } } const path = await resolveTypePath(_pkg + subpath, subpath, nuxt.options.modulesDir); if (path) { return [[pkg, [path]]]; } return []; })).then((r) => r.flat())); nuxt.options.nitro.typescript = defu$1(nuxt.options.nitro.typescript, { tsConfig: { compilerOptions: { paths: { ...paths } } } }); nuxt.hook("prepare:types", (opts) => { opts.references.push({ types: "nuxt" }); opts.references.push({ path: resolve(nuxt.options.buildDir, "types/app-defaults.d.ts") }); opts.references.push({ path: resolve(nuxt.options.buildDir, "types/plugins.d.ts") }); if (nuxt.options.typescript.shim) { opts.references.push({ path: resolve(nuxt.options.buildDir, "types/vue-shim.d.ts") }); } opts.references.push({ path: resolve(nuxt.options.buildDir, "types/build.d.ts") }); opts.references.push({ path: resolve(nuxt.options.buildDir, "types/schema.d.ts") }); opts.references.push({ path: resolve(nuxt.options.buildDir, "types/app.config.d.ts") }); opts.tsConfig.compilerOptions = defu$1(opts.tsConfig.compilerOptions, { paths: { ...paths } }); for (const layer of nuxt.options._layers) { const declaration = join(layer.cwd, "index.d.ts"); if (existsSync(declaration)) { opts.references.push({ path: declaration }); } } }); if (nuxt.options.scripts) { if (!nuxt.options._modules.some((m) => m === "@nuxt/scripts" || m === "@nuxt/scripts-nightly")) { await import('../chunks/features.mjs').then(({ installNuxtModule }) => installNuxtModule("@nuxt/scripts")); } } addBuildPlugin(VirtualFSPlugin(nuxt, { mode: "server" }), { client: false }); addBuildPlugin(VirtualFSPlugin(nuxt, { mode: "client", alias: { "#internal/nitro": join(nuxt.options.buildDir, "nitro.client.mjs") } }), { server: false }); addBuildPlugin(RemovePluginMetadataPlugin(nuxt)); addBuildPlugin(ComposableKeysPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, rootDir: nuxt.options.rootDir, composables: nuxt.options.optimization.keyedComposables })); const sharedDir = withTrailingSlash(resolve(nuxt.options.rootDir, nuxt.options.dir.shared)); const relativeSharedDir = withTrailingSlash(relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, nuxt.options.dir.shared))); const sharedPatterns = [/^#shared\//, new RegExp("^" + escapeRE(sharedDir)), new RegExp("^" + escapeRE(relativeSharedDir))]; const sharedProtectionConfig = { cwd: nuxt.options.rootDir, include: sharedPatterns, patterns: createImportProtectionPatterns(nuxt, { context: "shared" }) }; addVitePlugin(() => ImpoundPlugin.vite(sharedProtectionConfig), { server: false }); addWebpackPlugin(() => ImpoundPlugin.webpack(sharedProtectionConfig), { server: false }); const nuxtProtectionConfig = { cwd: nuxt.options.rootDir, // Exclude top-level resolutions by plugins exclude: [relative(nuxt.options.rootDir, join(nuxt.options.srcDir, "index.html")), ...sharedPatterns], patterns: createImportProtectionPatterns(nuxt, { context: "nuxt-app" }) }; addVitePlugin(() => Object.assign(ImpoundPlugin.vite({ ...nuxtProtectionConfig, error: false }), { name: "nuxt:import-protection" }), { client: false }); addVitePlugin(() => Object.assign(ImpoundPlugin.vite({ ...nuxtProtectionConfig, error: true }), { name: "nuxt:import-protection" }), { server: false }); addWebpackPlugin(() => ImpoundPlugin.webpack(nuxtProtectionConfig)); addVitePlugin(() => resolveDeepImportsPlugin(nuxt), { client: false }); addVitePlugin(() => resolveDeepImportsPlugin(nuxt), { server: false }); addBuildPlugin(PrehydrateTransformPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client })); if (nuxt.options.experimental.localLayerAliases) { addBuildPlugin(LayerAliasingPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, dev: nuxt.options.dev, root: nuxt.options.srcDir, // skip top-level layer (user's project) as the aliases will already be correctly resolved layers: nuxt.options._layers.slice(1) })); } nuxt.hook("modules:done", async () => { addBuildPlugin(UnctxTransformPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, transformerOptions: { ...nuxt.options.optimization.asyncTransforms, helperModule: await tryResolveModule("unctx", nuxt.options.modulesDir) ?? "unctx" } })); if (Object.keys(nuxt.options.optimization.treeShake.composables.server).length) { addBuildPlugin(TreeShakeComposablesPlugin({ sourcemap: !!nuxt.options.sourcemap.server, composables: nuxt.options.optimization.treeShake.composables.server }), { client: false }); } if (Object.keys(nuxt.options.optimization.treeShake.composables.client).length) { addBuildPlugin(TreeShakeComposablesPlugin({ sourcemap: !!nuxt.options.sourcemap.client, composables: nuxt.options.optimization.treeShake.composables.client }), { server: false }); } }); if (!nuxt.options.dev) { addBuildPlugin(DevOnlyPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client })); } if (nuxt.options.dev) { addPlugin(resolve(nuxt.options.appDir, "plugins/check-if-layout-used")); } if (nuxt.options.dev && nuxt.options.features.devLogs) { addPlugin(resolve(nuxt.options.appDir, "plugins/dev-server-logs")); addServerPlugin(resolve(distDir, "core/runtime/nitro/dev-server-logs")); nuxt.options.nitro = defu$1(nuxt.options.nitro, { externals: { inline: [/#internal\/dev-server-logs-options/] }, virtual: { "#internal/dev-server-logs-options": () => `export const rootDir = ${JSON.stringify(nuxt.options.rootDir)};` } }); } if (nuxt.options.experimental.asyncContext) { addBuildPlugin(AsyncContextInjectionPlugin(nuxt), { client: false }); } if (nuxt.options.features.noScripts && !nuxt.options.dev) { nuxt.hook("build:manifest", async (manifest) => { for (const chunk of Object.values(manifest)) { if (chunk.resourceType === "script") { await rm(resolve(nuxt.options.buildDir, "dist/client", withoutLeadingSlash(nuxt.options.app.buildAssetsDir), chunk.file), { force: true }); chunk.file = ""; } } }); } nuxt.options.build.transpile.push("nuxt/app"); nuxt.options.build.transpile.push( ...nuxt.options._layers.filter((i) => i.cwd.includes("node_modules")).map((i) => i.cwd) ); const locallyScannedLayersDirs = nuxt.options._layers.map((l) => resolve(l.cwd, "layers").replace(/\/?$/, "/")); nuxt.options.modulesDir.push(...nuxt.options._layers.filter((l) => l.cwd !== nuxt.options.rootDir && locallyScannedLayersDirs.every((dir) => !l.cwd.startsWith(dir))).map((l) => resolve(l.cwd, "node_modules"))); await nuxt.callHook("modules:before"); const modulesToInstall = /* @__PURE__ */ new Map(); const watchedPaths = /* @__PURE__ */ new Set(); const specifiedModules = /* @__PURE__ */ new Set(); for (const _mod of nuxt.options.modules) { const mod = Array.isArray(_mod) ? _mod[0] : _mod; if (typeof mod !== "string") { continue; } const modPath = await resolvePath$1(resolveAlias(mod), { fallbackToOriginal: true }); specifiedModules.add(modPath); } for (const config of nuxt.options._layers.map((layer) => layer.config).reverse()) { const modulesDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.modules || "modules"; const layerModules = await resolveFiles(config.srcDir, [ `${modulesDir}/*{${nuxt.options.extensions.join(",")}}`, `${modulesDir}/*/index{${nuxt.options.extensions.join(",")}}` ]); for (const mod of layerModules) { watchedPaths.add(mod); if (specifiedModules.has(mod)) { continue; } specifiedModules.add(mod); modulesToInstall.set(mod, {}); } } for (const key of ["modules", "_modules"]) { for (const item of nuxt.options[key]) { if (item) { const [key2, options = {}] = Array.isArray(item) ? item : [item]; if (!modulesToInstall.has(key2)) { modulesToInstall.set(key2, options); } } } } const islandsConfig = nuxt.options.experimental.componentIslands; if (nuxt.options.dev || !(typeof islandsConfig === "object" && islandsConfig.selectiveClient === "deep")) { addComponent({ name: "NuxtWelcome", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/welcome") }); } addComponent({ name: "NuxtLayout", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-layout") }); addComponent({ name: "NuxtErrorBoundary", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-error-boundary") }); addComponent({ name: "ClientOnly", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/client-only") }); addComponent({ name: "DevOnly", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/dev-only") }); addComponent({ name: "ServerPlaceholder", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/server-placeholder") }); addComponent({ name: "NuxtLink", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-link") }); addComponent({ name: "NuxtLoadingIndicator", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-loading-indicator") }); addComponent({ name: "NuxtRouteAnnouncer", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-route-announcer"), mode: "client" }); if (nuxt.options.experimental.clientFallback) { addComponent({ name: "NuxtClientFallback", _raw: true, priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/client-fallback.client"), mode: "client" }); addComponent({ name: "NuxtClientFallback", _raw: true, priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/client-fallback.server"), mode: "server" }); } for (const name of ["NuxtImg", "NuxtPicture"]) { addComponent({ name, export: name, priority: -1, filePath: resolve(nuxt.options.appDir, "components/nuxt-stubs"), // @ts-expect-error TODO: refactor to nuxi _internal_install: "@nuxt/image" }); } if (nuxt.options.builder === "@nuxt/webpack-builder") { addPlugin(resolve(nuxt.options.appDir, "plugins/preload.server")); } if (nuxt.options.debug) { addPlugin(resolve(nuxt.options.appDir, "plugins/debug")); } if (nuxt.options.experimental.browserDevtoolsTiming) { addPlugin(resolve(nuxt.options.appDir, "plugins/browser-devtools-timing.client")); } for (const [key, options] of modulesToInstall) { await installModule(key, options); } nuxt._ignore = ignore(nuxt.options.ignoreOptions); nuxt._ignore.add(resolveIgnorePatterns()); await nuxt.callHook("modules:done"); if (nuxt.options.experimental.componentIslands) { addComponent({ name: "NuxtIsland", priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, "components/nuxt-island") }); if (!nuxt.options.ssr && nuxt.options.experimental.componentIslands !== "auto") { nuxt.options.ssr = true; nuxt.options.nitro.routeRules ||= {}; nuxt.options.nitro.routeRules["/**"] = defu$1(nuxt.options.nitro.routeRules["/**"], { ssr: false }); } } if (!nuxt.options.dev && nuxt.options.experimental.payloadExtraction) { addPlugin(resolve(nuxt.options.appDir, "plugins/payload.client")); } if (nuxt.options.experimental.crossOriginPrefetch) { addPlugin(resolve(nuxt.options.appDir, "plugins/cross-origin-prefetch.client")); } if (nuxt.options.experimental.emitRouteChunkError === "automatic") { addPlugin(resolve(nuxt.options.appDir, "plugins/chunk-reload.client")); } if (nuxt.options.experimental.emitRouteChunkError === "automatic-immediate") { addPlugin(resolve(nuxt.options.appDir, "plugins/chunk-reload-immediate.client")); } if (nuxt.options.experimental.restoreState) { addPlugin(resolve(nuxt.options.appDir, "plugins/restore-state.client")); } if (nuxt.options.experimental.viewTransition) { addPlugin(resolve(nuxt.options.appDir, "plugins/view-transitions.client")); } if (nuxt.options.experimental.renderJsonPayloads) { addPlugin(resolve(nuxt.options.appDir, "plugins/revive-payload.client")); addPlugin(resolve(nuxt.options.appDir, "plugins/revive-payload.server")); } if (nuxt.options.experimental.appManifest) { addRouteMiddleware({ name: "manifest-route-rule", path: resolve(nuxt.options.appDir, "middleware/manifest-route-rule"), global: true }); if (nuxt.options.experimental.checkOutdatedBuildInterval !== false) { addPlugin(resolve(nuxt.options.appDir, "plugins/check-outdated-build.client")); } } if (nuxt.options.experimental.navigationRepaint) { addPlugin({ src: resolve(nuxt.options.appDir, "plugins/navigation-repaint.client") }); } if (nuxt.options.vue.config && Object.values(nuxt.options.vue.config).some((v) => v !== null && v !== undefined)) { addPluginTemplate({ filename: "vue-app-config.mjs", getContents: () => ` import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { ${Object.keys(nuxt.options.vue.config).map((k) => ` nuxtApp.vueApp.config[${JSON.stringify(k)}] = ${JSON.stringify(nuxt.options.vue.config[k])}`).join("\n")} } })` }); } nuxt.hooks.hook("builder:watch", (event, relativePath) => { const path = resolve(nuxt.options.srcDir, relativePath); if (watchedPaths.has(path)) { return nuxt.callHook("restart", { hard: true }); } const layerRelativePaths = nuxt.options._layers.map((l) => relative(l.config.srcDir || l.cwd, path)); for (const pattern of nuxt.options.watch) { if (typeof pattern === "string") { if (pattern === path || layerRelativePaths.includes(pattern)) { return nuxt.callHook("restart"); } continue; } if (layerRelativePaths.some((p) => pattern.test(p))) { return nuxt.callHook("restart"); } } if (event === "addDir" && path === resolve(nuxt.options.srcDir, "app")) { logger.info(`\`${path}/\` ${event === "addDir" ? "created" : "removed"}`); return nuxt.callHook("restart", { hard: true }); } const isFileChange = ["add", "unlink"].includes(event); if (isFileChange && RESTART_RE.test(path)) { logger.info(`\`${path}\` ${event === "add" ? "created" : "removed"}`); return nuxt.callHook("restart"); } }); nuxt.options.build.transpile = nuxt.options.build.transpile.map((t) => typeof t === "string" ? normalize(t) : t); addModuleTranspiles(); await initNitro(nuxt); const nitro = useNitro(); if (nitro.options.static && nuxt.options.experimental.payloadExtraction === undefined) { logger.warn("Using experimental payload extraction for full-static output. You can opt-out by setting `experimental.payloadExtraction` to `false`."); nuxt.options.experimental.payloadExtraction = true; } nitro.options.replace["process.env.NUXT_PAYLOAD_EXTRACTION"] = String(!!nuxt.options.experimental.payloadExtraction); nitro.options._config.replace["process.env.NUXT_PAYLOAD_EXTRACTION"] = String(!!nuxt.options.experimental.payloadExtraction); if (!nuxt.options.dev && nuxt.options.experimental.payloadExtraction) { addPlugin(resolve(nuxt.options.appDir, "plugins/payload.client")); } if (!satisfies(nuxt._version, nuxt.options.future.compatibilityVersion + ".x")) { logger.info(`Running with compatibility version \`${nuxt.options.future.compatibilityVersion}\``); } await nuxt.callHook("ready", nuxt); } async function loadNuxt(opts) { const options = await loadNuxtConfig(opts); options.appDir = options.alias["#app"] = resolve(distDir, "app"); options._majorVersion = 3; for (const key in options.app.head || {}) { options.app.head[key] = deduplicateArray(options.app.head[key]); } if (options.builder === "@nuxt/vite-builder") { const isDevToolsEnabled = typeof options.devtools === "boolean" ? options.devtools : options.devtools?.enabled !== false; if (isDevToolsEnabled) { if (!options._modules.some((m) => m === "@nuxt/devtools" || m === "@nuxt/devtools-edge")) { options._modules.push("@nuxt/devtools"); } } } if (!options._modules.some((m) => m === "@nuxt/scripts" || m === "@nuxt/scripts-nightly")) { options.imports = defu$1(options.imports, { presets: [scriptsStubsPreset] }); } if (options.builder === "@nuxt/webpack-builder") { if (!await import('../chunks/features.mjs').then((r) => r.ensurePackageInstalled("@nuxt/webpack-builder", { rootDir: options.rootDir, searchPaths: options.modulesDir }))) { logger.warn("Failed to install `@nuxt/webpack-builder`, please install it manually, or change the `builder` option to vite in `nuxt.config`"); } } options._modules.push(pagesModule, metaModule, componentsModule); options._modules.push([importsModule, { transform: { include: options._layers.filter((i) => i.cwd && i.cwd.includes("node_modules")).map((i) => new RegExp(`(^|\\/)${escapeRE(i.cwd.split("node_modules/").pop())}(\\/|$)(?!node_modules\\/)`)) } }]); options._modules.push(schemaModule); options.modulesDir.push(resolve(options.workspaceDir, "node_modules")); options.modulesDir.push(resolve(pkgDir, "node_modules")); options.build.transpile.push( "std-env" // we need to statically replace process.env when used in runtime code ); options.alias["vue-demi"] = resolve(options.appDir, "compat/vue-demi"); options.alias["@vue/composition-api"] = resolve(options.appDir, "compat/capi"); if (options.telemetry !== false && !process.env.NUXT_TELEMETRY_DISABLED) { options._modules.push("@nuxt/telemetry"); } createPortalProperties(options.nitro.runtimeConfig, options, ["nitro.runtimeConfig", "runtimeConfig"]); createPortalProperties(options.nitro.routeRules, options, ["nitro.routeRules", "routeRules"]); const nitroOptions = options.nitro; Object.defineProperties(options, { nitro: { configurable: false, enumerable: true, get: () => nitroOptions, set(value) { Object.assign(nitroOptions, value); } } }); const nuxt = createNuxt(options); if (nuxt.options.dev && !nuxt.options.test) { nuxt.hooks.hookOnce("build:done", () => { for (const dep of keyDependencies) { checkDependencyVersion(dep, nuxt._version).catch((e) => logger.warn(`Problem checking \`${dep}\` version.`, e)); } }); } if (opts.overrides?.hooks) { nuxt.hooks.addHooks(opts.overrides.hooks); } if (nuxt.options.debug) { createDebugger(nuxt.hooks, { tag: "nuxt" }); } if (opts.ready !== false) { await nuxt.ready(); } return nuxt; } async function checkDependencyVersion(name, nuxtVersion) { const path = await resolvePath$1(name, { fallbackToOriginal: true }).catch(() => null); if (!path || path === name) { return; } const { version: version2 } = await readPackageJSON(path); if (version2 && gt(nuxtVersion, version2)) { console.warn(`[nuxt] Expected \`${name}\` to be at least \`${nuxtVersion}\` but got \`${version2}\`. This might lead to unexpected behavior. Check your package.json or refresh your lockfile.`); } } const RESTART_RE = /^(?:app|error|app\.config)\.(?:js|ts|mjs|jsx|tsx|vue)$/i; function deduplicateArray(maybeArray) { if (!Array.isArray(maybeArray)) { return maybeArray; } const fresh = []; const hashes = /* @__PURE__ */ new Set(); for (const item of maybeArray) { const _hash = hash(item); if (!hashes.has(_hash)) { hashes.add(_hash); fresh.push(item); } } return fresh; } function createPortalProperties(sourceValue, options, paths) { let sharedValue = sourceValue; for (const path of paths) { const segments = path.split("."); const key = segments.pop(); let parent = options; while (segments.length) { const key2 = segments.shift(); parent = parent[key2] || (parent[key2] = {}); } delete parent[key]; Object.defineProperties(parent, { [key]: { configurable: false, enumerable: true, get: () => sharedValue, set(value) { sharedValue = value; } } }); } } const _getDefaultNuxtConfig = () => ( /* js */ `// https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ devtools: { enabled: true } }) ` ); const vueShim = { filename: "types/vue-shim.d.ts", getContents: ({ nuxt }) => { if (!nuxt.options.typescript.shim) { return ""; } return [ "declare module '*.vue' {", " import { DefineComponent } from 'vue'", " const component: DefineComponent<{}, {}, any>", " export default component", "}" ].join("\n"); } }; const appComponentTemplate = { filename: "app-component.mjs", getContents: (ctx) => genExport(ctx.app.mainComponent, ["default"]) }; const rootComponentTemplate = { filename: "root-component.mjs", // TODO: fix upstream in vite - this ensures that vite generates a module graph for islands // but should not be necessary (and has a warmup performance cost). See https://github.com/nuxt/nuxt/pull/24584. getContents: (ctx) => (ctx.nuxt.options.dev ? "import '#build/components.islands.mjs';\n" : "") + genExport(ctx.app.rootComponent, ["default"]) }; const errorComponentTemplate = { filename: "error-component.mjs", getContents: (ctx) => genExport(ctx.app.errorComponent, ["default"]) }; const testComponentWrapperTemplate = { filename: "test-component-wrapper.mjs", getContents: (ctx) => genExport(resolve(ctx.nuxt.options.appDir, "components/test-component-wrapper"), ["default"]) }; const cssTemplate = { filename: "css.mjs", getContents: (ctx) => ctx.nuxt.options.css.map((i) => genImport(i)).join("\n") }; const PLUGIN_TEMPLATE_RE = /_(45|46|47)/g; const clientPluginTemplate = { filename: "plugins.client.mjs", async getContents(ctx) { const clientPlugins = await annotatePlugins(ctx.nuxt, ctx.app.plugins.filter((p) => !p.mode || p.mode !== "server")); checkForCircularDependencies(clientPlugins); const exports = []; const imports = []; for (const plugin of clientPlugins) { const path = relative(ctx.nuxt.options.rootDir, plugin.src); const variable = genSafeVariableName(filename(plugin.src) || path).replace(PLUGIN_TEMPLATE_RE, "_") + "_" + hash(path); exports.push(variable); imports.push(genImport(plugin.src, variable)); } return [ ...imports, `export default ${genArrayFromRaw(exports)}` ].join("\n"); } }; const serverPluginTemplate = { filename: "plugins.server.mjs", async getContents(ctx) { const serverPlugins = await annotatePlugins(ctx.nuxt, ctx.app.plugins.filter((p) => !p.mode || p.mode !== "client")); checkForCircularDependencies(serverPlugins); const exports = []; const imports = []; for (const plugin of serverPlugins) { const path = relative(ctx.nuxt.options.rootDir, plugin.src); const variable = genSafeVariableName(filename(plugin.src) || path).replace(PLUGIN_TEMPLATE_RE, "_") + "_" + hash(path); exports.push(variable); imports.push(genImport(plugin.src, variable)); } return [ ...imports, `export default ${genArrayFromRaw(exports)}` ].join("\n"); } }; const appDefaults = { filename: "types/app-defaults.d.ts", getContents: (ctx) => { const isV4 = ctx.nuxt.options.future.compatibilityVersion === 4; return ` declare module 'nuxt/app/defaults' { type DefaultAsyncDataErrorValue = ${isV4 ? "undefined" : "null"} type DefaultAsyncDataValue = ${isV4 ? "undefined" : "null"} type DefaultErrorValue = ${isV4 ? "undefined" : "null"} type DedupeOption = ${isV4 ? "'cancel' | 'defer'" : "boolean | 'cancel' | 'defer'"} }`; } }; const TS_RE = /\.[cm]?tsx?$/; const JS_LETTER_RE = /\.(?<letter>[cm])?jsx?$/; const JS_RE = /\.[cm]jsx?$/; const JS_CAPTURE_RE = /\.[cm](jsx?)$/; const pluginsDeclaration = { filename: "types/plugins.d.ts", getContents: async ({ nuxt, app }) => { const EXTENSION_RE2 = new RegExp(`(?<=\\w)(${nuxt.options.extensions.map((e) => escapeRE(e)).join("|")})$`, "g"); const typesDir = join(nuxt.options.buildDir, "types"); const tsImports = []; const pluginNames = []; function exists(path) { return app.templates.some((t) => t.write && path === t.dst) || existsSync(path); } for (const plugin of await annotatePlugins(nuxt, app.plugins)) { if (plugin.name) { pluginNames.push(`'${plugin.name}'`); } const pluginPath = resolve(typesDir, plugin.src); const relativePath = relative(typesDir, pluginPath); const correspondingDeclaration = pluginPath.replace(JS_LETTER_RE, ".d.$<letter>ts"); if (correspondingDeclaration !== pluginPath && exists(correspondingDeclaration)) { tsImports.push(relativePath); continue; } const incorrectDeclaration = pluginPath.replace(JS_RE, ".d.ts"); if (incorrectDeclaration !== pluginPath && exists(incorrectDeclaration)) { tsImports.push(relativePath.replace(JS_CAPTURE_RE, ".$1")); continue; } if (exists(pluginPath)) { if (TS_RE.test(pluginPath)) { tsImports.push(relativePath.replace(EXTENSION_RE2, "")); continue; } tsImports.push(relativePath); } } return `// Generated by Nuxt' import type { Plugin } from '#app' type Decorate<T extends Record<string, any>> = { [K in keyof T as K extends string ? \`$\${K}\` : never]: T[K] } type InjectionType<A extends Plugin> = A extends {default: Plugin<infer T>} ? Decorate<T> : unknown type NuxtAppInjections = ${tsImports.map((p) => `InjectionType<typeof ${genDynamicImport(p, { wrapper: false })}>`).join(" &\n ")} declare module '#app' { interface NuxtApp extends NuxtAppInjections { } interface NuxtAppLiterals { pluginName: ${pluginNames.join(" | ")} } } declare module 'vue' { interface ComponentCustomProperties extends NuxtAppInjections { } } export { } `; } }; const IMPORT_NAME_RE = /\.\w+$/; const GIT_RE = /^git\+/; const schemaTemplate = { filename: "types/schema.d.ts", getContents: async ({ nuxt }) => { const relativeRoot = relative(resolve(nuxt.options.buildDir, "types"), nuxt.options.rootDir); const getImportName = (name) => (name[0] === "." ? "./" + join(relativeRoot, name) : name).replace(IMPORT_NAME_RE, ""); const modules = nuxt.options._installedModules.filter((m) => m.meta && m.meta.configKey && m.meta.name && !m.meta.name.startsWith("nuxt:") && m.meta.name !== "nuxt-config-schema").map((m) => [genString(m.meta.configKey), getImportName(m.entryPath || m.meta.name), m]); const privateRuntimeConfig = /* @__PURE__ */ Object.create(null); for (const key in nuxt.options.runtimeConfig) { if (key !== "public") { privateRuntimeConfig[key] = nuxt.options.runtimeConfig[key]; } } const moduleOptionsInterface = (options) => [ ...modules.flatMap(([configKey, importName, mod]) => { let link; if (!mod.meta?.rawPath) { link = `https://www.npmjs.com/package/${importName}`; } if (typeof mod.meta?.docs === "string") { link = mod.meta.docs; } else if (mod.meta?.repository) { if (typeof mod.meta.repository === "string") { link = mod.meta.repository; } else if (typeof mod.meta.repository.url === "string") { link = mod.meta.repository.url; } if (link) { if (link.startsWith("git+")) { link = link.replace(GIT_RE, ""); } if (!link.startsWith("http")) { link = "https://github.com/" + link; } } } return [ ` /**`, ` * Configuration for \`${importName}\``, ...options.addJSDocTags && link ? [` * @see ${link}`] : [], ` */`, ` [${configKey}]${options.unresolved ? "?" : ""}: typeof ${genDynamicImport(importName, { wrapper: false })}.default extends NuxtModule<infer O> ? ${options.unresolved ? "Partial<O>" : "O"} : Record<string, any>` ]; }), modules.length > 0 && options.unresolved ? ` modules?: (undefined | null | false | NuxtModule<any> | string | [NuxtModule | string, Record<string, any>] | ${modules.map(([configKey, importName, mod]) => `[${genString(mod.meta?.rawPath || importName)}, Exclude<NuxtConfig[${configKey}], boolean>]`).join(" | ")})[],` : "" ].filter(Boolean); return [ "import { NuxtModule, RuntimeConfig } from '@nuxt/schema'", "declare module '@nuxt/schema' {", " interface NuxtOptions {", ...moduleOptionsInterface({ addJSDocTags: false, unresolved: false }), " }", " interface NuxtConfig {", // TypeScript will duplicate the jsdoc tags if we augment it twice // So here we only generate tags for `nuxt/schema` ...moduleOptionsInterface({ addJSDocTags: false, unresolved: true }), " }", "}", "declare module 'nuxt/schema' {", " interface NuxtOptions {", ...moduleOptionsInterface({ addJSDocTags: true, unresolved: false }), " }", " interface NuxtConfig {", ...moduleOptionsInterface({ addJSDocTags: true, unresolved: true }), " }", generateTypes( await resolveSchema(privateRuntimeConfig), { interfaceName: "RuntimeConfig", addExport: false, addDefaults: false, allowExtraKeys: false, indentation: 2 } ), generateTypes( await resolveSchema(nuxt.options.runtimeConfig.public), { interfaceName: "PublicRuntimeConfig", addExport: false, addDefaults: false, allowExtraKeys: false, indentation: 2 } ), "}", `declare module 'vue' { interface ComponentCustomProperties { $config: RuntimeConfig } }` ].join("\n"); } }; const layoutTemplate = { filename: "layouts.mjs", getContents({ app }) { const layoutsObject = genObjectFromRawEntries(Object.values(app.layouts).map(({ name, file }) => { return [name, `defineAsyncComponent(${genDynamicImport(file, { interopDefault: true })})`]; })); return [ `import { defineAsyncComponent } from 'vue'`, `export default ${layoutsObject}` ].join("\n"); } }; const middlewareTemplate = { filename: "middleware.mjs", getContents({ app }) { const globalMiddleware = app.middleware.filter((mw) => mw.global); const namedMiddleware = app.middleware.filter((mw) => !mw.global); const namedMiddlewareObject = genObjectFromRawEntries(namedMiddleware.map((mw) => [mw.name, genDynamicImport(mw.path)])); return [ ...globalMiddleware.map((mw) => genImport(mw.path, genSafeVariableName(mw.name))), `export const globalMiddleware = ${genArrayFromRaw(globalMiddleware.map((mw) => genSafeVariableName(mw.name)))}`, `export const namedMiddleware = ${namedMiddlewareObject}` ].join("\n"); } }; const nitroSchemaTemplate = { filename: "types/nitro-nuxt.d.ts", getContents() { return ( /* typescript */ ` /// <reference path="./schema.d.ts" /> import type { RuntimeConfig } from 'nuxt/schema' import type { H3Event } from 'h3' import type { LogObject } from 'consola' import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from 'nuxt/app' declare module 'nitropack' { interface NitroRuntimeConfigApp { buildAssetsDir: string cdnURL: string } interface NitroRuntimeConfig extends RuntimeConfig {} interface NitroRouteConfig { ssr?: boolean experimentalNoScripts?: boolean } interface NitroRouteRules { ssr?: boolean experimentalNoScripts?: boolean appMiddleware?: Record<string, boolean> } interface NitroRuntimeHooks { 'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void> 'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void> 'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void> } } ` ); } }; const clientConfigTemplate = { filename: "nitro.client.mjs", getContents: ({ nuxt }) => { const appId = JSON.stringify(nuxt.options.appId); return [ "export const useRuntimeConfig = () => ", (!nuxt.options.future.multiApp ? "window?.__NUXT__?.config || {}" : `window?.__NUXT__?.[${appId}]?.config || {}`) || {} ].join("\n"); } }; const appConfigDeclarationTemplate = { filename: "types/app.config.d.ts", getContents({ app, nuxt }) { const typesDir = join(nuxt.options.buildDir, "types"); const configPaths = app.configs.map((path) => relative(typesDir, path).replace(EXTENSION_RE, "")); return ` import type { CustomAppConfig } from 'nuxt/schema' import type { Defu } from 'defu' ${configPaths.map((id, index) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join("\n")} declare const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} type ResolvedAppConfig = Defu<typeof inlineConfig, [${app.configs.map((_id, index) => `typeof cfg${index}`).join(", ")}]> type IsAny<T> = 0 extends 1 & T ? true : false type MergedAppConfig<Resolved extends Record<string, unknown>, Custom extends Record<string, unknown>> = { [K in keyof (Resolved & Custom)]: K extends keyof Custom ? unknown extends Custom[K] ? Resolved[K] : IsAny<Custom[K]> extends true ? Resolved[K] : Custom[K] extends Record<string, any> ? Resolved[K] extends Record<string, any> ? MergedAppConfig<Resolved[K], Custom[K]> : Exclude<Custom[K], undefined> : Exclude<Custom[K], undefined> : Resolved[K] } declare module 'nuxt/schema' { interface AppConfig extends MergedAppConfig<ResolvedAppConfig, CustomAppConfig> { } } declare module '@nuxt/schema' { interface AppConfig extends MergedAppConfig<ResolvedAppConfig, CustomAppConfig> { } } `; } }; const appConfigTemplate = { filename: "app.config.mjs", write: true, getContents({ app, nuxt }) { return ` import { updateAppConfig } from '#app/config' import { defuFn } from 'defu' const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} // Vite - webpack is handled directly in #app/config if (import.meta.hot) { import.meta.hot.accept((newModule) => { updateAppConfig(newModule.default) }) } ${app.configs.map((id, index) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join("\n")} export default /*@__PURE__*/ defuFn(${app.configs.map((_id, index) => `cfg${index}`).concat(["inlineConfig"]).join(", ")}) `; } }; const publicPathTemplate = { filename: "paths.mjs", getContents({ nuxt }) { return [ "import { joinRelativeURL } from 'ufo'", !nuxt.options.dev && "import { useRuntimeConfig } from '#internal/nitro'", nuxt.options.dev ? `const appConfig = ${JSON.stringify(nuxt.options.app)}` : "const appConfig = useRuntimeConfig().app", "export const baseURL = () => appConfig.baseURL", "export const buildAssetsDir = () => appConfig.buildAssetsDir", "export const buildAssetsURL = (...path) => joinRelativeURL(publicAssetsURL(), buildAssetsDir(), ...path)", "export const publicAssetsURL = (...path) => {", " const publicBase = appConfig.cdnURL || appConfig.baseURL", " return path.length ? joinRelativeURL(publicBase, ...path) : publicBase", "}", // On server these are registered directly in packages/nuxt/src/core/runtime/nitro/renderer.ts "if (import.meta.client) {", " globalThis.__buildAssetsURL = buildAssetsURL", " globalThis.__publicAssetsURL = publicAssetsURL", "}" ].filter(Boolean).join("\n"); } }; const dollarFetchTemplate = { filename: "fetch.mjs", getContents() { return [ "import { $fetch } from 'ofetch'", "import { baseURL } from '#internal/nuxt/paths'", "if (!globalThis.$fetch) {", " globalThis.$fetch = $fetch.create({", " baseURL: baseURL()", " })", "}" ].join("\n"); } }; const nuxtConfigTemplate = { filename: "nuxt.config.mjs", getContents: (ctx) => { const fetchDefaults = { ...ctx.nuxt.options.experimental.defaults.useFetch, baseURL: undefined, headers: undefined }; const shouldEnableComponentIslands = ctx.nuxt.options.experimental.componentIslands && (ctx.nuxt.options.dev || ctx.nuxt.options.experimental.componentIslands !== "auto" || ctx.app.pages?.some((p) => p.mode === "server") || ctx.app.components?.some((c) => c.mode === "server" && !ctx.app.components.some((other) => other.pascalName === c.pascalName && other.mode === "client"))); return [ ...Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase("app-" + k)} = ${JSON.stringify(v)}`), `export const renderJsonPayloads = ${!!ctx.nuxt.options.experimental.renderJsonPayloads}`, `export const componentIslands = ${shouldEnableComponentIslands}`, `export const payloadExtraction = ${!!ctx.nuxt.options.experimental.payloadExtraction}`, `export const cookieStore = ${!!ctx.nuxt.options.experimental.cookieStore}`, `export const appManifest = ${!!ctx.nuxt.options.experimental.appManifest}`, `export const remoteComponentIslands = ${typeof ctx.nuxt.options.experimental.componentIslands === "object" && ctx.nuxt.options.experimental.componentIslands.remoteIsland}`, `export const selectiveClient = ${typeof ctx.nuxt.options.experimental.componentIslands === "object" && Boolean(ctx.nuxt.options.experimental.componentIslands.selectiveClient)}`, `export const devPagesDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.dir.pages) : "null"}`, `export const devRootDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.rootDir) : "null"}`, `export const devLogs = ${JSON.stringify(ctx.nuxt.options.features.devLogs)}`, `export const nuxtLinkDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.nuxtLink)}`, `export const asyncDataDefaults = ${JSON.stringify({ ...ctx.nuxt.options.experimental.defaults.useAsyncData, value: ctx.nuxt.options.experimental.defaults.useAsyncData.value === "null" ? null : undefined, errorValue: ctx.nuxt.options.experimental.defaults.useAsyncData.errorValue === "null" ? null : undefined })}`, `export const resetAsyncDataToUndefined = ${ctx.nuxt.options.experimental.resetAsyncDataToUndefined}`, `export const nuxtDefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? "undefined" : "null"}`, `export const fetchDefaults = ${JSON.stringify(fetchDefaults)}`, `export const vueAppRootContainer = ${ctx.nuxt.options.app.rootAttrs.id ? `'#${ctx.nuxt.options.app.rootAttrs.id}'` : `'body > ${ctx.nuxt.options.app.rootTag}'`}`, `export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`, `export const appId = ${JSON.stringify(ctx.nuxt.options.appId)}`, `export const outdatedBuildInterval = ${ctx.nuxt.options.experimental.checkOutdatedBuildInterval}`, `export const multiApp = ${!!ctx.nuxt.options.future.multiApp}`, `export const chunkErrorEvent = ${ctx.nuxt.options.experimental.emitRouteChunkError ? ctx.nuxt.options.builder === "@nuxt/vite-builder" ? '"vite:preloadError"' : '"nuxt:preloadError"' : "false"}`, `export const crawlLinks = ${!!ctx.nuxt._nitro.options.prerender.crawlLinks}`, `export const spaLoadingTemplateOutside = ${ctx.nuxt.options.experimental.spaLoadingTemplateLocation === "body"}` ].join("\n\n"); } }; const TYPE_FILENAME_RE = /\.([cm])?[jt]s$/; const DECLARATION_RE = /\.d\.[cm]?ts$/; const buildTypeTemplate = { filename: "types/build.d.ts", getContents({ app }) { let declarations = ""; for (const file of app.templates) { if (file.write || !file.filename || DECLARATION_RE.test(file.filename)) { continue; } if (TYPE_FILENAME_RE.test(file.filename)) { const typeFilenames = /* @__PURE__ */ new Set([file.filename.replace(TYPE_FILENAME_RE, ".d.$1ts"), file.filename.replace(TYPE_FILENAME_RE, ".d.ts")]); if (app.templates.some((f) => f.filename && typeFilenames.has(f.filename))) { continue; } } declarations += "declare module " + JSON.stringify(join("#build", file.filename)) + ";\n"; } return declarations; } }; const defaultTemplates = { __proto__: null, appComponentTemplate: appComponentTemplate, appConfigDeclarationTemplate: appConfigDeclarationTemplate, appConfigTemplate: appConfigTemplate, appDefaults: appDefaults, buildTypeTemplate: buildTypeTemplate, clientConfigTemplate: clientConfigTemplate, clientPluginTemplate: clientPluginTemplate, cssTemplate: cssTemplate, dollarFetchTemplate: dollarFetchTemplate, errorComponentTemplate: errorComponentTemplate, layoutTemplate: layoutTemplate, middlewareTemplate: middlewareTemplate, nitroSchemaTemplate: nitroSchemaTemplate, nuxtConfigTemplate: nuxtConfigTemplate, pluginsDeclaration: pluginsDeclaration, publicPathTemplate: publicPathTemplate, rootComponentTemplate: rootComponentTemplate, schemaTemplate: schemaTemplate, serverPluginTemplate: serverPluginTemplate, testComponentWrapperTemplate: testComponentWrapperTemplate, vueShim: vueShim }; function createApp(nuxt, options = {}) { return defu(options, { dir: nuxt.options.srcDir, extensions: nuxt.options.extensions, plugins: [], components: [], templates: [] }); } const postTemplates = [ clientPluginTemplate.filename, serverPluginTemplate.filename, pluginsDeclaration.filename ]; async function generateApp(nuxt, app, options = {}) { await resolveApp(nuxt, app); app.templates = Object.values(defaultTemplates).concat(nuxt.options.build.templates); await nuxt.callHook("app:templates", app); app.templates = app.templates.map((tmpl) => normalizeTemplate(tmpl, nuxt.options.buildDir)); const filteredTemplates = { pre: [], post: [] }; for (const template of app.templates) { if (options.filter && !options.filter(template)) { continue; } const key = template.filename && postTemplates.includes(template.filename) ? "post" : "pre"; filteredTemplates[key].push(template); } const templateContext = { utils: templateUtils, nuxt, app }; const compileTemplate$1 = nuxt.options.experimental.compileTemplate ? compileTemplate : futureCompileTemplate; const writes = []; const dirs = /* @__PURE__ */ new Set(); const changedTemplates = []; const FORWARD_SLASH_RE = /\//g; async function processTemplate(template) { const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename); const start = performance.now(); const oldContents = nuxt.vfs[fullPath]; const contents = await compileTemplate$1(template, templateContext).catch((e) => { logger.error(`Could not compile template \`${template.filename}\`.`); logger.error(e); throw e; }); template.modified = oldContents !== contents; if (template.modified) { nuxt.vfs[fullPath] = contents; const aliasPath = "#build/" + template.filename; nuxt.vfs[aliasPath] = contents; if (process.platform === "win32") { nuxt.vfs[fullPath.replace(FORWARD_SLASH_RE, "\\")] = contents; } changedTemplates.push(template); } const perf = performance.now() - start; const setupTime = Math.round(perf * 100) / 100; if (nuxt.options.debug || setupTime > 500) { logger.info(`Compiled \`${template.filename}\` in ${setupTime}ms`); } if (template.modified && template.write) { dirs.add(dirname(fullPath)); writes.push(() => writeFileSync(fullPath, contents, "utf8")); } } await Promise.allSettled(filteredTemplates.pre.map(processTemplate)); await Promise.allSettled(filteredTemplates.post.map(processTemplate)); for (const dir of dirs) { mkdirSync(dir, { recursive: true }); } for (const write of writes) { write(); } if (changedTemplates.length) { await nuxt.callHook("app:templatesGenerated", app, changedTemplates, options); } } async function futureCompileTemplate(template, ctx) { delete ctx.utils; if (template.src) { try { return await promises.readFile(template.src, "utf-8"); } catch (err) { logger.error(`[nuxt] Error reading template from \`${template.src}\``); throw err; } } if (template.getContents) { return template.getContents({ ...ctx, options: template.options }); } throw new Error("[nuxt] Invalid template. Templates must have either `src` or `getContents`: " + JSON.stringify(template)); } async function resolveApp(nuxt, app) { if (!app.mainComponent) { app.mainComponent = await findPath( nuxt.options._layers.flatMap((layer) => [ join(layer.config.srcDir, "App"), join(layer.config.srcDir, "app") ]) ); } if (!app.mainComponent) { app.mainComponent = resolve(nuxt.options.appDir, "components/welcome.vue"); } if (!app.rootComponent) { app.rootComponent = await findPath(["~/app.root", resolve(nuxt.options.appDir, "components/nuxt-root.vue")]); } if (!app.errorComponent) { app.errorComponent = await findPath( nuxt.options._layers.map((layer) => join(layer.config.srcDir, "error")) ) ?? resolve(nuxt.options.appDir, "components/nuxt-error-page.vue"); } const layerConfigs = nuxt.options._layers.map((layer) => layer.config); const reversedConfigs = layerConfigs.slice().reverse(); app.layouts = {}; for (const config of layerConfigs) { const layoutDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.layouts || "layouts"; const layoutFiles = await resolveFiles(config.srcDir, `${layoutDir}/**/*{${nuxt.options.extensions.join(",")}}`); for (const file of layoutFiles) { const name = getNameFromPath(file, resolve(config.srcDir, layoutDir)); if (!name) { logger.warn(`No layout name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a layout name.`); continue; } app.layouts[name] = app.layouts[name] || { name, file }; } } app.middleware = []; for (const config of reversedConfigs) { const middlewareDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.middleware || "middleware"; const middlewareFiles = await resolveFiles(config.srcDir, [ `${middlewareDir}/*{${nuxt.options.extensions.join(",")}}`, ...nuxt.options.future.compatibilityVersion === 4 ? [`${middlewareDir}/*/index{${nuxt.options.extensions.join(",")}}`] : [] ]); for (const file of middlewareFiles) { const name = getNameFromPath(file); if (!name) { logger.warn(`No middleware name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a middleware name.`); continue; } app.middleware.push({ name, path: file, global: hasSuffix(file, ".global") }); } } app.plugins = []; for (const config of reversedConfigs) { const pluginDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.plugins || "plugins"; app.plugins.push(...[ ...config.plugins || [], ...config.srcDir ? await resolveFiles(config.srcDir, [ `${pluginDir}/*{${nuxt.options.extensions.join(",")}}`, `${pluginDir}/*/index{${nuxt.options.extensions.join(",")}}` ]) : [] ].map((plugin) => normalizePlugin(plugin))); } for (const p of [...nuxt.options.plugins].reverse()) { const plugin = normalizePlugin(p); if (!app.plugins.some((p2) => p2.src === plugin.src)) { app.plugins.unshift(plugin); } } app.middleware = uniqueBy(await resolvePaths([...app.middleware].reverse(), "path"), "name").reverse(); app.plugins = uniqueBy(await resolvePaths(app.plugins, "src"), "src"); app.configs = []; for (const config of layerConfigs) { const appConfigPath = await findPath(resolve(config.srcDir, "app.config")); if (appConfigPath) { app.configs.push(appConfigPath); } } await nuxt.callHook("app:resolve", app); app.middleware = uniqueBy(await resolvePaths(app.middleware, "path"), "name"); app.plugins = uniqueBy(await resolvePaths(app.plugins, "src"), "src"); } function resolvePaths(items, key) { return Promise.all(items.map(async (item) => { if (!item[key]) { return item; } return { ...item, [key]: await resolvePath$1(resolveAlias(item[key])) }; })); } const IS_TSX = /\.[jt]sx$/; async function annotatePlugins(nuxt, plugins) { const _plugins = []; for (const plugin of plugins) { try { const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src] : await promises.readFile(plugin.src, "utf-8"); _plugins.push({ ...await extractMetadata(code, IS_TSX.test(plugin.src) ? "tsx" : "ts"), ...plugin }); } catch (e) { const relativePluginSrc = relative(nuxt.options.rootDir, plugin.src); if (e.message === "Invalid plugin metadata") { logger.warn(`Failed to parse static properties from plugin \`${relativePluginSrc}\`, falling back to non-optimized runtime meta. Learn more: https://nuxt.com/docs/guide/directory-structure/plugins#object-syntax-plugins`); } else { logger.warn(`Failed to parse static properties from plugin \`${relativePluginSrc}\`.`, e); } _plugins.push(plugin); } } return _plugins.sort((a, b) => (a.order ?? orderMap.default) - (b.order ?? orderMap.default)); } function checkForCircularDependencies(_plugins) { const deps = /* @__PURE__ */ Object.create(null); const pluginNames = _plugins.map((plugin) => plugin.name); for (const plugin of _plugins) { if (plugin.dependsOn && plugin.dependsOn.some((name) => !pluginNames.includes(name))) { console.error(`Plugin \`${plugin.name}\` depends on \`${plugin.dependsOn.filter((name) => !pluginNames.includes(name)).join(", ")}\` but they are not registered.`); } if (plugin.name) { deps[plugin.name] = plugin.dependsOn || []; } } const checkDeps = (name, visited = []) => { if (visited.includes(name)) { console.error(`Circular dependency detected in plugins: ${visited.join(" -> ")} -> ${name}`); return []; } visited.push(name); return deps[name]?.length ? deps[name].flatMap((dep) => checkDeps(dep, [...visited])) : []; }; for (const name in deps) { checkDeps(name); } } async function checkForExternalConfigurationFiles() { const checkResults = await Promise.all([checkViteConfig(), checkWebpackConfig(), checkNitroConfig(), checkPostCSSConfig()]); const warningMessages = checkResults.filter(Boolean); if (!warningMessages.length) { return; } const foundOneExternalConfig = warningMessages.length === 1; if (foundOneExternalConfig) { logger.warn(warningMessages[0]); } else { const warningsAsList = warningMessages.map((message) => `- ${message}`).join("\n"); const warning = `Found multiple external configuration files: ${warningsAsList}`; logger.warn(warning); } } async function checkViteConfig() { return await checkAndWarnAboutConfigFileExistence({ fileName: "vite.config", extensions: [".js", ".mjs", ".ts", ".cjs", ".mts", ".cts"], createWarningMessage: (foundFile) => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.vite\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#vite\`.` }); } async function checkWebpackConfig() { return await checkAndWarnAboutConfigFileExistence({ fileName: "webpack.config", extensions: [".js", ".mjs", ".ts", ".cjs", ".mts", ".cts", "coffee"], createWarningMessage: (foundFile) => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.webpack\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#webpack-1\`.` }); } async function checkNitroConfig() { return await checkAndWarnAboutConfigFileExistence({ fileName: "nitro.config", extensions: [".ts", ".mts"], createWarningMessage: (foundFile) => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.nitro\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#nitro\`.` }); } async function checkPostCSSConfig() { return await checkAndWarnAboutConfigFileExistence({ fileName: "postcss.config", extensions: [".js", ".cjs"], createWarningMessage: (foundFile) => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.postcss\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#postcss\`.` }); } async function checkAndWarnAboutConfigFileExistence(options) { const { fileName, extensions, createWarningMessage } = options; const configFile = await findPath(fileName, { extensions }).catch(() => null); if (configFile) { return createWarningMessage(basename(configFile)); } } async function getVueHash(nuxt) { const id = "vue"; const { hash: hash2 } = await getHashes(nuxt, { id, cwd: (layer) => layer.config?.srcDir, patterns: (layer) => [ join(relative(layer.cwd, layer.config.srcDir), "**"), `!${relative(layer.cwd, layer.config.serverDir || join(layer.cwd, "server"))}/**`, `!${relative(layer.cwd, resolve$1(layer.config.srcDir || layer.cwd, layer.config.dir?.public || "public"))}/**`, `!${relative(layer.cwd, resolve$1(layer.config.srcDir || layer.cwd, layer.config.dir?.static || "public"))}/**`, "!node_modules/**", "!nuxt.config.*" ], configOverrides: { buildId: undefined, serverDir: undefined, nitro: undefined, devServer: undefined, runtimeConfig: undefined, logLevel: undefined, devServerHandlers: undefined, generate: undefined, devtools: undefined } }); const cacheFile = join(nuxt.options.workspaceDir, "node_modules/.cache/nuxt/builds", id, hash2 + ".tar"); return { hash: hash2, async collectCache() { const start = Date.now(); await writeCache(nuxt.options.buildDir, nuxt.options.buildDir, cacheFile); const elapsed = Date.now() - start; consola$1.success(`Cached Vue client and server builds in \`${elapsed}ms\`.`); }, async restoreCache() { const start = Date.now(); const res = await restoreCache(nuxt.options.buildDir, cacheFile); const elapsed = Date.now() - start; if (res) { consola$1.success(`Restored Vue client and server builds from cache in \`${elapsed}ms\`.`); } return res; } }; } async function cleanupCaches(nuxt) { const start = Date.now(); const caches = await glob(["*/*.tar"], { cwd: join(nuxt.options.workspaceDir, "node_modules/.cache/nuxt/builds"), absolute: true }); if (caches.length >= 10) { const cachesWithMeta = await Promise.all(caches.map(async (cache) => { return [cache, await stat(cache).then((r) => r.mtime.getTime()).catch(() => 0)]; })); cachesWithMeta.sort((a, b) => a[1] - b[1]); for (const [cache] of cachesWithMeta.slice(0, cachesWithMeta.length - 10)) { await unlink(cache); } const elapsed = Date.now() - start; consola$1.success(`Cleaned up old build caches in \`${elapsed}ms\`.`); } } async function getHashes(nuxt, options) { if (nuxt[`_${options.id}BuildHash`]) { return nuxt[`_${options.id}BuildHash`]; } const start = Date.now(); const hashSources = []; let layerCtr = 0; for (const layer of nuxt.options._layers) { if (layer.cwd.includes("node_modules")) { continue; } const layerName = `layer#${layerCtr++}`; hashSources.push({ name: `${layerName}:config`, data: objectHash({ ...layer.config, ...options.configOverrides || {} }) }); const normalizeFiles = (files) => files.map((f) => ({ name: f.name, size: f.attrs?.size, data: murmurHash( f.data /* ArrayBuffer */ ) })); const isIgnored = createIsIgnored(nuxt); const sourceFiles = await readFilesRecursive(options.cwd(layer), { shouldIgnore: isIgnored, // TODO: Validate if works with absolute paths cwd: nuxt.options.rootDir, patterns: options.patterns(layer) }); hashSources.push({ name: `${layerName}:src`, data: normalizeFiles(sourceFiles) }); const rootFiles = await readFilesRecursive(layer.config?.rootDir || layer.cwd, { shouldIgnore: isIgnored, // TODO: Validate if works with absolute paths cwd: nuxt.options.rootDir, patterns: [ ".nuxtrc", ".npmrc", "package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "tsconfig.json", "bun.lockb" ] }); hashSources.push({ name: `${layerName}:root`, data: normalizeFiles(rootFiles) }); } const res = nuxt[`_${options.id}BuildHash`] = { hash: hash(hashSources), sources: hashSources }; const elapsed = Date.now() - start; consola$1.debug(`Computed \`${options.id}\` build hash in \`${elapsed}ms\`.`); return res; } async function readFilesRecursive(dir, opts) { if (Array.isArray(dir)) { return (await Promise.all(dir.map((d) => readFilesRecursive(d, opts)))).flat(); } const files = await glob(opts.patterns, { cwd: dir }); const fileEntries = await Promise.all(files.map(async (fileName) => { if (!opts.shouldIgnore?.(fileName)) { const file = await readFileWithMeta(dir, fileName); if (!file) { return; } return { ...file, name: relative(opts.cwd, join(dir, file.name)) }; } })); return fileEntries.filter(Boolean); } async function readFileWithMeta(dir, fileName, count = 0) { let fd = undefined; try { fd = await open(resolve$1(dir, fileName)); const stats = await fd.stat(); if (!stats?.isFile()) { return; } const mtime = stats.mtime.getTime(); const data = await fd.readFile(); if ((await fd.stat()).mtime.getTime() !== mtime) { if (count < 5) { return readFileWithMeta(dir, fileName, count + 1); } console.warn(`Failed to read file \`${fileName}\` as it changed during read.`); return; } return { name: fileName, data, attrs: { mtime, size: stats.size } }; } catch (err) { console.warn(`Failed to read file \`${fileName}\`:`, err); } finally { await fd?.close(); } } async function restoreCache(cwd, cacheFile) { if (!existsSync(cacheFile)) { return false; } const files = parseTar(await readFile(cacheFile)); for (const file of files) { let fd = undefined; try { const filePath = resolve$1(cwd, file.name); await mkdir(dirname(filePath), { recursive: true }); fd = await open(filePath, "w"); const stats = await fd.stat().catch(() => null); if (stats?.isFile() && stats.size) { const lastModified = Number.parseInt(file.attrs?.mtime?.toString().padEnd(13, "0") || "0"); if (stats.mtime.getTime() >= lastModified) { consola$1.debug(`Skipping \`${file.name}\` (up to date or newer than cache)`); continue; } } await fd.writeFile(file.data); } catch (err) { console.error(err); } finally { await fd?.close(); } } return true; } async function writeCache(cwd, sources, cacheFile) { const fileEntries = await readFilesRecursive(sources, { patterns: ["**/*", "!analyze/**"], cwd }); const tarData = createTar(fileEntries); await mkdir(dirname(cacheFile), { recursive: true }); await writeFile(cacheFile, tarData); } async function build(nuxt) { const app = createApp(nuxt); nuxt.apps.default = app; const generateApp$1 = debounce(() => generateApp(nuxt, app), undefined, { leading: true }); await generateApp$1(); if (nuxt.options.dev) { watch(nuxt); nuxt.hook("builder:watch", async (event, relativePath) => { if (event === "add" || event === "unlink") { const path = resolve(nuxt.options.srcDir, relativePath); for (const layer of nuxt.options._layers) { const relativePath2 = relative(layer.config.srcDir || layer.cwd, path); if (relativePath2.match(/^app\./i)) { app.mainComponent = undefined; break; } if (relativePath2.match(/^error\./i)) { app.errorComponent = undefined; break; } } } await generateApp$1(); }); nuxt.hook("builder:generateApp", (options) => { if (options) { return generateApp(nuxt, app, options); } return generateApp$1(); }); } if (!nuxt.options._prepare && !nuxt.options.dev && nuxt.options.experimental.buildCache) { const { restoreCache, collectCache } = await getVueHash(nuxt); if (await restoreCache()) { await nuxt.callHook("build:done"); return await nuxt.callHook("close", nuxt); } nuxt.hooks.hookOnce("nitro:build:before", () => collectCache()); nuxt.hooks.hookOnce("close", () => cleanupCaches(nuxt)); } await nuxt.callHook("build:before"); if (nuxt.options._prepare) { nuxt.hook("prepare:types", () => nuxt.close()); return; } if (nuxt.options.dev && !nuxt.options.test) { nuxt.hooks.hookOnce("build:done", () => { checkForExternalConfigurationFiles().catch((e) => logger.warn("Problem checking for external configuration files.", e)); }); } await bundle(nuxt); await nuxt.callHook("build:done"); if (!nuxt.options.dev) { await nuxt.callHook("close", nuxt); } } const watchEvents = { create: "add", delete: "unlink", update: "change" }; async function watch(nuxt) { if (nuxt.options.experimental.watcher === "parcel") { const success = await createParcelWatcher(); if (success) { return; } } if (nuxt.options.experimental.watcher === "chokidar") { return createWatcher(); } return createGranularWatcher(); } function createWatcher() { const nuxt = useNuxt(); const isIgnored2 = createIsIgnored(nuxt); const watcher = watch$1(nuxt.options._layers.map((i) => i.config.srcDir).filter(Boolean), { ...nuxt.options.watchers.chokidar, ignoreInitial: true, ignored: [isIgnored2, /[\\/]node_modules[\\/]/] }); watcher.on("all", (event, path) => { if (event === "all" || event === "ready" || event === "error" || event === "raw") { return; } nuxt.callHook("builder:watch", event, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, path)) : normalize(path)); }); nuxt.hook("close", () => watcher?.close()); } function createGranularWatcher() { const nuxt = useNuxt(); const isIgnored2 = createIsIgnored(nuxt); if (nuxt.options.debug) { console.time("[nuxt] builder:chokidar:watch"); } let pending = 0; const ignoredDirs = /* @__PURE__ */ new Set([...nuxt.options.modulesDir, nuxt.options.buildDir]); const pathsToWatch = nuxt.options._layers.map((layer) => layer.config.srcDir || layer.cwd).filter((d) => d && !isIgnored2(d)); for (const pattern of nuxt.options.watch) { if (typeof pattern !== "string") { continue; } const path = resolve(nuxt.options.srcDir, pattern); if (pathsToWatch.some((w) => path.startsWith(w.replace(/[^/]$/, "$&/")))) { continue; } pathsToWatch.push(path); } for (const dir of pathsToWatch) { pending++; const watcher = watch$1(dir, { ...nuxt.options.watchers.chokidar, ignoreInitial: false, depth: 0, ignored: [isIgnored2, /[\\/]node_modules[\\/]/] }); const watchers = {}; watcher.on("all", (event, path) => { if (event === "all" || event === "ready" || event === "error" || event === "raw") { return; } path = normalize(path); if (!pending) { nuxt.callHook("builder:watch", event, nuxt.options.experimental.relativeWatchPaths ? relative(nuxt.options.srcDir, path) : path); } if (event === "unlinkDir" && path in watchers) { watchers[path]?.close(); delete watchers[path]; } if (event === "addDir" && path !== dir && !ignoredDirs.has(path) && !pathsToWatch.includes(path) && !(path in watchers) && !isIgnored2(path)) { const pathWatcher = watchers[path] = watch$1(path, { ...nuxt.options.watchers.chokidar, ignored: [isIgnored2] }); pathWatcher.on("all", (event2, p) => { if (event2 === "all" || event2 === "ready" || event2 === "error" || event2 === "raw") { return; } nuxt.callHook("builder:watch", event2, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, p)) : normalize(p)); }); nuxt.hook("close", () => watchers[path]?.close()); } }); watcher.on("ready", () => { pending--; if (nuxt.options.debug && !pending) { console.timeEnd("[nuxt] builder:chokidar:watch"); } }); nuxt.hook("close", () => watcher?.close()); } } async function createParcelWatcher() { const nuxt = useNuxt(); if (nuxt.options.debug) { console.time("[nuxt] builder:parcel:watch"); } const watcherPath = await tryResolveModule("@parcel/watcher", [nuxt.options.rootDir, ...nuxt.options.modulesDir]); if (!watcherPath) { logger.warn("Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project."); return false; } const { subscribe } = await importModule(watcherPath); for (const layer of nuxt.options._layers) { if (!layer.config.srcDir) { continue; } const watcher = subscribe(layer.config.srcDir, (err, events) => { if (err) { return; } for (const event of events) { if (isIgnored(event.path)) { continue; } nuxt.callHook("builder:watch", watchEvents[event.type], nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, event.path)) : normalize(event.path)); } }, { ignore: [ ...nuxt.options.ignore, "node_modules" ] }); watcher.then((subscription) => { if (nuxt.options.debug) { console.timeEnd("[nuxt] builder:parcel:watch"); } nuxt.hook("close", () => subscription.unsubscribe()); }); } return true; } async function bundle(nuxt) { try { const { bundle: bundle2 } = typeof nuxt.options.builder === "string" ? await loadBuilder(nuxt, nuxt.options.builder) : nuxt.options.builder; await bundle2(nuxt); } catch (error) { await nuxt.callHook("build:error", error); if (error.toString().includes("Cannot find module '@nuxt/webpack-builder'")) { throw new Error("Could not load `@nuxt/webpack-builder`. You may need to add it to your project dependencies, following the steps in `https://github.com/nuxt/framework/pull/2812`."); } throw error; } } async function loadBuilder(nuxt, builder) { const builderPath = await tryResolveModule(builder, [nuxt.options.rootDir, import.meta.url]); if (!builderPath) { throw new Error(`Loading \`${builder}\` builder failed. You can read more about the nuxt \`builder\` option at: \`https://nuxt.com/docs/api/nuxt-config#builder\``); } return importModule(builderPath); } export { loadNuxt as a, build as b, createNuxt as c, logger as l };
修改文件时间
将文件时间修改为当前时间的前一年
删除文件