nuxt
Version:
1,252 lines • 333 kB
JavaScript
import process from "node:process";
import fs, { existsSync, mkdirSync, promises, readdirSync, statSync, writeFileSync } from "node:fs";
import { mkdir, open, readFile, readdir, rm, stat, unlink, writeFile } from "node:fs/promises";
import { createHash, randomUUID } from "node:crypto";
import { AsyncLocalStorage } from "node:async_hooks";
import { basename, dirname, extname, isAbsolute, join, normalize, parse, relative, resolve } from "pathe";
import { createDebugger, createHooks } from "hookable";
import ignore from "ignore";
import { addBuildPlugin, addComponent, addImportsSources, addPlugin, addPluginTemplate, addRouteMiddleware, addTemplate, addTypeTemplate, addVitePlugin, buildDiagnostics, componentDiagnostics, configDiagnostics, createIsIgnored, createResolver, defineNuxtModule, directoryToURL, findPath, getLayerDirectories, headDiagnostics, importModule, installModules, isIgnored, loadNuxtConfig, normalizeModuleTranspilePath, normalizePlugin, normalizeTemplate, nuxtCtx, packageName, pageDiagnostics, pluginDiagnostics, resolveAlias, resolveDeclarationPath, resolveFiles, resolveIgnorePatterns, resolveModuleWithOptions, resolvePath, resolveTypePaths, runWithNuxtContext, tryUseNuxt, updateTemplates, useLogger, useNitro, useNuxt } from "@nuxt/kit";
import { readPackage, readPackageJSON, resolvePackageJSON } from "pkg-types";
import { hash, isEqual, serialize } from "ohash";
import onChange from "on-change";
import { formatDate, resolveCompatibilityDatesFromEnv } from "compatx";
import escapeStringRegexp from "escape-string-regexp";
import { joinURL, withTrailingSlash, withoutLeadingSlash } from "ufo";
import { ImpoundPlugin } from "impound";
import { defu } from "defu";
import { coerce, satisfies } from "verkit";
import { hasTTY, isCI, provider } from "std-env";
import { genArrayFromRaw, genDynamicImport, genDynamicTypeImport, genExport, genImport, genInlineTypeImport, genObjectFromRawEntries, genObjectKey, genSafeVariableName, genString } from "knitwork";
import { resolveModulePath } from "exsolve";
import { addDependency } from "nypm";
import { filename, resolveAlias as resolveAlias$1, reverseResolveAlias } from "pathe/utils";
import { createRoutesContext, resolveOptions } from "vue-router/unplugin";
import { addRoute, createRouter, findAllRoutes } from "rou3";
import { fileURLToPath, pathToFileURL } from "node:url";
import picomatch from "picomatch";
import { klona } from "klona";
import { ScopeTracker, getUndeclaredIdentifiersInFunction, isBindingIdentifier, parseAndWalk, walk } from "oxc-walker";
import { addFile, buildTree, compileParsePath, removeFile, toVueRouter4, vueRouterToRou3 } from "unrouting";
import { camelCase, kebabCase, pascalCase, splitByCase } from "scule";
import { createUnplugin } from "unplugin";
import { findExports, findStaticImports, parseStaticImport } from "mlly";
import MagicString from "magic-string";
import { generateTransform, rolldownString } from "rolldown-string";
import { streamingIifeCode } from "unhead/stream/iife";
import { unheadVueComposablesImports } from "@unhead/vue";
import { createUnimport, defineUnimportPreset, scanDirExports, toExports, toTypeDeclarationFile, toTypeReExports } from "unimport";
import { glob } from "tinyglobby";
import { ELEMENT_NODE, parse as parse$1, walk as walk$1 } from "ultrahtml";
import { isObject } from "@vue/shared";
import { consola } from "consola";
import { createTar, parseTar } from "nanotar";
import { createTransformer, getTransformFilter } from "unctx/transform";
import { performance } from "node:perf_hooks";
import { colors } from "consola/utils";
import { watch } from "chokidar";
import { debounce } from "perfect-debounce";
import { generateTypes, resolveSchema } from "untyped";
import untypedPlugin from "untyped/babel-plugin";
import { createJiti } from "jiti";
import { minifySync, transformSync } from "rolldown/utils";
import { Diagnostic } from "nostics";
//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __exportAll = (all, no_symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
//#endregion
//#region src/utils.ts
/** @since 3.9.0 */
function toArray(value) {
return Array.isArray(value) ? value : [value];
}
async function isDirectory(path) {
try {
return (await promises.lstat(path)).isDirectory();
} catch (err) {
const code = err.code;
if (code === "ENOENT" || code === "ENOTDIR") return false;
throw err;
}
}
function isDirectorySync(path) {
try {
return statSync(path, { throwIfNoEntry: false })?.isDirectory() ?? false;
} catch (err) {
if (err.code === "ENOTDIR") return false;
throw err;
}
}
const LEADING_DOT_RE = /^\.+/g;
/**
* Normalizes a file extension from a string to just the extension part (without the dot).
* In case the string does not contain a dot, it returns the string as is.
*
* @example
* normalizeExtension('.ts') // 'ts'
* normalizeExtension('.d.ts') // 'd.ts'
* normalizeExtension('ts') // 'ts'
* normalizeExtension('d.ts') // 'ts'
*/
function normalizeExtension(input) {
return input.replace(LEADING_DOT_RE, "");
}
function stripExtension(path) {
return path.replace(/\.[^./\\]+$/, "");
}
function isWhitespace(char) {
const c = typeof char === "string" ? char.charCodeAt(0) : char;
return c === 32 || c === 9 || c === 10 || c === 13 || c === 12;
}
const JS_EXT_RE = /^[^?]*\.(?:[jt]sx?|[cm][jt]s)(?:$|\?)/;
const NUXT_LIB_RE = /^[^?]*node_modules\/(?:nuxt|nuxt3|nuxt-nightly|@nuxt)\//;
const STYLE_QUERY_RE$1 = /[?&]type=style/;
const MACRO_QUERY_RE$2 = /[?&]macro(?:=|&|$)/;
const DECLARATION_EXTENSIONS = [
"d.ts",
"d.mts",
"d.cts",
"d.vue.ts",
"d.vue.mts",
"d.vue.cts"
];
const logger = useLogger("nuxt");
function resolveToAlias(path, nuxt = tryUseNuxt()) {
return reverseResolveAlias(path, {
...nuxt?.options.alias || {},
...strippedAtAliases$1
}).pop() || path;
}
const strippedAtAliases$1 = {
"@": "",
"@@": ""
};
//#endregion
//#region src/core/features.ts
var features_exports = /* @__PURE__ */ __exportAll({
ensurePackageInstalled: () => ensurePackageInstalled,
installNuxtModule: () => installNuxtModule
});
const isStackblitz = provider === "stackblitz";
async function promptToInstall(name, installCommand, options) {
for (const parent of options.searchPaths || []) if (await resolvePackageJSON(name, { parent }).catch(() => null)) return true;
configDiagnostics.NUXT_B5011({ name });
if (isCI) return false;
if (options.prompt === true || options.prompt !== false && !isStackblitz) {
if (await logger.prompt(`Do you want to install ${name} package?`, {
type: "confirm",
name: "confirm",
initial: true
}) !== true) return false;
}
logger.info(`Installing ${name}...`);
try {
await installCommand();
logger.success(`Installed ${name}`);
return true;
} catch (err) {
buildDiagnostics.NUXT_B1004({
packages: name,
cause: err
});
return false;
}
}
const installPrompts = /* @__PURE__ */ new Set();
function installNuxtModule(name, options) {
if (installPrompts.has(name)) return;
installPrompts.add(name);
const nuxt = useNuxt();
return promptToInstall(name, async () => {
const { runCommand } = await import("@nuxt/cli");
await runCommand("module", [
"add",
name,
"--cwd",
nuxt.options.rootDir
]);
}, {
rootDir: nuxt.options.rootDir,
searchPaths: nuxt.options.modulesDir,
...options
});
}
function ensurePackageInstalled(name, options) {
return promptToInstall(name, () => addDependency(name, {
cwd: options.rootDir,
dev: true
}), options);
}
//#endregion
//#region src/dirs.ts
let _distDir = dirname(fileURLToPath(import.meta.url));
if (/(?:chunks|shared)$/.test(_distDir)) _distDir = dirname(_distDir);
const distDir = _distDir;
const pkgDir = resolve(distDir, "..");
//#endregion
//#region src/core/utils/names.ts
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));
return kebabCase(resolveComponentNameSegments(fileName.toLowerCase() === "index" ? "" : fileName, prefixParts).filter(Boolean)).replace(QUOTE_RE, "");
}
function hasSuffix(path, suffix) {
return basename(path, extname(path)).endsWith(suffix);
}
function resolveComponentNameSegments(fileName, prefixParts) {
/**
* Array of fileName parts split by case, / or -
* @example third-component -> ['third', 'component']
* @example AwesomeComponent -> ['Awesome', 'Component']
*/
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 + "/") || prefixPart.toLowerCase() === fileNamePartsContent && prefixParts[index + 1] && prefixParts[index] === prefixParts[index + 1]) componentNameParts.length = index;
index--;
}
return [...componentNameParts, ...fileNameParts];
}
//#endregion
//#region src/core/utils/plugins.ts
/**
* Split a bundler module ID into its pathname and search (query) parts.
*
* Module IDs from Vite/webpack are already-normalized filesystem paths
* that may carry query strings (e.g. `?vue&type=style&lang=css`).
*/
function parseModuleId(id) {
const qIndex = id.indexOf("?");
if (qIndex === -1) return {
pathname: id,
search: ""
};
return {
pathname: id.slice(0, qIndex),
search: id.slice(qIndex)
};
}
const NUXT_COMPONENT_RE = /[?&]nuxt_component=/;
const MACRO_RE$1 = /[?&]macro=/;
const VUE_QUERY_RE = /[?&]vue(?:&|$)/;
const SETUP_QUERY_RE = /[?&]setup(?:=|&|$)/;
const TYPE_QUERY_RE = /[?&]type=([^&]*)/;
function isVue(id, opts = {}) {
const { search } = parseModuleId(id);
if (id.endsWith(".vue") && !search) return true;
if (!search) return false;
if (NUXT_COMPONENT_RE.test(search)) return false;
if (MACRO_RE$1.test(search) && (search === "?macro=true" || !opts.type || opts.type.includes("script"))) return true;
if (!VUE_QUERY_RE.test(search)) return false;
if (opts.type) {
const type = SETUP_QUERY_RE.test(search) ? "script" : TYPE_QUERY_RE.exec(search)?.[1];
if (!type || !opts.type.includes(type)) return false;
}
return true;
}
const JS_RE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
/** Matches module IDs for Vue files (ignoring query strings). */
const VUE_ID_RE = /\.vue(?:\?|$)/;
function isJS(id) {
const { pathname } = parseModuleId(id);
return JS_RE.test(pathname);
}
function getLoader(id) {
const { pathname } = parseModuleId(id);
const ext = extname(pathname);
if (ext === ".vue") return "vue";
if (!JS_RE.test(ext)) return null;
return ext.endsWith("x") ? "tsx" : "ts";
}
//#endregion
//#region src/core/utils/index.ts
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$/;
//#endregion
//#region src/pages/utils.ts
function createPagesContext(options = {}) {
const modes = options.shouldUseServerComponents ? ["server", "client"] : ["client"];
const treeOptions = {
roots: options.roots,
modes,
warn: (message) => pageDiagnostics.NUXT_B4011({ message })
};
const emitOptions = {
onDuplicateRouteName: (_name, file, existingFile) => {
pageDiagnostics.NUXT_B4004({
file,
existingFile
});
},
attrs: { mode: modes }
};
const compiledParse = compileParsePath(treeOptions);
let tree = buildTree([], treeOptions);
const trackedFiles = /* @__PURE__ */ new Set();
return {
emit() {
return toVueRouter4(tree, emitOptions);
},
addFile(filePath, priority = 0) {
addFile(tree, {
path: filePath,
priority
}, compiledParse);
trackedFiles.add(filePath);
},
removeFile(filePath) {
const removed = removeFile(tree, filePath);
if (removed) trackedFiles.delete(filePath);
return removed;
},
rebuild(files) {
tree = buildTree(files, treeOptions);
trackedFiles.clear();
for (const f of files) trackedFiles.add(f.path);
},
trackedFiles
};
}
async function resolvePagesRoutes(pattern, nuxt = useNuxt(), ctx, originalPagePaths) {
const pagesDirs = getLayerDirectories(nuxt).map((d) => d.appPages);
const inputFiles = [];
for (let priority = 0; priority < pagesDirs.length; priority++) {
const dir = pagesDirs[priority];
const files = await resolveFiles(dir, pattern);
for (const file of files) inputFiles.push({
path: file,
priority
});
}
let pages;
if (ctx) {
ctx.rebuild(inputFiles);
pages = ctx.emit();
} else {
const oneShot = createPagesContext({
roots: pagesDirs,
shouldUseServerComponents: !!nuxt.options.experimental.componentIslands
});
oneShot.rebuild(inputFiles);
pages = oneShot.emit();
}
return augmentAndResolve(pages, ctx?.trackedFiles ?? new Set(inputFiles.map((f) => f.path)), nuxt, originalPagePaths);
}
async function augmentAndResolve(pages, trackedFiles, nuxt = useNuxt(), originalPagePaths) {
const shouldAugment = nuxt.options.experimental.scanPageMeta || nuxt.options.experimental.typedPages;
if (shouldAugment === false) {
await nuxt.callHook("pages:extend", pages);
return pages;
}
const extraPageMetaExtractionKeys = nuxt.options?.experimental?.extraPageMetaExtractionKeys || [];
const augmentCtx = {
extraExtractionKeys: /* @__PURE__ */ new Set(["middleware", ...extraPageMetaExtractionKeys]),
fullyResolvedPaths: trackedFiles,
originalPagePaths
};
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;
}
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 routeMeta = getRouteMeta(vfs[route.file] ?? fs.readFileSync(ctx.fullyResolvedPaths?.has(route.file) ? route.file : await resolvePath(route.file), "utf-8"), route.file, ctx.extraExtractionKeys);
if (route.meta) routeMeta.meta = defu({}, routeMeta.meta, route.meta);
if (route.rules) routeMeta.rules = defu({}, routeMeta.rules, route.rules);
if (ctx.augmentedPages.has(route.file)) {
delete routeMeta.name;
delete routeMeta.path;
}
if (routeMeta.path !== void 0 && routeMeta.path !== route.path) ctx.originalPagePaths?.set(route, route.path);
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(?=\s|>)(?<attrs>[^>]*)>(?<content>[\s\S]*?)<\/script\s*>/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 && /[tj]sx/.test(match.groups.attrs) ? "tsx" : "ts",
code: match.groups.content.trim()
});
return contents;
}
const PAGE_EXTRACT_RE = new RegExp(`\\b(${["definePageMeta", "defineRouteRules"].join("|")})\\b`, "g");
const defaultExtractionKeys = [
"name",
"path",
"props",
"alias",
"redirect",
"middleware"
];
const DYNAMIC_META_KEY = "__nuxt_dynamic_meta_key";
const STATIC_EXPRESSION_WRAPPERS = /* @__PURE__ */ new Set([
"ParenthesizedExpression",
"TSAsExpression",
"TSNonNullExpression",
"TSSatisfiesExpression",
"TSTypeAssertion"
]);
function unwrapStaticExpression(node) {
let current = node;
while (current && STATIC_EXPRESSION_WRAPPERS.has(current.type)) current = current.expression;
return current;
}
const pageContentsCache = {};
const extractCache = {};
function getRouteMeta(contents, absolutePath, extraExtractionKeys = /* @__PURE__ */ new Set()) {
if (!(absolutePath in pageContentsCache) || pageContentsCache[absolutePath] !== contents) {
pageContentsCache[absolutePath] = contents;
delete extractCache[absolutePath];
}
if (absolutePath in extractCache && extractCache[absolutePath]) return klona(extractCache[absolutePath]);
const loader = getLoader(absolutePath);
const scriptBlocks = !loader ? null : loader === "vue" ? extractScriptContent(contents) : [{
code: contents,
loader
}];
if (!scriptBlocks) {
extractCache[absolutePath] = {};
return {};
}
const extractedData = {};
const extractionKeys = /* @__PURE__ */ new Set([...defaultExtractionKeys, ...extraExtractionKeys]);
for (const script of scriptBlocks) {
const found = {};
for (const macro of script.code.matchAll(PAGE_EXTRACT_RE)) found[macro[1]] = false;
if (Object.keys(found).length === 0) continue;
const dynamicProperties = /* @__PURE__ */ new Set();
parseAndWalk(script.code, absolutePath.replace(/\.\w+$/, "." + script.loader), (node) => {
if (node.type !== "ExpressionStatement" || node.expression.type !== "CallExpression" || node.expression.callee.type !== "Identifier") return;
const fnName = node.expression.callee.name;
if (fnName in found === false || found[fnName] !== false) return;
found[fnName] = true;
const code = script.code;
const pageExtractArgument = unwrapStaticExpression(node.expression.arguments[0]);
if (pageExtractArgument?.type !== "ObjectExpression") {
pageDiagnostics.NUXT_B4005({
fnName,
file: absolutePath,
receivedType: String(pageExtractArgument?.type)
});
return;
}
if (fnName === "defineRouteRules") {
const { value, serializable } = isSerializable(code, pageExtractArgument);
if (!serializable) {
pageDiagnostics.NUXT_B4006({
fnName,
file: absolutePath
});
return;
}
extractedData.rules = value;
return;
}
if (fnName === "definePageMeta") {
for (const key of extractionKeys) {
const property = pageExtractArgument.properties.find((property) => property.type === "Property" && property.key.type === "Identifier" && property.key.name === key);
if (!property) continue;
const { value, serializable } = isSerializable(code, property.value);
if (!serializable) {
logger.debug(`Skipping extraction of \`${key}\` metadata as it is not JSON-serializable (reading \`${absolutePath}\`).`);
dynamicProperties.add(extraExtractionKeys.has(key) ? "meta" : key);
continue;
}
if (extraExtractionKeys.has(key)) {
extractedData.meta ??= {};
extractedData.meta[key] = value;
} else extractedData[key] = value;
}
for (const property of pageExtractArgument.properties) {
if (property.type !== "Property") continue;
if (!(property.key.type === "Literal" || property.key.type === "Identifier")) continue;
const name = property.key.type === "Identifier" ? property.key.name : String(property.value);
if (!extractionKeys.has(name)) {
dynamicProperties.add("meta");
break;
}
}
if (dynamicProperties.size) {
extractedData.meta ??= {};
extractedData.meta[DYNAMIC_META_KEY] = dynamicProperties;
}
}
});
}
extractCache[absolutePath] = extractedData;
return klona(extractedData);
}
function serializeRouteValue(value, skipSerialisation = false) {
if (skipSerialisation || value === void 0) return;
return JSON.stringify(value);
}
function normalizeComponent(page, pageImport, routeName, islandKey) {
if (page.mode === "server") return `() => createIslandPage(${routeName}, import.meta.server ? ${islandKey} : undefined)`;
if (page.mode === "client") return `() => createClientPage(${pageImport})`;
return pageImport;
}
function normalizeComponentWithName(page, isSyncImport, pageImportName, pageImport, routeName, metaRouteName, islandKey) {
if (isSyncImport) return `Object.assign(${pageImportName}, { __name: ${metaRouteName} })`;
if (page.mode === "server") return `() => createIslandPage(${routeName}, import.meta.server ? ${islandKey} : undefined)`;
if (page.mode === "client") return `() => createClientPage(${pageImport}).then((c) => Object.assign(c, { __name: ${metaRouteName} }))`;
return `${pageImport}.then((m) => Object.assign(m.default, { __name: ${metaRouteName} }))`;
}
function normalizeRoutes(routes, metaImports = /* @__PURE__ */ new Set(), options) {
const nuxt = useNuxt();
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] !== void 0) {
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 [...defaultExtractionKeys, "meta"]) if (route[key] === void 0) 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).replace(/-/g, "_"));
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 isSyncImport = page._sync && page.mode !== "client";
const pageImport = isSyncImport ? pageImportName : genDynamicImport(file);
const metaRouteName = `${metaImportName}?.name ?? ${route.name}`;
const islandKey = page.mode === "server" && page.file ? JSON.stringify(hash(relative(nuxt.options.rootDir, page.file))) : void 0;
const component = nuxt.options.experimental.normalizePageNames ? normalizeComponentWithName(page, isSyncImport, pageImportName, pageImport, route.name, metaRouteName, islandKey) : normalizeComponent(page, pageImport, route.name, islandKey);
let componentsObject;
if (page.components) {
const viewEntries = [];
for (const viewName in page.components) {
if (viewName === "default") continue;
const viewFile = normalize(page.components[viewName]);
viewEntries.push(`${JSON.stringify(viewName)}: ${genDynamicImport(viewFile)}`);
}
if (viewEntries.length > 0) componentsObject = `{ default: ${component}, ${viewEntries.join(", ")} }`;
}
const metaRoute = {
name: metaRouteName,
path: `${metaImportName}?.path ?? ${route.path}`,
props: `${metaImportName}?.props ?? ${route.props ?? false}`,
meta: `${metaImportName} || {}`,
alias: `${metaImportName}?.alias || []`,
redirect: `${metaImportName}?.redirect`,
component
};
if (componentsObject) metaRoute.components = componentsObject;
if (page.mode === "server") metaImports.add(`
let _createIslandPage
async function createIslandPage (name, islandKey) {
_createIslandPage ||= await import(${JSON.stringify(options?.serverComponentRuntime)}).then(r => r.createIslandPage)
return _createIslandPage(name, islandKey)
};`);
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;
}))
};
}
function resolveRoutePaths(page, parent = "/") {
return [joinURL(parent, page.path), ...page.children?.flatMap((child) => resolveRoutePaths(child, joinURL(parent, page.path))) || []];
}
const EMPTY_PARAM_REGEXP_RE = /:(\w+)\(\)([+*?]?)/g;
function canonicalizeParams(path) {
return path.replace(EMPTY_PARAM_REGEXP_RE, ":$1$2");
}
/**
* Strip the leading segments an absolute child path shares with its parent's `fullPath`.
* Inserting only the remainder avoids re-declaring the parent's params on the child node.
* The remainder only determines the node's own params, as the absolute child path is
* re-applied as a path override afterwards and becomes the route's `fullPath`. A child
* path that shares nothing with its parent therefore still resolves correctly.
*/
function relativizeToParent(parentFullPath, childPath) {
if (!childPath.startsWith("/")) return childPath;
const parentSegments = canonicalizeParams(parentFullPath).split("/");
const childSegments = childPath.split("/");
let index = 0;
while (index < parentSegments.length && index < childSegments.length && canonicalizeParams(childSegments[index]) === parentSegments[index]) index++;
return index === 0 ? childPath : childSegments.slice(index).join("/");
}
function isSerializable(code, node) {
node = unwrapStaticExpression(node) || node;
if (node.type === "Literal") {
if (typeof node.value === "string" || typeof node.value === "number" || typeof node.value === "boolean" || node.value === null) return {
value: node.value,
serializable: true
};
return { serializable: false };
}
if (node.type === "UnaryExpression" && (node.operator === "-" || node.operator === "+")) {
const arg = node.argument;
if (arg.type === "Literal" && typeof arg.value === "number") return {
value: node.operator === "-" ? -arg.value : arg.value,
serializable: true
};
return { serializable: false };
}
if (node.type === "ArrayExpression") {
const values = [];
for (const element of node.elements) {
if (!element || element.type === "SpreadElement") return { serializable: false };
const { serializable, value } = isSerializable(code, element);
if (!serializable) return { serializable: false };
values.push(value);
}
return {
value: values,
serializable: true
};
}
if (node.type === "ObjectExpression") {
const value = {};
for (const property of node.properties) {
if (property.type !== "Property" || property.computed || property.kind !== "init" || property.method) return { serializable: false };
let key;
if (property.key.type === "Identifier") key = property.key.name;
else if (property.key.type === "Literal" && (typeof property.key.value === "string" || typeof property.key.value === "number")) key = String(property.key.value);
else return { serializable: false };
const { serializable, value: propertyValue } = isSerializable(code, property.value);
if (!serializable) return { serializable: false };
value[key] = propertyValue;
}
return {
value,
serializable: true
};
}
return { serializable: false };
}
function toRou3Patterns(pages, prefix = "/") {
const routes = [];
for (const page of pages) {
const path = page.path.replace(/\([^)]*\)/g, "").replace(/:(\w+)\*.*/g, (_, name) => `**:${name}`).replace(/:([^/*]*)/g, (_, name) => `:${name.replace(/\W/g, (r) => r === "?" ? "" : "_")}`);
routes.push(joinURL(prefix, path));
if (page.children) routes.push(...toRou3Patterns(page.children, joinURL(prefix, path)));
}
return routes;
}
//#endregion
//#region src/pages/route-rules.ts
function globRouteRulesFromPages(pages) {
return collectRouteRulesFromPages(pages, {}, "");
}
function collectRouteRulesFromPages(pages, paths, prefix) {
for (const page of pages) {
if (page.rules) {
if (Object.keys(page.rules).length) {
const path = prefix + page.path;
const { patterns, issues } = vueRouterToRou3(path, { collapse: true });
if (issues.length) for (const issue of issues) pageDiagnostics.NUXT_B4016({
path,
detail: issue.message
});
else for (const pattern of patterns) {
if (pattern in paths && !isEqual(paths[pattern], page.rules)) pageDiagnostics.NUXT_B4017({
path,
pattern
});
paths[pattern] = page.rules;
}
}
delete page.rules;
}
if (page.children?.length) collectRouteRulesFromPages(page.children, paths, prefix + page.path + "/");
}
return paths;
}
function removePagesRules(routes) {
for (const route of routes) {
delete route.rules;
if (route.children?.length) removePagesRules(route.children);
}
}
//#endregion
//#region src/pages/plugins/page-meta.ts
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",
transform: {
filter: {
id: {
include: /[?&]macro=true\b/,
exclude: [/(?:\?|%3F).*type=(?:style|template)/]
},
code: { include: [
HAS_MACRO_RE,
/\bfrom\s+["'][^"'?]*\?[^"']*type=script[^"']*["']/,
/export\s+\{\s*default\s*\}\s+from\s+["'][^"'?]*\?[^"']*type=script[^"']*["']/,
/^(?!.*__nuxt_page_meta)(?!.*export\s+\{\s*default\s*\})(?!.*\bdefinePageMeta\s*\()[\s\S]*$/
] }
},
handler(code, id, transformMeta) {
const query = parseMacroQuery(id);
if (query.type && query.type !== "script") return;
const s = rolldownString(code, id, transformMeta);
function result() {
return generateTransform(s, id);
}
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 } = parseModuleId(id);
pageDiagnostics.NUXT_B4001({ pathname });
} 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 = `${resolveStart(node)}-${resolveEnd(node)}`;
if (addedDeclarations.has(codeSectionKey)) return;
addedDeclarations.add(codeSectionKey);
declarationNodes.push(node);
}
/**
* Adds an import or a declaration to the extracted code.
* @param name The name of the import or declaration to add.
* @param node The node that is currently being processed. (To detect self-references)
*/
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({ preserveExitedScopes: 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") {
const codeSnippet = code.slice(node.start, Math.min(node.end, node.start + 80));
throw pageDiagnostics.NUXT_B4002({
codeSnippet,
offset: node.start
});
}
if (isBindingIdentifier(node, parent) || node.type !== "Identifier") return;
addImportOrDeclaration(node.name, scopeTrackerNode);
} });
}
} else if (scopeTrackerNode?.type === "Function") {
if (scopeTrackerNode.node.type === "ArrowFunctionExpression") return;
if (!scopeTrackerNode.node.id?.name) return;
addDeclaration(scopeTrackerNode);
const undeclaredIdentifiers = getUndeclaredIdentifiersInFunction(scopeTrackerNode.node);
for (const name of undeclaredIdentifiers) addImportOrDeclaration(name);
}
}
const { program: ast } = parseAndWalk(code, id, {
scopeTracker,
parseOptions: { lang: query.lang ?? "ts" }
});
scopeTracker.freeze();
let instances = 0;
walk(ast, {
scopeTracker,
enter: (node) => {
if (node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
if (!("name" in node.callee) || node.callee.name !== "definePageMeta") return;
instances++;
const meta = node.arguments[0];
if (!meta) return;
const metaCode = code.slice(meta.start, meta.end);
const m = new MagicString(metaCode);
if (meta.type === "ObjectExpression") {
const omitProp = (prop, i) => {
const nextProperty = meta.properties[i + 1];
if (nextProperty) m.overwrite(prop.start - meta.start, nextProperty.start - meta.start, "");
else if (code[prop.end] === ",") m.overwrite(prop.start - meta.start, prop.end - meta.start + 1, "");
else m.overwrite(prop.start - meta.start, prop.end - meta.start, "");
};
for (let i = 0; i < meta.properties.length; i++) {
const prop = meta.properties[i];
if (prop.type !== "Property" || prop.key.type !== "Identifier") continue;
if (options.extractedKeys?.includes(prop.key.name)) {
const { serializable } = isSerializable(metaCode, prop.value);
if (serializable) omitProp(prop, i);
} else if (prop.key.name === "layout" && prop.value.type === "ObjectExpression") {
for (const layoutProp of prop.value.properties) {
if (layoutProp.type !== "Property" || layoutProp.key.type !== "Identifier") continue;
if (layoutProp.key.name === "name") m.appendLeft(prop.start - meta.start, `layout: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`);
else if (layoutProp.key.name === "props") m.appendLeft(prop.start - meta.start, `layoutProps: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`);
}
omitProp(prop, i);
}
}
}
const definePageMetaScope = scopeTracker.getCurrentScope();
walk(meta, {
scopeTracker,
enter(node, parent) {
if (isBindingIdentifier(node, parent) || node.type !== "Identifier") return;
const declaration = scopeTracker.getDeclaration(node.name);
if (declaration) {
if (declaration.isUnderScope(definePageMetaScope) && (scopeTracker.isCurrentScopeUnder(declaration.scope) || resolveStart(declaration) < node.start)) return;
}
if (isStaticIdentifier(node.name)) addImport(node.name);
else if (declaration) processDeclaration(declaration);
}
});
const extracted = [
Array.from(addedImports).join("\n"),
declarationNodes.sort((a, b) => resolveStart(a) - resolveStart(b)).map((node) => code.slice(resolveStart(node), resolveEnd(node))).join("\n"),
`const __nuxt_page_meta = ${m.toString() || "null"}\nexport default __nuxt_page_meta` + (options.dev ? CODE_HMR : "")
].join("\n");
s.overwrite(0, code.length, extracted.trim());
}
});
if (instances > 1) throw pageDiagnostics.NUXT_B4003({
callCount: instances,
file: id
});
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.routesId && options.isPage?.(file)) {
const macroModule = server.moduleGraph.getModuleById(file + "?macro=true");
const routesModule = server.moduleGraph.getModuleById(options.routesId);
const realModules = [];
for (const mod of modules) if (mod.id && MACRO_STRIP_RE.test(mod.id)) {
const realModule = server.moduleGraph.getModuleById(mod.id.replace(MACRO_STRIP_RE, (r) => r.endsWith("&") ? "?" : ""));
if (realModule) realModules.push(realModule);
}
return [
...modules,
...realModules,
...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, ""));
}
const MACRO_QUERY_RE$1 = /[?&]macro=true(?:&|$)/;
const MACRO_STRIP_RE = /\?macro=true&?/;
const TYPE_PARAM_RE = /[?&]type=([^?&]+)/;
const LANG_PARAM_RE = /[?&]lang=([^?&]+)/;
function parseMacroQuery(id) {
const { search } = parseModuleId(id);
const query = {
type: TYPE_PARAM_RE.exec(search)?.[1],
lang: LANG_PARAM_RE.exec(search)?.[1] ?? void 0
};
if (MACRO_QUERY_RE$1.test(search)) query.macro = "true";
return query;
}
const QUOTED_SPECIFIER_RE = /(["']).*\1/;
function getQuotedSpecifier(id) {
return id.match(QUOTED_SPECIFIER_RE)?.[0];
}
function resolveStart(node) {
return "fnNode" in node ? node.fnNode.start : node.start;
}
function resolveEnd(node) {
return "fnNode" in node ? node.fnNode.end : node.end;
}
//#endregion
//#region src/core/plugins/virtual.ts
const PREFIX = "virtual:nuxt:";
const PREFIX_RE = /^\/?virtual:nuxt:/;
function toVirtualId(absolutePath, nuxt) {
return PREFIX + encodeURIComponent(relative(nuxt.options.rootDir, absolutePath));
}
function fromVirtualId(id, nuxt) {
const search = id.match(QUERY_RE)?.[0] || "";
const relativePart = withoutQuery(decodeURIComponent(withoutPrefix(id)));
return resolve(nuxt.options.rootDir, relativePart) + search;
}
const RELATIVE_ID_RE = /^\.{1,2}[\\/]/;
const VirtualFSPlugin = (nuxt, options) => createUnplugin((_, meta) => {
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;
}
};
function resolveId(id, importer) {
id = resolveAlias(id, alias);
if (PREFIX_RE.test(id)) id = fromVirtualId(id, nuxt);
const search = id.match(QUERY_RE)?.[0] || "";
id = withoutQuery(id);
if (process.platform === "win32" && isAbsolute(id)) id = resolve(id);
const resolvedId = resolveWithExt(id);
if (resolvedId) return toVirtualId(resolvedId, nuxt) + search;
if (importer && RELATIVE_ID_RE.test(id)) {
const path = resolve(dirname(withoutQuery(fromVirtualId(importer, nuxt))), id);
const resolved = resolveWithExt(path);
if (resolved) return toVirtualId(resolved, nuxt) + search;
}
}
const relevantAliases = /* @__PURE__ */ new Set();
for (const key in alias) {
const value = alias[key];
if (value && Object.keys(nuxt.vfs).some((vfsPath) => vfsPath.startsWith(value))) relevantAliases.add(escapeDirectory(key));
}
const vfsEntries = /* @__PURE__ */ new Set();
for (const key in nuxt.vfs) if (!key.startsWith("#build/") && !key.startsWith(nuxt.options.buildDir)) vfsEntries.add(escapeDirectory(dirname(key)));
const filter = { id: [
PREFIX_RE,
RELATIVE_ID_RE,
/^#build\//,
new RegExp("^(\\w:)?" + escapeDirectory(nuxt.options.buildDir)),
...Array.from(vfsEntries).map((id) => new RegExp("^" + id)),
...relevantAliases.size ? [new RegExp("^" + Array.from(relevantAliases).join("|") + "([\\\\/]|$)")] : []
] };
return {
name: "nuxt:virtual",
resolveId: meta.framework === "vite" ? void 0 : {
order: "pre",
filter,
handler: resolveId
},
vite: { resolveId: {
order: "pre",
filter,
handler(id, importer) {
const res = resolveId(id, importer);
if (res) return res;
if (importer && PREFIX_RE.test(importer) && RELATIVE_ID_RE.test(id)) return this.resolve?.(id, withoutQuery(fromVirtualId(importer, nuxt)), { skipSelf: true });
}
} },
load: {
filter: { id: PREFIX_RE },
handler(id) {
const key = withoutQuery(fromVirtualId(id, nuxt));
return {
code: nuxt.vfs[key] || "",
map: null
};
}
}
};
});
function withoutPrefix(id) {
return id.replace(PREFIX_RE, "");
}
const QUERY_RE = /\?.*$/;
function withoutQuery(id) {
return id.replace(QUERY_RE, "");
}
function escapeDirectory(path) {
return escapeStringRegexp(path).replace(/\//g, "[\\\\/]");
}
//#endregion
//#region src/pages/plugins/route-injection.ts
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: {
filter: { code: {
include: INJECTION_SINGLE_RE,
exclude: [`_ctx._.provides[__nuxt_route_symbol`, "this._.provides[__nuxt_route_symbol"]
} },
handler(code, id, meta) {
const s = rolldownString(code, id, meta);
parseAndWalk(code, id, (node) => {
if (node.type !== "MemberExpression") return;
if (node.object.type === "ThisExpression" && node.property.type === "Identifier" && node.property.name === "$route") {
s.overwrite(node.start, node.end, "(this._.provides[__nuxt_route_symbol] || this.$route)");
return;
}
if (node.object.type === "Identifier" && node.object.name === "_ctx" && node.property.type === "Identifier" && node.property.name === "$route") s.overwrite(node.start, node.end, "(_ctx._.provides[__nuxt_route_symbol] || _ctx.$route)");
});
if (s.hasChanged()) s.prepend("import { PageRouteSymbol as __nuxt_route_symbol } from '#app/components/injections';\n");
return generateTransform(s, id);
}
}
};
});
//#endregion
//#region src/pages/module.ts
const OPTIONAL_PARAM_RE = /^\/?:.*(?:\?|\(\.\*\)\*)$/;
const pagesImportPresets = [
{
imports: ["definePageMeta"],
from: "#app/composables/pages"
},
{
imports: ["PageMeta"],
from: "#app/composables/pages",
type: true
},
{
imports: ["useLink"],
from: "vue-router"
}
];
const routeRulesPresets = [{
imports: ["defineRouteRules"],
from: "#app/composables/pages"
}];
async function resolveRouterOptions(nuxt, builtInRouterOptions) {
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;
}
var module_default$4 = defineNuxtModule({
meta: {
name: "nuxt:pages",
configKey: "pages"
},
defaults: (nuxt) => ({
enabled: typeof nuxt.options.pages === "boolean" ? nuxt.options.pages : void 0,
pattern: `**/*{${nuxt.options.extensions.join(",")}}`
}),
async setup(_options, nuxt) {
const runtimeDir = resolve(distDir, "pages/runtime");
const options = typeof _options === "boolean" ? {
enabled: _options ?? nuxt.options.pages,
pattern: `**/*{${nuxt.options.extensions.join(",")}}`
} : { ..._options };
options.pattern = Array.isArray(options.pattern) ? [...new Set(options.pattern)] : options.pattern;
let inlineRulesCache = {};
let updateRouteConfig;
if (nuxt.options.experimental.inlineRouteRules) nuxt.hook("nitro:init", (nitro) => {
updateRouteConfig = async (inlineRules) => {
if (!isEqual(inlineRulesCache, inlineRules)) {
await nitro.updateConfig({ routeRules: defu(inlineRules, nitro.options._config.routeRules) });
inlineRulesCache = inlineRules;
}
};
});
const useExperimentalTypedPages = nuxt.options.experimental.typedPages;
const builtInRouterOptions = await findPath(resolve(runtimeDir, "router.options")) || resolve(runtimeDir, "router.options");
const pagesDirs = getLayerDirectories(nuxt).map((dirs) => dirs.appPages);
const pagesCtx = nuxt.options.dev ? createPagesContext({
roots: pagesDirs,
shouldUseServerComponents: !!nuxt.options.experimental.componentIslands
}) : void 0;
const isPagePattern = picomatch(Array.isArray(options.pattern) ? options.pattern : [options.pattern]);
const originalPagePaths = /* @__PURE__ */ new WeakMap();
const handleRouteRules = async (pages) => {
if (nuxt.options.experimental.inlineRouteRules) {
const routeRules = globRouteRulesFromPages(pages);
await updateRouteConfig?.(routeRules);
} else removePagesRules(pages);
};
const resolvePagesRoutes$1 = async (pattern, nuxt) => {
const pages = await resolvePagesRoutes(pattern, nuxt, pagesCtx, originalPagePaths);
await handleRouteRules(pages);
return pages;
};
/** Emit from existing tree + augment + hooks + route rules (used for incremental updates). */
const augmentAndResolvePages = async (pages, trackedFiles, nuxt) => {
const resolved = await augmentAndResolve(pages, trackedFiles, nuxt, originalPagePaths);
await handleRouteRules(resolved);
return resolved;
};
nuxt.options.alias["#vue-router"] = "vue-router";
const routerPath = (await resolveTypePaths(["vue-router"], nuxt.options.modulesDir))[0]?.[1] || "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 isNonEmptyDir = (dir) => existsSync(dir) && readdirSync(dir).length;
const userPreference = options.enabled;
const isPagesEnabled = async () => {
if (typeof userPreference === "boolean") return userPreference;
if ((await resolveRouterOptions(nuxt, builtInRouterOptions)).filter((p) => !p.optional).length > 0) return true;
if (pagesDirs.some((dir) => isNonEmptyDir(dir))) return true;
const pages = await resolvePagesRoutes$1(options.pattern, nuxt);
if (pages.length) {
if (nuxt.apps.default) nuxt.apps.default.pages = pages;
return true;
}
return false;
};
options.enabled = await isPagesEnabled();
nuxt.options.pages = options;
Object.defineProperty(nuxt.options.pages, "toString", {
enumerable: false,
get: () => () => options.enabled
});
if (nuxt.options.dev && options.enabled) addPlugin(resolve(runtimeDir, "plugins/check-if-page-unused"));
nuxt.hook("app:templates", (app) => {
if (!nuxt.options.ssr && app.pages?.some((p) => p.mode === "server")) pageDiagnostics.NUXT_B4008();
});
const restartPaths = nuxt.options._layers.flatMap((layer) => {
const pagesDir = (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options.dir : layer.config.dir)?.pages || "pages";
return [resolve(layer.config.srcDir || layer.cwd, layer.config.dir?.app || "app", "router.options.ts"), resolve(layer.config.srcDir |