3117 lines
116 KiB
JavaScript
Raw Normal View History

2025-09-05 14:59:21 +08:00
import 'scule';
import defu$1, { defu } from 'defu';
import { resolve, join, relative, basename } from 'pathe';
import { isTest, isDevelopment, isDebug } from 'std-env';
import { consola } from 'consola';
import { existsSync } from 'node:fs';
import { readdir } from 'node:fs/promises';
import { randomUUID } from 'node:crypto';
import { findWorkspaceDir } from 'pkg-types';
import { withTrailingSlash } from 'ufo';
import { escapeHtml } from '@vue/shared';
function defineUntypedSchema(options) {
return options;
}
function defineResolvers(config) {
return defineUntypedSchema(config);
}
const adhoc = defineResolvers({
/**
* Configure Nuxt component auto-registration.
*
* Any components in the directories configured here can be used throughout your
* pages, layouts (and other components) without needing to explicitly import them.
* @see [`components/` directory documentation](https://nuxt.com/docs/guide/directory-structure/components)
* @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']}
*/
components: {
$resolve: (val) => {
if (Array.isArray(val)) {
return { dirs: val };
}
if (val === false) {
return { dirs: [] };
}
return {
dirs: [{ path: "~/components/global", global: true }, "~/components"],
...typeof val === "object" ? val : {}
};
}
},
/**
* Configure how Nuxt auto-imports composables into your application.
* @see [Nuxt documentation](https://nuxt.com/docs/guide/directory-structure/composables)
* @type {typeof import('../src/types/imports').ImportsOptions}
*/
imports: {
global: false,
/**
* Whether to scan your `composables/` and `utils/` directories for composables to auto-import.
* Auto-imports registered by Nuxt or other modules, such as imports from `vue` or `nuxt`, will still be enabled.
*/
scan: true,
/**
* An array of custom directories that will be auto-imported.
* Note that this option will not override the default directories (~/composables, ~/utils).
* @example
* ```js
* imports: {
* // Auto-import pinia stores defined in `~/stores`
* dirs: ['stores']
* }
* ```
*/
dirs: []
},
/**
* Whether to use the vue-router integration in Nuxt 3. If you do not provide a value it will be
* enabled if you have a `pages/` directory in your source folder.
*
* Additionally, you can provide a glob pattern or an array of patterns
* to scan only certain files for pages.
* @example
* ```js
* pages: {
* pattern: ['**\/*\/*.vue', '!**\/*.spec.*'],
* }
* ```
* @type {boolean | { enabled?: boolean, pattern?: string | string[] }}
*/
pages: void 0,
/**
* Manually disable nuxt telemetry.
* @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information.
* @type {boolean | Record<string, any>}
*/
telemetry: void 0,
/**
* Enable Nuxt DevTools for development.
*
* Breaking changes for devtools might not reflect on the version of Nuxt.
* @see [Nuxt DevTools](https://devtools.nuxt.com/) for more information.
* @type { { enabled: boolean, [key: string]: any } }
*/
devtools: {}
});
const app = defineResolvers({
/**
* Vue.js config
*/
vue: {
/** @type {typeof import('@vue/compiler-sfc').AssetURLTagConfig} */
transformAssetUrls: {
video: ["src", "poster"],
source: ["src"],
img: ["src"],
image: ["xlink:href", "href"],
use: ["xlink:href", "href"]
},
/**
* Options for the Vue compiler that will be passed at build time.
* @see [Vue documentation](https://vuejs.org/api/application.html#app-config-compileroptions)
* @type {typeof import('@vue/compiler-core').CompilerOptions}
*/
compilerOptions: {},
/**
* Include Vue compiler in runtime bundle.
*/
runtimeCompiler: {
$resolve: async (val, get) => {
if (typeof val === "boolean") {
return val;
}
const legacyProperty = await get("experimental.runtimeVueCompiler");
if (typeof legacyProperty === "boolean") {
return legacyProperty;
}
return false;
}
},
/**
* Enable reactive destructure for `defineProps`
* @type {boolean}
*/
propsDestructure: true,
/**
* It is possible to pass configure the Vue app globally. Only serializable options
* may be set in your `nuxt.config`. All other options should be set at runtime in a Nuxt plugin..
* @see [Vue app config documentation](https://vuejs.org/api/application.html#app-config)
*/
config: {}
},
/**
* Nuxt App configuration.
*/
app: {
/**
* The base path of your Nuxt application.
*
* For example:
* @example
* ```ts
* export default defineNuxtConfig({
* app: {
* baseURL: '/prefix/'
* }
* })
* ```
*
* This can also be set at runtime by setting the NUXT_APP_BASE_URL environment variable.
* @example
* ```bash
* NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs
* ```
*/
baseURL: {
$resolve: (val) => {
if (typeof val === "string") {
return val;
}
return process.env.NUXT_APP_BASE_URL || "/";
}
},
/** The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. */
buildAssetsDir: {
$resolve: (val) => {
if (typeof val === "string") {
return val;
}
return process.env.NUXT_APP_BUILD_ASSETS_DIR || "/_nuxt/";
}
},
/**
* An absolute URL to serve the public folder from (production-only).
*
* For example:
* @example
* ```ts
* export default defineNuxtConfig({
* app: {
* cdnURL: 'https://mycdn.org/'
* }
* })
* ```
*
* This can be set to a different value at runtime by setting the `NUXT_APP_CDN_URL` environment variable.
* @example
* ```bash
* NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs
* ```
*/
cdnURL: {
$resolve: async (val, get) => {
if (await get("dev")) {
return "";
}
return process.env.NUXT_APP_CDN_URL || (typeof val === "string" ? val : "");
}
},
/**
* Set default configuration for `<head>` on every page.
* @example
* ```js
* app: {
* head: {
* meta: [
* // <meta name="viewport" content="width=device-width, initial-scale=1">
* { name: 'viewport', content: 'width=device-width, initial-scale=1' }
* ],
* script: [
* // <script src="https://myawesome-lib.js"><\/script>
* { src: 'https://awesome-lib.js' }
* ],
* link: [
* // <link rel="stylesheet" href="https://myawesome-lib.css">
* { rel: 'stylesheet', href: 'https://awesome-lib.css' }
* ],
* // please note that this is an area that is likely to change
* style: [
* // <style>:root { color: red }</style>
* { textContent: ':root { color: red }' }
* ],
* noscript: [
* // <noscript>JavaScript is required</noscript>
* { textContent: 'JavaScript is required' }
* ]
* }
* }
* ```
* @type {typeof import('../src/types/config').NuxtAppConfig['head']}
*/
head: {
$resolve: async (_val, get) => {
const legacyMetaValues = await get("meta");
const val = _val && typeof _val === "object" ? _val : {};
const resolved = defu(val, legacyMetaValues, {
meta: [],
link: [],
style: [],
script: [],
noscript: []
});
if (!resolved.meta.find((m) => m?.charset)?.charset) {
resolved.meta.unshift({ charset: resolved.charset || "utf-8" });
}
if (!resolved.meta.find((m) => m?.name === "viewport")?.content) {
resolved.meta.unshift({ name: "viewport", content: resolved.viewport || "width=device-width, initial-scale=1" });
}
resolved.meta = resolved.meta.filter(Boolean);
resolved.link = resolved.link.filter(Boolean);
resolved.style = resolved.style.filter(Boolean);
resolved.script = resolved.script.filter(Boolean);
resolved.noscript = resolved.noscript.filter(Boolean);
return resolved;
}
},
/**
* Default values for layout transitions.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
* @see [Vue Transition docs](https://vuejs.org/api/built-in-components.html#transition)
* @type {typeof import('../src/types/config').NuxtAppConfig['layoutTransition']}
*/
layoutTransition: false,
/**
* Default values for page transitions.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
* @see [Vue Transition docs](https://vuejs.org/api/built-in-components.html#transition)
* @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']}
*/
pageTransition: false,
/**
* Default values for view transitions.
*
* This only has an effect when **experimental** support for View Transitions is
* [enabled in your nuxt.config file](/docs/getting-started/transitions#view-transitions-api-experimental).
*
* This can be overridden with `definePageMeta` on an individual page.
* @see [Nuxt View Transition API docs](https://nuxt.com/docs/getting-started/transitions#view-transitions-api-experimental)
* @type {typeof import('../src/types/config').NuxtAppConfig['viewTransition']}
*/
viewTransition: {
$resolve: async (val, get) => {
if (val === "always" || typeof val === "boolean") {
return val;
}
return await get("experimental").then((e) => e.viewTransition) ?? false;
}
},
/**
* Default values for KeepAlive configuration between pages.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
* @see [Vue KeepAlive](https://vuejs.org/api/built-in-components.html#keepalive)
* @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']}
*/
keepalive: false,
/**
* Customize Nuxt root element id.
* @type {string | false}
* @deprecated Prefer `rootAttrs.id` instead
*/
rootId: {
$resolve: (val) => val === false ? false : val && typeof val === "string" ? val : "__nuxt"
},
/**
* Customize Nuxt root element tag.
*/
rootTag: {
$resolve: (val) => val && typeof val === "string" ? val : "div"
},
/**
* Customize Nuxt root element id.
* @type {typeof import('../src/types/head').SerializableHtmlAttributes}
*/
rootAttrs: {
$resolve: async (val, get) => {
const rootId = await get("app.rootId");
return {
id: rootId === false ? void 0 : rootId || "__nuxt",
...typeof val === "object" ? val : {}
};
}
},
/**
* Customize Nuxt Teleport element tag.
*/
teleportTag: {
$resolve: (val) => val && typeof val === "string" ? val : "div"
},
/**
* Customize Nuxt Teleport element id.
* @type {string | false}
* @deprecated Prefer `teleportAttrs.id` instead
*/
teleportId: {
$resolve: (val) => val === false ? false : val && typeof val === "string" ? val : "teleports"
},
/**
* Customize Nuxt Teleport element attributes.
* @type {typeof import('../src/types/head').SerializableHtmlAttributes}
*/
teleportAttrs: {
$resolve: async (val, get) => {
const teleportId = await get("app.teleportId");
return {
id: teleportId === false ? void 0 : teleportId || "teleports",
...typeof val === "object" ? val : {}
};
}
},
/**
* Customize Nuxt SpaLoader element tag.
*/
spaLoaderTag: {
$resolve: (val) => val && typeof val === "string" ? val : "div"
},
/**
* Customize Nuxt Nuxt SpaLoader element attributes.
* @type {typeof import('../src/types/head').SerializableHtmlAttributes}
*/
spaLoaderAttrs: {
id: "__nuxt-loader"
}
},
/**
* Boolean or a path to an HTML file with the contents of which will be inserted into any HTML page
* rendered with `ssr: false`.
*
* - If it is unset, it will use `~/app/spa-loading-template.html` file in one of your layers, if it exists.
* - If it is false, no SPA loading indicator will be loaded.
* - If true, Nuxt will look for `~/app/spa-loading-template.html` file in one of your layers, or a
* default Nuxt image will be used.
*
* Some good sources for spinners are [SpinKit](https://github.com/tobiasahlin/SpinKit) or [SVG Spinners](https://icones.js.org/collection/svg-spinners).
* @example ~/app/spa-loading-template.html
* ```html
* <!-- https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md -->
* <div class="loader"></div>
* <style>
* .loader {
* display: block;
* position: fixed;
* z-index: 1031;
* top: 50%;
* left: 50%;
* transform: translate(-50%, -50%);
* width: 18px;
* height: 18px;
* box-sizing: border-box;
* border: solid 2px transparent;
* border-top-color: #000;
* border-left-color: #000;
* border-bottom-color: #efefef;
* border-right-color: #efefef;
* border-radius: 50%;
* -webkit-animation: loader 400ms linear infinite;
* animation: loader 400ms linear infinite;
* }
*
* @-webkit-keyframes loader {
* 0% {
* -webkit-transform: translate(-50%, -50%) rotate(0deg);
* }
* 100% {
* -webkit-transform: translate(-50%, -50%) rotate(360deg);
* }
* }
* @keyframes loader {
* 0% {
* transform: translate(-50%, -50%) rotate(0deg);
* }
* 100% {
* transform: translate(-50%, -50%) rotate(360deg);
* }
* }
* </style>
* ```
* @type {string | boolean | undefined | null}
*/
spaLoadingTemplate: {
$resolve: async (val, get) => {
if (typeof val === "string") {
return resolve(await get("srcDir"), val);
}
if (typeof val === "boolean") {
return val;
}
return null;
}
},
/**
* An array of nuxt app plugins.
*
* Each plugin can be a string (which can be an absolute or relative path to a file).
* If it ends with `.client` or `.server` then it will be automatically loaded only
* in the appropriate context.
*
* It can also be an object with `src` and `mode` keys.
* @note Plugins are also auto-registered from the `~/plugins` directory
* and these plugins do not need to be listed in `nuxt.config` unless you
* need to customize their order. All plugins are deduplicated by their src path.
* @see [`plugins/` directory documentation](https://nuxt.com/docs/guide/directory-structure/plugins)
* @example
* ```js
* plugins: [
* '~/plugins/foo.client.js', // only in client side
* '~/plugins/bar.server.js', // only in server side
* '~/plugins/baz.js', // both client & server
* { src: '~/plugins/both-sides.js' },
* { src: '~/plugins/client-only.js', mode: 'client' }, // only on client side
* { src: '~/plugins/server-only.js', mode: 'server' } // only on server side
* ]
* ```
* @type {(typeof import('../src/types/nuxt').NuxtPlugin | string)[]}
*/
plugins: [],
/**
* You can define the CSS files/modules/libraries you want to set globally
* (included in every page).
*
* Nuxt will automatically guess the file type by its extension and use the
* appropriate pre-processor. You will still need to install the required
* loader if you need to use them.
* @example
* ```js
* css: [
* // Load a Node.js module directly (here it's a Sass file).
* 'bulma',
* // CSS file in the project
* '~/assets/css/main.css',
* // SCSS file in the project
* '~/assets/css/main.scss'
* ]
* ```
* @type {string[]}
*/
css: {
$resolve: (val) => {
if (!Array.isArray(val)) {
return [];
}
const css = [];
for (const item of val) {
if (typeof item === "string") {
css.push(item);
} else if (item && "src" in item) {
css.push(item.src);
}
}
return css;
}
},
/**
* An object that allows us to configure the `unhead` nuxt module.
*/
unhead: {
/***
* Enable the legacy compatibility mode for `unhead` module. This applies the following changes:
* - Disables Capo.js sorting
* - Adds the `DeprecationsPlugin`: supports `hid`, `vmid`, `children`, `body`
* - Adds the `PromisesPlugin`: supports promises as input
*
* @see [`unhead` migration documentation](https://unhead.unjs.io/docs/typescript/head/guides/get-started/migration)
*
* @example
* ```ts
* export default defineNuxtConfig({
* unhead: {
* legacy: true
* })
* ```
* @type {boolean}
*/
legacy: false,
/**
* An object that will be passed to `renderSSRHead` to customize the output.
*
* @example
* ```ts
* export default defineNuxtConfig({
* unhead: {
* renderSSRHeadOptions: {
* omitLineBreaks: true
* }
* })
* ```
* @type {typeof import('@unhead/vue/types').RenderSSRHeadOptions}
*/
renderSSRHeadOptions: {
$resolve: async (val, get) => {
const isV4 = (await get("future")).compatibilityVersion === 4;
return {
...typeof val === "object" ? val : {},
omitLineBreaks: isV4
};
}
}
}
});
const build = defineResolvers({
/**
* The builder to use for bundling the Vue part of your application.
* @type {'vite' | 'webpack' | 'rspack' | { bundle: (nuxt: typeof import('../src/types/nuxt').Nuxt) => Promise<void> }}
*/
builder: {
$resolve: async (val, get) => {
if (val && typeof val === "object" && "bundle" in val) {
return val;
}
const map = {
rspack: "@nuxt/rspack-builder",
vite: "@nuxt/vite-builder",
webpack: "@nuxt/webpack-builder"
};
if (typeof val === "string" && val in map) {
return map[val];
}
if (await get("vite") === false) {
return map.webpack;
}
return map.vite;
}
},
/**
* Configures whether and how sourcemaps are generated for server and/or client bundles.
*
* If set to a single boolean, that value applies to both server and client.
* Additionally, the `'hidden'` option is also available for both server and client.
*
* Available options for both client and server:
* - `true`: Generates sourcemaps and includes source references in the final bundle.
* - `false`: Does not generate any sourcemaps.
* - `'hidden'`: Generates sourcemaps but does not include references in the final bundle.
*
* @type {boolean | { server?: boolean | 'hidden', client?: boolean | 'hidden' }}
*/
sourcemap: {
$resolve: async (val, get) => {
if (typeof val === "boolean") {
return { server: val, client: val };
}
return {
server: true,
client: await get("dev"),
...typeof val === "object" ? val : {}
};
}
},
/**
* Log level when building logs.
*
* Defaults to 'silent' when running in CI or when a TTY is not available.
* This option is then used as 'silent' in Vite and 'none' in Webpack
* @type {'silent' | 'info' | 'verbose'}
*/
logLevel: {
$resolve: (val) => {
if (val && typeof val === "string" && !["silent", "info", "verbose"].includes(val)) {
consola.warn(`Invalid \`logLevel\` option: \`${val}\`. Must be one of: \`silent\`, \`info\`, \`verbose\`.`);
}
return val && typeof val === "string" ? val : isTest ? "silent" : "info";
}
},
/**
* Shared build configuration.
*/
build: {
/**
* If you want to transpile specific dependencies with Babel, you can add them here.
* Each item in transpile can be a package name, a function, a string or regex object matching the
* dependency's file name.
*
* You can also use a function to conditionally transpile. The function will receive an object ({ isDev, isServer, isClient, isModern, isLegacy }).
* @example
* ```js
* transpile: [({ isLegacy }) => isLegacy && 'ky']
* ```
* @type {Array<string | RegExp | ((ctx: { isClient?: boolean; isServer?: boolean; isDev: boolean }) => string | RegExp | false)>}
*/
transpile: {
$resolve: (val) => {
const transpile = [];
if (Array.isArray(val)) {
for (const pattern of val) {
if (!pattern) {
continue;
}
if (typeof pattern === "string" || typeof pattern === "function" || pattern instanceof RegExp) {
transpile.push(pattern);
}
}
}
return transpile;
}
},
/**
* It is recommended to use `addTemplate` from `@nuxt/kit` instead of this option.
*
* @example
* ```js
* templates: [
* {
* src: '~/modules/support/plugin.js', // `src` can be absolute or relative
* dst: 'support.js', // `dst` is relative to project `.nuxt` dir
* }
* ]
* ```
* @type {typeof import('../src/types/nuxt').NuxtTemplate<any>[]}
*/
templates: [],
/**
* Nuxt allows visualizing your bundles and how to optimize them.
*
* Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options).
* @example
* ```js
* analyze: {
* analyzerMode: 'static'
* }
* ```
* @type {boolean | { enabled?: boolean } & ((0 extends 1 & typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options ? Record<string, unknown> : typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options) | typeof import('rollup-plugin-visualizer').PluginVisualizerOptions)}
*/
analyze: {
$resolve: async (val, get) => {
const [rootDir, analyzeDir] = await Promise.all([get("rootDir"), get("analyzeDir")]);
return {
template: "treemap",
projectRoot: rootDir,
filename: join(analyzeDir, "{name}.html"),
...typeof val === "boolean" ? { enabled: val } : typeof val === "object" ? val : {}
};
}
}
},
/**
* Build time optimization configuration.
*/
optimization: {
/**
* Functions to inject a key for.
*
* As long as the number of arguments passed to the function is less than `argumentLength`, an
* additional magic string will be injected that can be used to deduplicate requests between server
* and client. You will need to take steps to handle this additional key.
*
* The key will be unique based on the location of the function being invoked within the file.
* @type {Array<{ name: string, source?: string | RegExp, argumentLength: number }>}
*/
keyedComposables: {
$resolve: (val) => [
{ name: "callOnce", argumentLength: 3 },
{ name: "defineNuxtComponent", argumentLength: 2 },
{ name: "useState", argumentLength: 2 },
{ name: "useFetch", argumentLength: 3 },
{ name: "useAsyncData", argumentLength: 3 },
{ name: "useLazyAsyncData", argumentLength: 3 },
{ name: "useLazyFetch", argumentLength: 3 },
...Array.isArray(val) ? val : []
].filter(Boolean)
},
/**
* Tree shake code from specific builds.
*/
treeShake: {
/**
* Tree shake composables from the server or client builds.
* @example
* ```js
* treeShake: { client: { myPackage: ['useServerOnlyComposable'] } }
* ```
*/
composables: {
server: {
$resolve: async (val, get) => defu(
typeof val === "object" ? val || {} : {},
await get("dev") ? {} : {
"vue": ["onMounted", "onUpdated", "onUnmounted", "onBeforeMount", "onBeforeUpdate", "onBeforeUnmount", "onRenderTracked", "onRenderTriggered", "onActivated", "onDeactivated"],
"#app": ["definePayloadReviver", "definePageMeta"]
}
)
},
client: {
$resolve: async (val, get) => defu(
typeof val === "object" ? val || {} : {},
await get("dev") ? {} : {
"vue": ["onRenderTracked", "onRenderTriggered", "onServerPrefetch"],
"#app": ["definePayloadReducer", "definePageMeta", "onPrehydrate"]
}
)
}
}
},
/**
* Options passed directly to the transformer from `unctx` that preserves async context
* after `await`.
* @type {typeof import('unctx/transform').TransformerOptions}
*/
asyncTransforms: {
asyncFunctions: ["defineNuxtPlugin", "defineNuxtRouteMiddleware"],
objectDefinitions: {
defineNuxtComponent: ["asyncData", "setup"],
defineNuxtPlugin: ["setup"],
definePageMeta: ["middleware", "validate"]
}
}
}
});
const common = defineResolvers({
/**
* Extend project from multiple local or remote sources.
*
* Value should be either a string or array of strings pointing to source directories or config path relative to current config.
*
* You can use `github:`, `gh:` `gitlab:` or `bitbucket:`
* @see [`c12` docs on extending config layers](https://github.com/unjs/c12#extending-config-layer-from-remote-sources)
* @see [`giget` documentation](https://github.com/unjs/giget)
* @type {string | [string, typeof import('c12').SourceOptions?] | (string | [string, typeof import('c12').SourceOptions?])[]}
*/
extends: void 0,
/**
* Specify a compatibility date for your app.
*
* This is used to control the behavior of presets in Nitro, Nuxt Image
* and other modules that may change behavior without a major version bump.
*
* We plan to improve the tooling around this feature in the future.
*
* @type {typeof import('compatx').CompatibilityDateSpec}
*/
compatibilityDate: void 0,
/**
* Extend project from a local or remote source.
*
* Value should be a string pointing to source directory or config path relative to current config.
*
* You can use `github:`, `gitlab:`, `bitbucket:` or `https://` to extend from a remote git repository.
* @type {string}
*/
theme: void 0,
/**
* Define the root directory of your application.
*
* This property can be overwritten (for example, running `nuxt ./my-app/`
* will set the `rootDir` to the absolute path of `./my-app/` from the
* current/working directory.
*
* It is normally not needed to configure this option.
*/
rootDir: {
$resolve: (val) => typeof val === "string" ? resolve(val) : process.cwd()
},
/**
* Define the workspace directory of your application.
*
* Often this is used when in a monorepo setup. Nuxt will attempt to detect
* your workspace directory automatically, but you can override it here.
*
* It is normally not needed to configure this option.
*/
workspaceDir: {
$resolve: async (val, get) => {
const rootDir = await get("rootDir");
return val && typeof val === "string" ? resolve(rootDir, val) : await findWorkspaceDir(rootDir, {
gitConfig: "closest",
try: true
}).catch(() => rootDir);
}
},
/**
* Define the source directory of your Nuxt application.
*
* If a relative path is specified, it will be relative to the `rootDir`.
* @example
* ```js
* export default {
* srcDir: 'src/'
* }
* ```
* This would work with the following folder structure:
* ```bash
* -| app/
* ---| node_modules/
* ---| nuxt.config.js
* ---| package.json
* ---| src/
* ------| assets/
* ------| components/
* ------| layouts/
* ------| middleware/
* ------| pages/
* ------| plugins/
* ------| public/
* ------| store/
* ------| server/
* ------| app.config.ts
* ------| app.vue
* ------| error.vue
* ```
*/
srcDir: {
$resolve: async (val, get) => {
if (val && typeof val === "string") {
return resolve(await get("rootDir"), val);
}
const [rootDir, isV4] = await Promise.all([
get("rootDir"),
get("future").then((r) => r.compatibilityVersion === 4)
]);
if (!isV4) {
return rootDir;
}
const srcDir = resolve(rootDir, "app");
if (!existsSync(srcDir)) {
return rootDir;
}
const srcDirFiles = /* @__PURE__ */ new Set();
const files = await readdir(srcDir).catch(() => []);
for (const file of files) {
if (file !== "spa-loading-template.html" && !file.startsWith("router.options")) {
srcDirFiles.add(file);
}
}
if (srcDirFiles.size === 0) {
for (const file of ["app.vue", "App.vue"]) {
if (existsSync(resolve(rootDir, file))) {
return rootDir;
}
}
const keys = ["assets", "layouts", "middleware", "pages", "plugins"];
const dirs = await Promise.all(keys.map((key) => get(`dir.${key}`)));
for (const dir of dirs) {
if (existsSync(resolve(rootDir, dir))) {
return rootDir;
}
}
}
return srcDir;
}
},
/**
* Define the server directory of your Nuxt application, where Nitro
* routes, middleware and plugins are kept.
*
* If a relative path is specified, it will be relative to your `rootDir`.
*
*/
serverDir: {
$resolve: async (val, get) => {
if (val && typeof val === "string") {
const rootDir = await get("rootDir");
return resolve(rootDir, val);
}
const isV4 = (await get("future")).compatibilityVersion === 4;
return join(isV4 ? await get("rootDir") : await get("srcDir"), "server");
}
},
/**
* Define the directory where your built Nuxt files will be placed.
*
* Many tools assume that `.nuxt` is a hidden directory (because it starts
* with a `.`). If that is a problem, you can use this option to prevent that.
* @example
* ```js
* export default {
* buildDir: 'nuxt-build'
* }
* ```
*/
buildDir: {
$resolve: async (val, get) => {
const rootDir = await get("rootDir");
return resolve(rootDir, val && typeof val === "string" ? val : ".nuxt");
}
},
/**
* For multi-app projects, the unique id of the Nuxt application.
*
* Defaults to `nuxt-app`.
*/
appId: {
$resolve: (val) => val && typeof val === "string" ? val : "nuxt-app"
},
/**
* A unique identifier matching the build. This may contain the hash of the current state of the project.
*/
buildId: {
$resolve: async (val, get) => {
if (typeof val === "string") {
return val;
}
const [isDev, isTest2] = await Promise.all([get("dev"), get("test")]);
return isDev ? "dev" : isTest2 ? "test" : randomUUID();
}
},
/**
* Used to set the modules directories for path resolving (for example, webpack's
* `resolveLoading`, `nodeExternals` and `postcss`).
*
* The configuration path is relative to `options.rootDir` (default is current working directory).
*
* Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository.
* @example
* ```js
* export default {
* modulesDir: ['../../node_modules']
* }
* ```
*/
modulesDir: {
$default: ["node_modules"],
$resolve: async (val, get) => {
const rootDir = await get("rootDir");
const modulesDir = /* @__PURE__ */ new Set([resolve(rootDir, "node_modules")]);
if (Array.isArray(val)) {
for (const dir of val) {
if (dir && typeof dir === "string") {
modulesDir.add(resolve(rootDir, dir));
}
}
}
return [...modulesDir];
}
},
/**
* The directory where Nuxt will store the generated files when running `nuxt analyze`.
*
* If a relative path is specified, it will be relative to your `rootDir`.
*/
analyzeDir: {
$resolve: async (val, get) => val && typeof val === "string" ? resolve(await get("rootDir"), val) : resolve(await get("buildDir"), "analyze")
},
/**
* Whether Nuxt is running in development mode.
*
* Normally, you should not need to set this.
*/
dev: {
$resolve: (val) => typeof val === "boolean" ? val : Boolean(isDevelopment)
},
/**
* Whether your app is being unit tested.
*/
test: {
$resolve: (val) => typeof val === "boolean" ? val : Boolean(isTest)
},
/**
* Set to `true` to enable debug mode.
*
* At the moment, it prints out hook names and timings on the server, and
* logs hook arguments as well in the browser.
*
* You can also set this to an object to enable specific debug options.
*
* @type {boolean | (typeof import('../src/types/debug').NuxtDebugOptions) | undefined}
*/
debug: {
$resolve: (val) => {
val ??= isDebug;
if (val === true) {
return {
templates: true,
modules: true,
watchers: true,
hooks: {
client: true,
server: true
},
nitro: true,
router: true,
hydration: true
};
}
if (val && typeof val === "object") {
return val;
}
return false;
}
},
/**
* Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time.
* If set to `false` generated pages will have no content.
*/
ssr: {
$resolve: (val) => typeof val === "boolean" ? val : true
},
/**
* Modules are Nuxt extensions which can extend its core functionality and add endless integrations.
*
* Each module is either a string (which can refer to a package, or be a path to a file), a
* tuple with the module as first string and the options as a second object, or an inline module function.
*
* Nuxt tries to resolve each item in the modules array using node require path
* (in `node_modules`) and then will be resolved from project `srcDir` if `~` alias is used.
* @note Modules are executed sequentially so the order is important. First, the modules defined in `nuxt.config.ts` are loaded. Then, modules found in the `modules/`
* directory are executed, and they load in alphabetical order.
* @example
* ```js
* modules: [
* // Using package name
* '@nuxtjs/axios',
* // Relative to your project srcDir
* '~/modules/awesome.js',
* // Providing options
* ['@nuxtjs/google-analytics', { ua: 'X1234567' }],
* // Inline definition
* function () {}
* ]
* ```
* @type {(typeof import('../src/types/module').NuxtModule<any> | string | [typeof import('../src/types/module').NuxtModule | string, Record<string, any>] | undefined | null | false)[]}
*/
modules: {
$resolve: (val) => {
const modules = [];
if (Array.isArray(val)) {
for (const mod of val) {
if (!mod) {
continue;
}
if (typeof mod === "string" || typeof mod === "function" || Array.isArray(mod) && mod[0]) {
modules.push(mod);
}
}
}
return modules;
}
},
/**
* Customize default directory structure used by Nuxt.
*
* It is better to stick with defaults unless needed.
*/
dir: {
app: {
$resolve: async (val, get) => {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4) {
const [srcDir, rootDir] = await Promise.all([get("srcDir"), get("rootDir")]);
return resolve(await get("srcDir"), val && typeof val === "string" ? val : srcDir === rootDir ? "app" : ".");
}
return val && typeof val === "string" ? val : "app";
}
},
/**
* The assets directory (aliased as `~assets` in your build).
*/
assets: "assets",
/**
* The layouts directory, each file of which will be auto-registered as a Nuxt layout.
*/
layouts: "layouts",
/**
* The middleware directory, each file of which will be auto-registered as a Nuxt middleware.
*/
middleware: "middleware",
/**
* The modules directory, each file in which will be auto-registered as a Nuxt module.
*/
modules: {
$resolve: async (val, get) => {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4) {
return resolve(await get("rootDir"), val && typeof val === "string" ? val : "modules");
}
return val && typeof val === "string" ? val : "modules";
}
},
/**
* The directory which will be processed to auto-generate your application page routes.
*/
pages: "pages",
/**
* The plugins directory, each file of which will be auto-registered as a Nuxt plugin.
*/
plugins: "plugins",
/**
* The shared directory. This directory is shared between the app and the server.
*/
shared: {
$resolve: (val) => {
return val && typeof val === "string" ? val : "shared";
}
},
/**
* The directory containing your static files, which will be directly accessible via the Nuxt server
* and copied across into your `dist` folder when your app is generated.
*/
public: {
$resolve: async (val, get) => {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4) {
return resolve(await get("rootDir"), val && typeof val === "string" ? val : await get("dir.static") || "public");
}
return val && typeof val === "string" ? val : await get("dir.static") || "public";
}
},
// TODO: remove in v4
static: {
// @ts-expect-error schema has invalid types
$schema: { deprecated: "use `dir.public` option instead" },
$resolve: async (val, get) => {
if (val && typeof val === "string") {
return val;
}
return await get("dir.public") || "public";
}
}
},
/**
* The extensions that should be resolved by the Nuxt resolver.
*/
extensions: {
$resolve: (val) => {
const extensions = [".js", ".jsx", ".mjs", ".ts", ".tsx", ".vue"];
if (Array.isArray(val)) {
for (const item of val) {
if (item && typeof item === "string") {
extensions.push(item);
}
}
}
return extensions;
}
},
/**
* You can improve your DX by defining additional aliases to access custom directories
* within your JavaScript and CSS.
* @note Within a webpack context (image sources, CSS - but not JavaScript) you _must_ access
* your alias by prefixing it with `~`.
* @note These aliases will be automatically added to the generated `.nuxt/tsconfig.json` so you can get full
* type support and path auto-complete. In case you need to extend options provided by `./.nuxt/tsconfig.json`
* further, make sure to add them here or within the `typescript.tsConfig` property in `nuxt.config`.
* @example
* ```js
* export default {
* alias: {
* 'images': fileURLToPath(new URL('./assets/images', import.meta.url)),
* 'style': fileURLToPath(new URL('./assets/style', import.meta.url)),
* 'data': fileURLToPath(new URL('./assets/other/data', import.meta.url))
* }
* }
* ```
*
* ```html
* <template>
* <img src="~images/main-bg.jpg">
* </template>
*
* <script>
* import data from 'data/test.json'
* <\/script>
*
* <style>
* // Uncomment the below
* //@import '~style/variables.scss';
* //@import '~style/utils.scss';
* //@import '~style/base.scss';
* body {
* background-image: url('~images/main-bg.jpg');
* }
* </style>
* ```
* @type {Record<string, string>}
*/
alias: {
$resolve: async (val, get) => {
const [srcDir, rootDir, assetsDir, publicDir, buildDir, sharedDir] = await Promise.all([get("srcDir"), get("rootDir"), get("dir.assets"), get("dir.public"), get("buildDir"), get("dir.shared")]);
const srcWithTrailingSlash = withTrailingSlash(srcDir);
const rootWithTrailingSlash = withTrailingSlash(rootDir);
return {
"~": srcWithTrailingSlash,
"@": srcWithTrailingSlash,
"~~": rootWithTrailingSlash,
"@@": rootWithTrailingSlash,
"#shared": withTrailingSlash(resolve(rootDir, sharedDir)),
[basename(assetsDir)]: withTrailingSlash(resolve(srcDir, assetsDir)),
[basename(publicDir)]: withTrailingSlash(resolve(srcDir, publicDir)),
"#build": withTrailingSlash(buildDir),
"#internal/nuxt/paths": resolve(buildDir, "paths.mjs"),
...typeof val === "object" ? val : {}
};
}
},
/**
* Pass options directly to `node-ignore` (which is used by Nuxt to ignore files).
* @see [node-ignore](https://github.com/kaelzhang/node-ignore)
* @example
* ```js
* ignoreOptions: {
* ignorecase: false
* }
* ```
* @type {typeof import('ignore').Options}
*/
ignoreOptions: void 0,
/**
* Any file in `pages/`, `layouts/`, `middleware/`, and `public/` directories will be ignored during
* the build process if its filename starts with the prefix specified by `ignorePrefix`. This is intended to prevent
* certain files from being processed or served in the built application.
* By default, the `ignorePrefix` is set to '-', ignoring any files starting with '-'.
*/
ignorePrefix: {
$resolve: (val) => val && typeof val === "string" ? val : "-"
},
/**
* More customizable than `ignorePrefix`: all files matching glob patterns specified
* inside the `ignore` array will be ignored in building.
*/
ignore: {
$resolve: async (val, get) => {
const [rootDir, ignorePrefix, analyzeDir, buildDir] = await Promise.all([get("rootDir"), get("ignorePrefix"), get("analyzeDir"), get("buildDir")]);
const ignore = /* @__PURE__ */ new Set([
"**/*.stories.{js,cts,mts,ts,jsx,tsx}",
// ignore storybook files
"**/*.{spec,test}.{js,cts,mts,ts,jsx,tsx}",
// ignore tests
"**/*.d.{cts,mts,ts}",
// ignore type declarations
"**/.{pnpm-store,vercel,netlify,output,git,cache,data}",
"**/*.sock",
relative(rootDir, analyzeDir),
relative(rootDir, buildDir)
]);
if (ignorePrefix) {
ignore.add(`**/${ignorePrefix}*.*`);
}
if (Array.isArray(val)) {
for (const pattern of val) {
if (pattern) {
ignore.add(pattern);
}
}
}
return [...ignore];
}
},
/**
* The watch property lets you define patterns that will restart the Nuxt dev server when changed.
*
* It is an array of strings or regular expressions. Strings should be either absolute paths or
* relative to the `srcDir` (and the `srcDir` of any layers). Regular expressions will be matched
* against the path relative to the project `srcDir` (and the `srcDir` of any layers).
* @type {Array<string | RegExp>}
*/
watch: {
$resolve: (val) => {
if (Array.isArray(val)) {
return val.filter((b) => typeof b === "string" || b instanceof RegExp);
}
return [];
}
},
/**
* The watchers property lets you overwrite watchers configuration in your `nuxt.config`.
*/
watchers: {
/** An array of event types, which, when received, will cause the watcher to restart. */
rewatchOnRawEvents: void 0,
/**
* `watchOptions` to pass directly to webpack.
* @see [webpack@4 watch options](https://v4.webpack.js.org/configuration/watch/#watchoptions).
*/
webpack: {
aggregateTimeout: 1e3
},
/**
* Options to pass directly to `chokidar`.
* @see [chokidar](https://github.com/paulmillr/chokidar#api)
* @type {typeof import('chokidar').ChokidarOptions}
*/
chokidar: {
ignoreInitial: true,
ignorePermissionErrors: true
}
},
/**
* Hooks are listeners to Nuxt events that are typically used in modules,
* but are also available in `nuxt.config`.
*
* Internally, hooks follow a naming pattern using colons (e.g., build:done).
*
* For ease of configuration, you can also structure them as an hierarchical
* object in `nuxt.config` (as below).
* @example
* ```js
* import fs from 'node:fs'
* import path from 'node:path'
* export default {
* hooks: {
* build: {
* done(builder) {
* const extraFilePath = path.join(
* builder.nuxt.options.buildDir,
* 'extra-file'
* )
* fs.writeFileSync(extraFilePath, 'Something extra')
* }
* }
* }
* }
* ```
* @type {typeof import('../src/types/hooks').NuxtHooks}
*/
hooks: void 0,
/**
* Runtime config allows passing dynamic config and environment variables to the Nuxt app context.
*
* The value of this object is accessible from server only using `useRuntimeConfig`.
*
* It mainly should hold _private_ configuration which is not exposed on the frontend.
* This could include a reference to your API secret tokens.
*
* Anything under `public` and `app` will be exposed to the frontend as well.
*
* Values are automatically replaced by matching env variables at runtime, e.g. setting an environment
* variable `NUXT_API_KEY=my-api-key NUXT_PUBLIC_BASE_URL=/foo/` would overwrite the two values in the example below.
* @example
* ```js
* export default {
* runtimeConfig: {
* apiKey: '', // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY
* public: {
* baseURL: '' // Exposed to the frontend as well.
* }
* }
* }
* ```
* @type {typeof import('../src/types/config').RuntimeConfig}
*/
runtimeConfig: {
$resolve: async (_val, get) => {
const val = _val && typeof _val === "object" ? _val : {};
const [app, buildId] = await Promise.all([get("app"), get("buildId")]);
provideFallbackValues(val);
return defu(val, {
public: {},
app: {
buildId,
baseURL: app.baseURL,
buildAssetsDir: app.buildAssetsDir,
cdnURL: app.cdnURL
}
});
}
},
/**
* Additional app configuration
*
* For programmatic usage and type support, you can directly provide app config with this option.
* It will be merged with `app.config` file as default value.
* @type {typeof import('../src/types/config').AppConfig}
*/
appConfig: {
nuxt: {}
},
$schema: {}
});
function provideFallbackValues(obj) {
for (const key in obj) {
if (typeof obj[key] === "undefined" || obj[key] === null) {
obj[key] = "";
} else if (typeof obj[key] === "object") {
provideFallbackValues(obj[key]);
}
}
}
const _messages = { "appName": "Nuxt", "version": "", "loading": "Loading" };
const template = (messages) => {
messages = { ..._messages, ...messages };
return '<!DOCTYPE html><html lang="en"><head><title>' + escapeHtml(messages.loading) + " | " + escapeHtml(messages.appName) + '</title><meta charset="utf-8"><meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0" name="viewport"><style>.nuxt-loader-bar{animation:gradient 2s infinite;animation-fill-mode:forwards;animation-timing-function:linear;background:repeating-linear-gradient(90deg,#36e4da 0,#1de0b1 25%,#00dc82 50%,#1de0b1 75%,#36e4da);background-position:0 0;background-size:200% auto;bottom:0;height:100px;height:5px;left:0;position:fixed;right:0}.visual-effects .nuxt-loader-bar{bottom:-50px;filter:blur(100px);height:100px;left:-50px;right:-50px}.visual-effects .mouse-gradient{background:repeating-linear-gradient(90deg,#00dc82 0,#1de0b1 50%,#36e4da);filter:blur(100px);opacity:.5}#animation-toggle{opacity:0;padding:10px;position:fixed;right:0;top:0;transition:opacity .4s ease-in}#animation-toggle:hover{opacity:.8}@keyframes gradient{0%{background-position:0 0}to{background-position:-200% 0}}@media (prefers-color-scheme:dark){body,html{color:#fff;color-scheme:dark}.nuxt-loader-bar{opacity:.5}}*,:after,:before{border-color:var(--un-default-border-color,#e5e7eb);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}a{text-decoration:inherit}a,button{color:inherit}button{font-family:inherit;font-feature-settings:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0;text-transform:none}[type=button],button{-webkit-appearance:button;background-color:transparent;background-image:none}button{cursor:pointer}svg{display:block;vertical-align:middle}*,:after,:before{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 transparent;--un-ring-shadow:0 0 transparent;--un-shadow-inset: ;--un-shadow:0 0 transparent;--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.z-20{z-index:20}.h-\\[200px\\]{height:200px}.min-h-screen{min-height:100vh}.w-\\[200px\\]{width:200px}.flex{display:flex}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.overflow-hidden{overflow:hidden}.rounded-full{border-radius:9999px}.bg-white{--un-bg-opacity:1;background-color:rgb(255 255 255/var(--un-bg-opacity))}.text-center{text-align:center}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.dark\\:bg-black{--un-bg-opacity:1;background-color:rgb(0 0 0/var(--un-bg-opacity))}}</style><script>!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll(\'link[rel="modulepreload"]\'))r(e);new MutationObserver((e=>{for(const o of e)if("childList"===o.type)for(const e of o.addedNodes)"LINK"===e.tagName
};
const dev = defineResolvers({
devServer: {
/**
* Whether to enable HTTPS.
* @example
* ```ts
* export default defineNuxtConfig({
* devServer: {
* https: {
* key: './server.key',
* cert: './server.crt'
* }
* }
* })
* ```
* @type {boolean | { key: string; cert: string } | { pfx: string; passphrase: string }}
*/
https: false,
/** Dev server listening port */
port: Number(process.env.NUXT_PORT || process.env.NITRO_PORT || process.env.PORT || 3e3),
/**
* Dev server listening host
* @type {string | undefined}
*/
host: process.env.NUXT_HOST || process.env.NITRO_HOST || process.env.HOST || void 0,
/**
* Listening dev server URL.
*
* This should not be set directly as it will always be overridden by the
* dev server with the full URL (for module and internal use).
*/
url: "http://localhost:3000",
/**
* Template to show a loading screen
* @type {(data: { loading?: string }) => string}
*/
loadingTemplate: template,
/**
* Set CORS options for the dev server
* @type {typeof import('h3').H3CorsOptions}
*/
cors: {
origin: [/^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/]
}
}
});
const esbuild = defineResolvers({
esbuild: {
/**
* Configure shared esbuild options used within Nuxt and passed to other builders, such as Vite or Webpack.
* @type {import('esbuild').TransformOptions}
*/
options: {
target: {
$resolve: async (val, get) => {
if (typeof val === "string") {
return val;
}
const useDecorators = await get("experimental").then((r) => r?.decorators === true);
if (useDecorators) {
return "es2024";
}
return "esnext";
}
},
jsxFactory: "h",
jsxFragment: "Fragment",
tsconfigRaw: {
$resolve: async (_val, get) => {
const val = typeof _val === "string" ? JSON.parse(_val) : _val && typeof _val === "object" ? _val : {};
const useDecorators = await get("experimental").then((r) => r?.decorators === true);
if (!useDecorators) {
return val;
}
return defu({
compilerOptions: {
experimentalDecorators: false
}
}, val);
}
}
}
}
});
const oxc = defineResolvers({
/**
* Configure shared oxc options used within Nuxt and passed where necessary.
*/
oxc: {
/**
* Options for `oxc-transform`
* @see [Oxc transform docs](https://oxc.rs/docs/guide/usage/transformer.html)
*/
transform: {
options: {
target: {
$resolve: async (val, get) => {
if (typeof val === "string") {
return val;
}
const useDecorators = await get("experimental").then(
(r) => r?.decorators === true
);
if (useDecorators) {
return "es2024";
}
return "esnext";
}
},
jsxFactory: "h",
jsxFragment: "Fragment"
}
}
}
});
const experimental = defineResolvers({
/**
* `future` is for early opting-in to new features that will become default in a future
* (possibly major) version of the framework.
*/
future: {
/**
* Enable early access to Nuxt v4 features or flags.
*
* Setting `compatibilityVersion` to `4` changes defaults throughout your
* Nuxt configuration, but you can granularly re-enable Nuxt v3 behaviour
* when testing (see example). Please file issues if so, so that we can
* address in Nuxt or in the ecosystem.
*
* @example
* ```ts
* export default defineNuxtConfig({
* future: {
* compatibilityVersion: 4,
* },
* // To re-enable _all_ Nuxt v3 behaviour, set the following options:
* srcDir: '.',
* dir: {
* app: 'app'
* },
* experimental: {
* compileTemplate: true,
* templateUtils: true,
* relativeWatchPaths: true,
* resetAsyncDataToUndefined: true,
* defaults: {
* useAsyncData: {
* deep: true
* }
* }
* },
* unhead: {
* renderSSRHeadOptions: {
* omitLineBreaks: false
* }
* }
* })
* ```
* @type {3 | 4}
*/
compatibilityVersion: 3,
/**
* This enables early access to the experimental multi-app support.
* @see [Nuxt Issue #21635](https://github.com/nuxt/nuxt/issues/21635)
*/
multiApp: false,
/**
* This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting
* for frameworks like Nuxt and Vite.
*
* It improves type support when using modern libraries with `exports`.
*
* You can set it to false to use the legacy 'Node' mode, which is the default for TypeScript.
*
* @see [TypeScript PR implementing `bundler` module resolution](https://github.com/microsoft/TypeScript/pull/51669)
*/
typescriptBundlerResolution: {
async $resolve(val, get) {
val = typeof val === "boolean" ? val : await get("experimental").then((e) => e?.typescriptBundlerResolution);
if (typeof val === "boolean") {
return val;
}
const setting = await get("typescript.tsConfig").then((r) => r?.compilerOptions?.moduleResolution);
if (setting) {
return setting.toLowerCase() === "bundler";
}
return true;
}
}
},
/**
* Some features of Nuxt are available on an opt-in basis, or can be disabled based on your needs.
*/
features: {
/**
* Inline styles when rendering HTML (currently vite only).
*
* You can also pass a function that receives the path of a Vue component
* and returns a boolean indicating whether to inline the styles for that component.
* @type {boolean | ((id?: string) => boolean)}
*/
inlineStyles: {
async $resolve(_val, get) {
const val = typeof _val === "boolean" || typeof _val === "function" ? _val : await get("experimental").then((e) => e?.inlineSSRStyles);
if (val === false || await get("dev") || await get("ssr") === false || // @ts-expect-error TODO: handled normalised types
await get("builder") === "@nuxt/webpack-builder") {
return false;
}
return val ?? ((await get("future")).compatibilityVersion === 4 ? (id) => !!id && id.includes(".vue") : true);
}
},
/**
* Stream server logs to the client as you are developing. These logs can
* be handled in the `dev:ssr-logs` hook.
*
* If set to `silent`, the logs will not be printed to the browser console.
* @type {boolean | 'silent'}
*/
devLogs: {
async $resolve(val, get) {
if (typeof val === "boolean" || val === "silent") {
return val;
}
const [isDev, isTest] = await Promise.all([get("dev"), get("test")]);
return isDev && !isTest;
}
},
/**
* Turn off rendering of Nuxt scripts and JS resource hints.
* You can also disable scripts more granularly within `routeRules`.
*
* If set to 'production' or `true`, JS will be disabled in production mode only.
* @type {'production' | 'all' | boolean}
*/
noScripts: {
async $resolve(val, get) {
const isValidLiteral = (val2) => {
return typeof val2 === "string" && ["production", "all"].includes(val2);
};
return val === true ? "production" : val === false || isValidLiteral(val) ? val : await get("experimental").then((e) => e?.noScripts && "production") ?? false;
}
}
},
experimental: {
/**
* Enable to use experimental decorators in Nuxt and Nitro.
*
* @see https://github.com/tc39/proposal-decorators
*/
decorators: false,
/**
* Set to true to generate an async entry point for the Vue bundle (for module federation support).
*/
asyncEntry: {
$resolve: (val) => typeof val === "boolean" ? val : false
},
// TODO: Remove when nitro has support for mocking traced dependencies
// https://github.com/nitrojs/nitro/issues/1118
/**
* Externalize `vue`, `@vue/*` and `vue-router` when building.
* @see [Nuxt Issue #13632](https://github.com/nuxt/nuxt/issues/13632)
*/
externalVue: true,
/**
* Tree shakes contents of client-only components from server bundle.
* @see [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750)
* @deprecated This option will no longer be configurable in Nuxt v4
*/
treeshakeClientOnly: {
async $resolve(val, get) {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4 && val === false) {
console.warn("Enabling `experimental.treeshakeClientOnly` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.");
return true;
}
return typeof val === "boolean" ? val : true;
}
},
/**
* Emit `app:chunkError` hook when there is an error loading vite/webpack
* chunks.
*
* By default, Nuxt will also perform a reload of the new route
* when a chunk fails to load when navigating to a new route (`automatic`).
*
* Setting `automatic-immediate` will lead Nuxt to perform a reload of the current route
* right when a chunk fails to load (instead of waiting for navigation).
*
* You can disable automatic handling by setting this to `false`, or handle
* chunk errors manually by setting it to `manual`.
* @see [Nuxt PR #19038](https://github.com/nuxt/nuxt/pull/19038)
* @type {false | 'manual' | 'automatic' | 'automatic-immediate'}
*/
emitRouteChunkError: {
$resolve: (val) => {
if (val === true) {
return "manual";
}
if (val === "reload") {
return "automatic";
}
if (val === false) {
return false;
}
const validOptions = /* @__PURE__ */ new Set(["manual", "automatic", "automatic-immediate"]);
if (typeof val === "string" && validOptions.has(val)) {
return val;
}
return "automatic";
}
},
/**
* By default the route object returned by the auto-imported `useRoute()` composable
* is kept in sync with the current page in view in `<NuxtPage>`. This is not true for
* `vue-router`'s exported `useRoute` or for the default `$route` object available in your
* Vue templates.
*
* By enabling this option a mixin will be injected to keep the `$route` template object
* in sync with Nuxt's managed `useRoute()`.
*/
templateRouteInjection: true,
/**
* Whether to restore Nuxt app state from `sessionStorage` when reloading the page
* after a chunk error or manual `reloadNuxtApp()` call.
*
* To avoid hydration errors, it will be applied only after the Vue app has been mounted,
* meaning there may be a flicker on initial load.
*
* Consider carefully before enabling this as it can cause unexpected behavior, and
* consider providing explicit keys to `useState` as auto-generated keys may not match
* across builds.
* @type {boolean}
*/
restoreState: false,
/** Render JSON payloads with support for revivifying complex types. */
renderJsonPayloads: true,
/**
* Disable vue server renderer endpoint within nitro.
*/
noVueServer: false,
/**
* When this option is enabled (by default) payload of pages that are prerendered are extracted
* @type {boolean | undefined}
*/
payloadExtraction: true,
/**
* Whether to enable the experimental `<NuxtClientFallback>` component for rendering content on the client
* if there's an error in SSR.
*/
clientFallback: false,
/** Enable cross-origin prefetch using the Speculation Rules API. */
crossOriginPrefetch: false,
/**
* Enable View Transition API integration with client-side router.
* @see [View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions)
* @type {boolean | 'always'}
*/
viewTransition: false,
/**
* Write early hints when using node server.
* @note nginx does not support 103 Early hints in the current version.
*/
writeEarlyHints: false,
/**
* Experimental component islands support with `<NuxtIsland>` and `.island.vue` files.
*
* By default it is set to 'auto', which means it will be enabled only when there are islands,
* server components or server pages in your app.
* @type {true | 'auto' | 'local' | 'local+remote' | Partial<{ remoteIsland: boolean, selectiveClient: boolean | 'deep' }> | false}
*/
componentIslands: {
$resolve: (val) => {
if (val === "local+remote") {
return { remoteIsland: true };
}
if (val === "local") {
return true;
}
return val ?? "auto";
}
},
/**
* Config schema support
* @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592)
* @deprecated This option will no longer be configurable in Nuxt v4
*/
configSchema: {
async $resolve(val, get) {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4 && val === false) {
console.warn("Enabling `experimental.configSchema` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.");
return true;
}
return typeof val === "boolean" ? val : true;
}
},
/**
* Whether or not to add a compatibility layer for modules, plugins or user code relying on the old
* `@vueuse/head` API.
*
* This is disabled to reduce the client-side bundle by ~0.5kb.
* @deprecated This feature will be removed in Nuxt v4.
*/
polyfillVueUseHead: {
async $resolve(val, get) {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4 && val === true) {
console.warn("Disabling `experimental.polyfillVueUseHead` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.");
return false;
}
return typeof val === "boolean" ? val : false;
}
},
/**
* Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
* @deprecated This feature will be removed in Nuxt v4.
*/
respectNoSSRHeader: {
async $resolve(val, get) {
const isV4 = (await get("future")).compatibilityVersion === 4;
if (isV4 && val === true) {
console.warn("Disabling `experimental.respectNoSSRHeader` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.");
return false;
}
return typeof val === "boolean" ? val : false;
}
},
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
localLayerAliases: true,
/** Enable the new experimental typed router using [unplugin-vue-router](https://github.com/posva/unplugin-vue-router). */
typedPages: false,
/**
* Use app manifests to respect route rules on client-side.
*/
appManifest: true,
/**
* Set the time interval (in ms) to check for new builds. Disabled when `experimental.appManifest` is `false`.
*
* Set to `false` to disable.
* @type {number | false}
*/
checkOutdatedBuildInterval: 1e3 * 60 * 60,
/**
* Set an alternative watcher that will be used as the watching service for Nuxt.
*
* Nuxt uses 'chokidar-granular' if your source directory is the same as your root
* directory . This will ignore top-level directories (like `node_modules` and `.git`)
* that are excluded from watching.
*
* You can set this instead to `parcel` to use `@parcel/watcher`, which may improve
* performance in large projects or on Windows platforms.
*
* You can also set this to `chokidar` to watch all files in your source directory.
* @see [chokidar](https://github.com/paulmillr/chokidar)
* @see [@parcel/watcher](https://github.com/parcel-bundler/watcher)
* @type {'chokidar' | 'parcel' | 'chokidar-granular'}
*/
watcher: {
$resolve: async (val, get) => {
const validOptions = /* @__PURE__ */ new Set(["chokidar", "parcel", "chokidar-granular"]);
if (typeof val === "string" && validOptions.has(val)) {
return val;
}
const [srcDir, rootDir] = await Promise.all([get("srcDir"), get("rootDir")]);
if (srcDir === rootDir) {
return "chokidar-granular";
}
return "chokidar";
}
},
/**
* Enable native async context to be accessible for nested composables
* @see [Nuxt PR #20918](https://github.com/nuxt/nuxt/pull/20918)
*/
asyncContext: false,
/**
* Use new experimental head optimisations:
*
* - Add the capo.js head plugin in order to render tags in of the head in a more performant way.
* - Uses the hash hydration plugin to reduce initial hydration
*
* @see [Nuxt Discussion #22632](https://github.com/nuxt/nuxt/discussions/22632)
*/
headNext: true,
/**
* Allow defining `routeRules` directly within your `~/pages` directory using `defineRouteRules`.
*
* Rules are converted (based on the path) and applied for server requests. For example, a rule
* defined in `~/pages/foo/bar.vue` will be applied to `/foo/bar` requests. A rule in `~/pages/foo/[id].vue`
* will be applied to `/foo/**` requests.
*
* For more control, such as if you are using a custom `path` or `alias` set in the page's `definePageMeta`, you
* should set `routeRules` directly within your `nuxt.config`.
*/
inlineRouteRules: false,
/**
* Allow exposing some route metadata defined in `definePageMeta` at build-time to modules (alias, name, path, redirect, props, middleware).
*
* This only works with static or strings/arrays rather than variables or conditional assignment.
*
* @see [Nuxt Issues #24770](https://github.com/nuxt/nuxt/issues/24770)
* @type {boolean | 'after-resolve'}
*/
scanPageMeta: {
async $resolve(val, get) {
return typeof val === "boolean" || val === "after-resolve" ? val : (await get("future")).compatibilityVersion === 4 ? "after-resolve" : true;
}
},
/**
* Configure additional keys to extract from the page metadata when using `scanPageMeta`.
*
* This allows modules to access additional metadata from the page metadata. It's recommended
* to augment the NuxtPage types with your keys.
*
* @type {string[]}
*/
extraPageMetaExtractionKeys: [],
/**
* Automatically share payload _data_ between pages that are prerendered. This can result in a significant
* performance improvement when prerendering sites that use `useAsyncData` or `useFetch` and fetch the same
* data in different pages.
*
* It is particularly important when enabling this feature to make sure that any unique key of your data
* is always resolvable to the same data. For example, if you are using `useAsyncData` to fetch
* data related to a particular page, you should provide a key that uniquely matches that data. (`useFetch`
* should do this automatically for you.)
* @example
* ```ts
* // This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
* // to the data fetched, but Nuxt can't know that because it's not reflected in the key.
* const route = useRoute()
* const { data } = await useAsyncData(async () => {
* return await $fetch(`/api/my-page/${route.params.slug}`)
* })
* // Instead, you should use a key that uniquely identifies the data fetched.
* const { data } = await useAsyncData(route.params.slug, async () => {
* return await $fetch(`/api/my-page/${route.params.slug}`)
* })
* ```
*/
sharedPrerenderData: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion === 4;
}
},
/**
* Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values.
* @see [CookieStore](https://developer.mozilla.org/en-US/docs/Web/API/CookieStore)
*/
cookieStore: true,
/**
* This allows specifying the default options for core Nuxt components and composables.
*
* These options will likely be moved elsewhere in the future, such as into `app.config` or into the
* `app/` directory.
*/
defaults: {
/** @type {typeof import('nuxt/app')['NuxtLinkOptions']} */
nuxtLink: {
componentName: "NuxtLink",
prefetch: true,
prefetchOn: {
visibility: true
}
},
/**
* Options that apply to `useAsyncData` (and also therefore `useFetch`)
*/
useAsyncData: {
/** @type {'undefined' | 'null'} */
value: {
async $resolve(val, get) {
const validOptions = ["undefined", "null"];
return typeof val === "string" && validOptions.includes(val) ? val : (await get("future")).compatibilityVersion === 4 ? "undefined" : "null";
}
},
/** @type {'undefined' | 'null'} */
errorValue: {
async $resolve(val, get) {
const validOptions = ["undefined", "null"];
return typeof val === "string" && validOptions.includes(val) ? val : (await get("future")).compatibilityVersion === 4 ? "undefined" : "null";
}
},
deep: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
}
},
/** @type {Pick<typeof import('ofetch')['FetchOptions'], 'timeout' | 'retry' | 'retryDelay' | 'retryStatusCodes'>} */
useFetch: {}
},
/**
* Automatically polyfill Node.js imports in the client build using `unenv`.
* @see [unenv](https://github.com/unjs/unenv)
*
* **Note:** To make globals like `Buffer` work in the browser, you need to manually inject them.
*
* ```ts
* import { Buffer } from 'node:buffer'
*
* globalThis.Buffer = globalThis.Buffer || Buffer
* ```
* @type {boolean}
*/
clientNodeCompat: false,
/**
* Whether to use `lodash.template` to compile Nuxt templates.
*
* This flag will be removed with the release of v4 and exists only for
* advance testing within Nuxt v3.12+ or in [the nightly release channel](/docs/guide/going-further/nightly-release-channel).
*/
compileTemplate: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
/**
* Whether to provide a legacy `templateUtils` object (with `serialize`,
* `importName` and `importSources`) when compiling Nuxt templates.
*
* This flag will be removed with the release of v4 and exists only for
* advance testing within Nuxt v3.12+ or in [the nightly release channel](/docs/guide/going-further/nightly-release-channel).
*/
templateUtils: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
/**
* Whether to provide relative paths in the `builder:watch` hook.
*
* This flag will be removed with the release of v4 and exists only for
* advance testing within Nuxt v3.12+ or in [the nightly release channel](/docs/guide/going-further/nightly-release-channel).
*/
relativeWatchPaths: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
/**
* Whether `clear` and `clearNuxtData` should reset async data to its _default_ value or update
* it to `null`/`undefined`.
*/
resetAsyncDataToUndefined: {
async $resolve(val, get) {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
/**
* Wait for a single animation frame before navigation, which gives an opportunity
* for the browser to repaint, acknowledging user interaction.
*
* It can reduce INP when navigating on prerendered routes.
*/
navigationRepaint: true,
/**
* Cache Nuxt/Nitro build artifacts based on a hash of the configuration and source files.
*
* This only works for source files within `srcDir` and `serverDir` for the Vue/Nitro parts of your app.
*/
buildCache: false,
/**
* Ensure that auto-generated Vue component names match the full component name
* you would use to auto-import the component.
*/
normalizeComponentNames: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion === 4;
}
},
/**
* Keep showing the spa-loading-template until suspense:resolve
* @see [Nuxt Issues #21721](https://github.com/nuxt/nuxt/issues/21721)
* @type {'body' | 'within'}
*/
spaLoadingTemplateLocation: {
$resolve: async (val, get) => {
const validOptions = /* @__PURE__ */ new Set(["body", "within"]);
return typeof val === "string" && validOptions.has(val) ? val : (await get("future")).compatibilityVersion === 4 ? "body" : "within";
}
},
/**
* Enable timings for Nuxt application hooks in the performance panel of Chromium-based browsers.
*
* This feature adds performance markers for Nuxt hooks, allowing you to track their execution time
* in the browser's Performance tab. This is particularly useful for debugging performance issues.
*
* @example
* ```ts
* // nuxt.config.ts
* export default defineNuxtConfig({
* experimental: {
* // Enable performance markers for Nuxt hooks in browser devtools
* browserDevtoolsTiming: true
* }
* })
* ```
*
* @see [PR #29922](https://github.com/nuxt/nuxt/pull/29922)
* @see [Chrome DevTools Performance API](https://developer.chrome.com/docs/devtools/performance/extension#tracks)
*/
browserDevtoolsTiming: {
$resolve: async (val, get) => typeof val === "boolean" ? val : await get("dev")
},
/**
* Enable integration with Chrome DevTools Workspaces
* for Nuxt projects.
* @see [Chrome DevTools Project Settings](https://docs.google.com/document/d/1rfKPnxsNuXhnF7AiQZhu9kIwdiMS5hnAI05HBwFuBSM)
*/
chromeDevtoolsProjectSettings: true,
/**
* Record mutations to `nuxt.options` in module context, helping to debug configuration changes
* made by modules during the Nuxt initialization phase.
*
* When enabled, Nuxt will track which modules modify configuration options, making it
* easier to trace unexpected configuration changes.
*
* @example
* ```ts
* // nuxt.config.ts
* export default defineNuxtConfig({
* experimental: {
* // Enable tracking of config mutations by modules
* debugModuleMutation: true
* }
* })
* ```
*
* @see [PR #30555](https://github.com/nuxt/nuxt/pull/30555)
*/
debugModuleMutation: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : Boolean(await get("debug"));
}
},
/**
* Enable automatic configuration of hydration strategies for `<Lazy>` components.
*
* This feature intelligently determines when to hydrate lazy components based on
* visibility, idle time, or other triggers, improving performance by deferring
* hydration of components until they're needed.
*
* @example
* ```ts
* // nuxt.config.ts
* export default defineNuxtConfig({
* experimental: {
* lazyHydration: true // Enable smart hydration strategies for Lazy components
* }
* })
*
* // In your Vue components
* <template>
* <Lazy>
* <ExpensiveComponent />
* </Lazy>
* </template>
* ```
*
* @see [PR #26468](https://github.com/nuxt/nuxt/pull/26468)
*/
lazyHydration: {
$resolve: (val) => {
return typeof val === "boolean" ? val : true;
}
},
/**
* Disable resolving imports into Nuxt templates from the path of the module that added the template.
*
* By default, Nuxt attempts to resolve imports in templates relative to the module that added them.
* Setting this to `false` disables this behavior, which may be useful if you're experiencing
* resolution conflicts in certain environments.
*
* @example
* ```ts
* // nuxt.config.ts
* export default defineNuxtConfig({
* experimental: {
* // Disable template import resolution from module path
* templateImportResolution: false
* }
* })
* ```
*
* @see [PR #31175](https://github.com/nuxt/nuxt/pull/31175)
*/
templateImportResolution: true,
/**
* Whether to clean up Nuxt static and asyncData caches on route navigation.
*
* Nuxt will automatically purge cached data from `useAsyncData` and `nuxtApp.static.data`. This helps prevent memory leaks
* and ensures fresh data is loaded when needed, but it is possible to disable it.
*
* @example
* ```ts
* // nuxt.config.ts
* export default defineNuxtConfig({
* experimental: {
* // Disable automatic cache cleanup (default is true)
* purgeCachedData: false
* }
* })
* ```
*
* @see [PR #31379](https://github.com/nuxt/nuxt/pull/31379)
*/
purgeCachedData: {
$resolve: (val) => {
return typeof val === "boolean" ? val : true;
}
},
/**
* Whether to call and use the result from `getCachedData` on manual refresh for `useAsyncData` and `useFetch`.
*/
granularCachedData: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion === 4;
}
},
/**
* Whether to run `useFetch` when the key changes, even if it is set to `immediate: false` and it has not been triggered yet.
*
* `useFetch` and `useAsyncData` will always run when the key changes if `immediate: true` or if it has been already triggered.
*/
alwaysRunFetchOnKeyChange: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
/**
* Whether to parse `error.data` when rendering a server error page.
*/
parseErrorData: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion === 4;
}
},
/**
* Whether Nuxt should stop if a Nuxt module is incompatible.
*/
enforceModuleCompatibility: false,
/**
* For `useAsyncData` and `useFetch`, whether `pending` should be `true` when data has not yet started to be fetched.
*/
pendingWhenIdle: {
$resolve: async (val, get) => {
return typeof val === "boolean" ? val : (await get("future")).compatibilityVersion !== 4;
}
},
entryImportMap: true
}
});
const generate = defineResolvers({
generate: {
/**
* The routes to generate.
*
* If you are using the crawler, this will be only the starting point for route generation.
* This is often necessary when using dynamic routes.
*
* It is preferred to use `nitro.prerender.routes`.
* @example
* ```js
* routes: ['/users/1', '/users/2', '/users/3']
* ```
* @type {string | string[]}
*/
routes: [],
/**
* This option is no longer used. Instead, use `nitro.prerender.ignore`.
* @deprecated
*/
exclude: []
}
});
const internal = defineResolvers({
/** @private */
_majorVersion: 3,
/** @private */
_legacyGenerate: false,
/** @private */
_start: false,
/** @private */
_build: false,
/** @private */
_generate: false,
/** @private */
_prepare: false,
/** @private */
_cli: false,
/** @private */
_requiredModules: {},
/**
* @private
* @type {{ dotenv?: boolean | import('c12').DotenvOptions }}
*/
_loadOptions: void 0,
/** @private */
_nuxtConfigFile: void 0,
/** @private */
_nuxtConfigFiles: [],
/** @private */
appDir: "",
/**
* @private
* @type {Array<{ meta: typeof import('../src/types/module').ModuleMeta; module: typeof import('../src/types/module').NuxtModule, timings?: Record<string, number | undefined>; entryPath?: string }>}
*/
_installedModules: [],
/** @private */
_modules: []
});
const nitro = defineResolvers({
/**
* Configuration for Nitro.
* @see [Nitro configuration docs](https://nitro.build/config/)
* @type {typeof import('nitropack')['NitroConfig']}
*/
nitro: {
runtimeConfig: {
$resolve: async (val, get) => {
const runtimeConfig = await get("runtimeConfig");
return {
...runtimeConfig,
app: {
...runtimeConfig.app,
baseURL: runtimeConfig.app.baseURL.startsWith("./") ? runtimeConfig.app.baseURL.slice(1) : runtimeConfig.app.baseURL
},
nitro: {
envPrefix: "NUXT_",
...runtimeConfig.nitro
}
};
}
},
routeRules: {
$resolve: async (val, get) => {
return {
...await get("routeRules"),
...val && typeof val === "object" ? val : {}
};
}
}
},
/**
* Global route options applied to matching server routes.
* @experimental This is an experimental feature and API may change in the future.
* @see [Nitro route rules documentation](https://nitro.build/config/#routerules)
* @type {typeof import('nitropack')['NitroConfig']['routeRules']}
*/
routeRules: {},
/**
* Nitro server handlers.
*
* Each handler accepts the following options:
*
* - handler: The path to the file defining the handler.
* - route: The route under which the handler is available. This follows the conventions of [rou3](https://github.com/unjs/rou3).
* - method: The HTTP method of requests that should be handled.
* - middleware: Specifies whether it is a middleware handler.
* - lazy: Specifies whether to use lazy loading to import the handler.
*
* @see [`server/` directory documentation](https://nuxt.com/docs/guide/directory-structure/server)
* @note Files from `server/api`, `server/middleware` and `server/routes` will be automatically registered by Nuxt.
* @example
* ```js
* serverHandlers: [
* { route: '/path/foo/**:name', handler: '~/server/foohandler.ts' }
* ]
* ```
* @type {typeof import('nitropack')['NitroEventHandler'][]}
*/
serverHandlers: [],
/**
* Nitro development-only server handlers.
* @see [Nitro server routes documentation](https://nitro.build/guide/routing)
* @type {typeof import('nitropack')['NitroDevEventHandler'][]}
*/
devServerHandlers: []
});
const ensureItemIsLast = (item) => (arr) => {
const index = arr.indexOf(item);
if (index !== -1) {
arr.splice(index, 1);
arr.push(item);
}
return arr;
};
const orderPresets = {
cssnanoLast: ensureItemIsLast("cssnano"),
autoprefixerLast: ensureItemIsLast("autoprefixer"),
autoprefixerAndCssnanoLast(names) {
return orderPresets.cssnanoLast(orderPresets.autoprefixerLast(names));
}
};
const postcss = defineResolvers({
postcss: {
/**
* A strategy for ordering PostCSS plugins.
*
* @type {'cssnanoLast' | 'autoprefixerLast' | 'autoprefixerAndCssnanoLast' | string[] | ((names: string[]) => string[])}
*/
order: {
$resolve: (val) => {
if (typeof val === "string") {
if (!(val in orderPresets)) {
throw new Error(`[nuxt] Unknown PostCSS order preset: ${val}`);
}
return orderPresets[val];
}
if (typeof val === "function") {
return val;
}
if (Array.isArray(val)) {
return val;
}
return orderPresets.autoprefixerAndCssnanoLast;
}
},
/**
* Options for configuring PostCSS plugins.
*
* @see [PostCSS docs](https://postcss.org/)
* @type {Record<string, unknown> & { autoprefixer?: typeof import('autoprefixer').Options; cssnano?: typeof import('cssnano').Options }}
*/
plugins: {
/**
* Plugin to parse CSS and add vendor prefixes to CSS rules.
*
* @see [`autoprefixer`](https://github.com/postcss/autoprefixer)
*/
autoprefixer: {},
/**
* @see [`cssnano` configuration options](https://cssnano.github.io/cssnano/docs/config-file/#configuration-options)
*/
cssnano: {
$resolve: async (val, get) => {
if (val || val === false) {
return val;
}
if (await get("dev")) {
return false;
}
return {};
}
}
}
}
});
const router = defineResolvers({
router: {
/**
* Additional router options passed to `vue-router`. On top of the options for `vue-router`,
* Nuxt offers additional options to customize the router (see below).
* @note Only JSON serializable options should be passed by Nuxt config.
* For more control, you can use `app/router.options.ts` file.
* @see [Vue Router documentation](https://router.vuejs.org/api/interfaces/routeroptions.html).
* @type {typeof import('../src/types/router').RouterConfigSerializable}
*/
options: {
/**
* You can enable hash history in SPA mode. In this mode, router uses a hash character (#) before
* the actual URL that is internally passed. When enabled, the
* **URL is never sent to the server** and **SSR is not supported**.
* @type {typeof import('../src/types/router').RouterConfigSerializable['hashMode']}
* @default false
*/
hashMode: false,
/**
* Customize the scroll behavior for hash links.
* @type {typeof import('../src/types/router').RouterConfigSerializable['scrollBehaviorType']}
* @default 'auto'
*/
scrollBehaviorType: "auto"
}
}
});
const typescript = defineResolvers({
/**
* Configuration for Nuxt's TypeScript integration.
*
*/
typescript: {
/**
* TypeScript comes with certain checks to give you more safety and analysis of your program.
* Once youve converted your codebase to TypeScript, you can start enabling these checks for greater safety.
* [Read More](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks)
*/
strict: true,
/**
* Which builder types to include for your project.
*
* By default Nuxt infers this based on your `builder` option (defaulting to 'vite') but you can either turn off
* builder environment types (with `false`) to handle this fully yourself, or opt for a 'shared' option.
*
* The 'shared' option is advised for module authors, who will want to support multiple possible builders.
* @type {'vite' | 'webpack' | 'rspack' | 'shared' | false | undefined | null}
*/
builder: {
$resolve: (val) => {
const validBuilderTypes = /* @__PURE__ */ new Set(["vite", "webpack", "rspack", "shared"]);
if (typeof val === "string" && validBuilderTypes.has(val)) {
return val;
}
if (val === false) {
return false;
}
return null;
}
},
/**
* Modules to generate deep aliases for within `compilerOptions.paths`. This does not yet support subpaths.
* It may be necessary when using Nuxt within a pnpm monorepo with `shamefully-hoist=false`.
*/
hoist: {
$resolve: (val) => {
const defaults = [
// Nitro auto-imported/augmented dependencies
"nitropack/types",
"nitropack/runtime",
"nitropack",
"defu",
"h3",
"consola",
"ofetch",
// Key nuxt dependencies
"@unhead/vue",
"@nuxt/devtools",
"vue",
"@vue/runtime-core",
"@vue/compiler-sfc",
"vue-router",
"vue-router/auto-routes",
"unplugin-vue-router/client",
"@nuxt/schema",
"nuxt"
];
return val === false ? [] : Array.isArray(val) ? val.concat(defaults) : defaults;
}
},
/**
* Include parent workspace in the Nuxt project. Mostly useful for themes and module authors.
*/
includeWorkspace: false,
/**
* Enable build-time type checking.
*
* If set to true, this will type check in development. You can restrict this to build-time type checking by setting it to `build`.
* Requires to install `typescript` and `vue-tsc` as dev dependencies.
* @see [Nuxt TypeScript docs](https://nuxt.com/docs/guide/concepts/typescript)
* @type {boolean | 'build'}
*/
typeCheck: false,
/**
* You can extend generated `.nuxt/tsconfig.json` using this option.
* @type {0 extends 1 & RawVueCompilerOptions ? typeof import('pkg-types')['TSConfig'] : typeof import('pkg-types')['TSConfig'] & { vueCompilerOptions?: typeof import('@vue/language-core')['RawVueCompilerOptions'] }}
*/
tsConfig: {},
/**
* Generate a `*.vue` shim.
*
* We recommend instead letting the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
* generate accurate types for your components.
*
* Note that you may wish to set this to `true` if you are using other libraries, such as ESLint,
* that are unable to understand the type of `.vue` files.
*/
shim: false
}
});
const vite = defineResolvers({
/**
* Configuration that will be passed directly to Vite.
*
* @see [Vite configuration docs](https://vite.dev/config) for more information.
* Please note that not all vite options are supported in Nuxt.
* @type {typeof import('../src/types/config').ViteConfig & { $client?: typeof import('../src/types/config').ViteConfig, $server?: typeof import('../src/types/config').ViteConfig }}
*/
vite: {
root: {
$resolve: async (val, get) => typeof val === "string" ? val : await get("srcDir")
},
mode: {
$resolve: async (val, get) => typeof val === "string" ? val : await get("dev") ? "development" : "production"
},
define: {
$resolve: async (_val, get) => {
const [isDev, isDebug] = await Promise.all([get("dev"), get("debug")]);
return {
"__VUE_PROD_HYDRATION_MISMATCH_DETAILS__": Boolean(isDebug && (isDebug === true || isDebug.hydration)),
"process.dev": isDev,
"import.meta.dev": isDev,
"process.test": isTest,
"import.meta.test": isTest,
..._val && typeof _val === "object" ? _val : {}
};
}
},
resolve: {
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"]
},
publicDir: {
$resolve: (val) => {
if (val) {
consola.warn("Directly configuring the `vite.publicDir` option is not supported. Instead, set `dir.public`. You can read more in `https://nuxt.com/docs/api/nuxt-config#public`.");
}
return false;
}
},
vue: {
isProduction: {
$resolve: async (val, get) => typeof val === "boolean" ? val : !await get("dev")
},
template: {
compilerOptions: {
$resolve: async (val, get) => val ?? (await get("vue")).compilerOptions
},
transformAssetUrls: {
$resolve: async (val, get) => val ?? (await get("vue")).transformAssetUrls
}
},
script: {
hoistStatic: {
$resolve: async (val, get) => typeof val === "boolean" ? val : (await get("vue")).compilerOptions?.hoistStatic
}
},
features: {
propsDestructure: {
$resolve: async (val, get) => {
if (typeof val === "boolean") {
return val;
}
const vueOptions = await get("vue") || {};
return Boolean(
// @ts-expect-error TODO: remove in future: supporting a legacy schema
vueOptions.script?.propsDestructure ?? vueOptions.propsDestructure
);
}
}
}
},
vueJsx: {
$resolve: async (val, get) => {
return {
// TODO: investigate type divergence between types for @vue/compiler-core and @vue/babel-plugin-jsx
isCustomElement: (await get("vue")).compilerOptions?.isCustomElement,
...typeof val === "object" ? val : {}
};
}
},
optimizeDeps: {
esbuildOptions: {
$resolve: async (val, get) => defu$1(val && typeof val === "object" ? val : {}, await get("esbuild.options"))
},
exclude: {
$resolve: async (val, get) => [
...Array.isArray(val) ? val : [],
...(await get("build.transpile")).filter((i) => typeof i === "string"),
"vue-demi"
]
}
},
esbuild: {
$resolve: async (val, get) => {
return defu$1(val && typeof val === "object" ? val : {}, await get("esbuild.options"));
}
},
clearScreen: true,
build: {
assetsDir: {
$resolve: async (val, get) => typeof val === "string" ? val : (await get("app")).buildAssetsDir?.replace(/^\/+/, "")
},
emptyOutDir: false
},
server: {
fs: {
allow: {
$resolve: async (val, get) => {
const [buildDir, srcDir, rootDir, workspaceDir] = await Promise.all([get("buildDir"), get("srcDir"), get("rootDir"), get("workspaceDir")]);
return [.../* @__PURE__ */ new Set([
buildDir,
srcDir,
rootDir,
workspaceDir,
...Array.isArray(val) ? val : []
])];
}
}
}
},
cacheDir: {
$resolve: async (val, get) => typeof val === "string" ? val : resolve(await get("rootDir"), "node_modules/.cache/vite")
}
}
});
const webpack = defineResolvers({
webpack: {
/**
* Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them.
*
* Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options).
* @example
* ```js
* analyze: {
* analyzerMode: 'static'
* }
* ```
* @type {boolean | { enabled?: boolean } & typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options}
*/
analyze: {
$resolve: async (val, get) => {
const value = typeof val === "boolean" ? { enabled: val } : val && typeof val === "object" ? val : {};
return defu(value, await get("build.analyze"));
}
},
/**
* Enable the profiler in webpackbar.
*
* It is normally enabled by CLI argument `--profile`.
* @see [webpackbar](https://github.com/unjs/webpackbar#profile).
*/
profile: process.argv.includes("--profile"),
/**
* Enables Common CSS Extraction.
*
* Using [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) under the hood, your CSS will be extracted
* into separate files, usually one per component. This allows caching your CSS and
* JavaScript separately.
* @example
* ```js
* export default {
* webpack: {
* extractCSS: true,
* // or
* extractCSS: {
* ignoreOrder: true
* }
* }
* }
* ```
*
* If you want to extract all your CSS to a single file, there is a workaround for this.
* However, note that it is not recommended to extract everything into a single file.
* Extracting into multiple CSS files is better for caching and preload isolation. It
* can also improve page performance by downloading and resolving only those resources
* that are needed.
* @example
* ```js
* export default {
* webpack: {
* extractCSS: true,
* optimization: {
* splitChunks: {
* cacheGroups: {
* styles: {
* name: 'styles',
* test: /\.(css|vue)$/,
* chunks: 'all',
* enforce: true
* }
* }
* }
* }
* }
* }
* ```
* @type {boolean | typeof import('mini-css-extract-plugin').PluginOptions}
*/
extractCSS: true,
/**
* Enables CSS source map support (defaults to `true` in development).
*/
cssSourceMap: {
$resolve: async (val, get) => typeof val === "boolean" ? val : await get("dev")
},
/**
* The polyfill library to load to provide URL and URLSearchParams.
*
* Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)).
*/
serverURLPolyfill: "url",
/**
* Customize bundle filenames.
*
* To understand a bit more about the use of manifests, take a look at [webpack documentation](https://webpack.js.org/guides/code-splitting/).
* @note Be careful when using non-hashed based filenames in production
* as most browsers will cache the asset and not detect the changes on first load.
*
* This example changes fancy chunk names to numerical ids:
* @example
* ```js
* filenames: {
* chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js')
* }
* ```
* @type {
* Record<
* string,
* string |
* ((
* ctx: {
* nuxt: import('../src/types/nuxt').Nuxt,
* options: import('../src/types/nuxt').Nuxt['options'],
* name: string,
* isDev: boolean,
* isServer: boolean,
* isClient: boolean,
* alias: { [index: string]: string | false | string[] },
* transpile: RegExp[]
* }) => string)
* >
* }
*/
filenames: {
app: ({ isDev }) => isDev ? "[name].js" : "[contenthash:7].js",
chunk: ({ isDev }) => isDev ? "[name].js" : "[contenthash:7].js",
css: ({ isDev }) => isDev ? "[name].css" : "css/[contenthash:7].css",
img: ({ isDev }) => isDev ? "[path][name].[ext]" : "img/[name].[contenthash:7].[ext]",
font: ({ isDev }) => isDev ? "[path][name].[ext]" : "fonts/[name].[contenthash:7].[ext]",
video: ({ isDev }) => isDev ? "[path][name].[ext]" : "videos/[name].[contenthash:7].[ext]"
},
/**
* Customize the options of Nuxt's integrated webpack loaders.
*/
loaders: {
$resolve: async (val, get) => {
const loaders = val && typeof val === "object" ? val : {};
const styleLoaders = [
"css",
"cssModules",
"less",
"sass",
"scss",
"stylus",
"vueStyle"
];
for (const name of styleLoaders) {
const loader = loaders[name];
if (loader && loader.sourceMap === void 0) {
loader.sourceMap = Boolean(
// @ts-expect-error TODO: remove legacay configuration
await get("build.cssSourceMap")
);
}
}
return loaders;
},
/**
* @see [esbuild loader](https://github.com/esbuild-kit/esbuild-loader)
* @type {Omit<typeof import('esbuild-loader')['LoaderOptions'], 'loader'>}
*/
esbuild: {
$resolve: async (val, get) => {
return defu(val && typeof val === "object" ? val : {}, await get("esbuild.options"));
}
},
/**
* @see [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options)
* @default
* ```ts
* { esModule: false }
* ```
*/
file: { esModule: false, limit: 1e3 },
/**
* @see [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options)
* @default
* ```ts
* { esModule: false }
* ```
*/
fontUrl: { esModule: false, limit: 1e3 },
/**
* @see [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options)
* @default
* ```ts
* { esModule: false }
* ```
*/
imgUrl: { esModule: false, limit: 1e3 },
/**
* @see [`pug` options](https://pugjs.org/api/reference.html#options)
* @type {typeof import('pug')['Options']}
*/
pugPlain: {},
/**
* See [vue-loader](https://github.com/vuejs/vue-loader) for available options.
* @type {Partial<typeof import('vue-loader')['VueLoaderOptions']>}
*/
vue: {
transformAssetUrls: {
$resolve: async (val, get) => val ?? await get("vue.transformAssetUrls")
},
compilerOptions: {
$resolve: async (val, get) => val ?? await get("vue.compilerOptions")
},
propsDestructure: {
$resolve: async (val, get) => Boolean(val ?? await get("vue.propsDestructure"))
}
},
/**
* See [css-loader](https://github.com/webpack-contrib/css-loader) for available options.
*/
css: {
importLoaders: 0,
/**
* @type {boolean | { filter: (url: string, resourcePath: string) => boolean }}
*/
url: {
filter: (url, _resourcePath) => url[0] !== "/"
},
esModule: false
},
/**
* See [css-loader](https://github.com/webpack-contrib/css-loader) for available options.
*/
cssModules: {
importLoaders: 0,
/**
* @type {boolean | { filter: (url: string, resourcePath: string) => boolean }}
*/
url: {
filter: (url, _resourcePath) => url[0] !== "/"
},
esModule: false,
modules: {
localIdentName: "[local]_[hash:base64:5]"
}
},
/**
* @see [`less-loader` Options](https://github.com/webpack-contrib/less-loader#options)
*/
less: {},
/**
* @see [`sass-loader` Options](https://github.com/webpack-contrib/sass-loader#options)
* @default
* ```ts
* {
* sassOptions: {
* indentedSyntax: true
* }
* }
* ```
*/
sass: {
sassOptions: {
indentedSyntax: true
}
},
/**
* @see [`sass-loader` Options](https://github.com/webpack-contrib/sass-loader#options)
*/
scss: {},
/**
* @see [`stylus-loader` Options](https://github.com/webpack-contrib/stylus-loader#options)
*/
stylus: {},
vueStyle: {}
},
/**
* Add webpack plugins.
* @example
* ```js
* import webpack from 'webpack'
* import { version } from './package.json'
* // ...
* plugins: [
* new webpack.DefinePlugin({
* 'process.VERSION': version
* })
* ]
* ```
*/
plugins: [],
/**
* Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle.
*/
aggressiveCodeRemoval: false,
/**
* OptimizeCSSAssets plugin options.
*
* Defaults to true when `extractCSS` is enabled.
* @see [css-minimizer-webpack-plugin documentation](https://github.com/webpack-contrib/css-minimizer-webpack-plugin).
* @type {false | typeof import('css-minimizer-webpack-plugin').BasePluginOptions & typeof import('css-minimizer-webpack-plugin').DefinedDefaultMinimizerAndOptions<{}>}
*/
optimizeCSS: {
$resolve: async (val, get) => {
if (val === false || val && typeof val === "object") {
return val;
}
const extractCSS = await get("build.extractCSS");
return extractCSS ? {} : false;
}
},
/**
* Configure [webpack optimization](https://webpack.js.org/configuration/optimization/).
* @type {false | typeof import('webpack').Configuration['optimization']}
*/
optimization: {
runtimeChunk: "single",
/** Set minimize to `false` to disable all minimizers. (It is disabled in development by default). */
minimize: {
$resolve: async (val, get) => typeof val === "boolean" ? val : !await get("dev")
},
/** You can set minimizer to a customized array of plugins. */
minimizer: void 0,
splitChunks: {
chunks: "all",
automaticNameDelimiter: "/",
cacheGroups: {}
}
},
/**
* Customize PostCSS Loader.
* same options as [`postcss-loader` options](https://github.com/webpack-contrib/postcss-loader#options)
* @type {{ execute?: boolean, postcssOptions: typeof import('postcss').ProcessOptions & { plugins: Record<string, unknown> & { autoprefixer?: typeof import('autoprefixer').Options; cssnano?: typeof import('cssnano').Options } }, sourceMap?: boolean, implementation?: any }}
*/
postcss: {
postcssOptions: {
plugins: {
$resolve: async (val, get) => val && typeof val === "object" ? val : await get("postcss.plugins")
}
}
},
/**
* See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options.
* @type {typeof import('webpack-dev-middleware').Options<typeof import('http').IncomingMessage, typeof import('http').ServerResponse>}
*/
devMiddleware: {
stats: "none"
},
/**
* See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options.
* @type {typeof import('webpack-hot-middleware').MiddlewareOptions & { client?: typeof import('webpack-hot-middleware').ClientOptions }}
*/
hotMiddleware: {},
/**
* Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin).
*/
friendlyErrors: true,
/**
* Filters to hide build warnings.
* @type {Array<(warn: typeof import('webpack').WebpackError) => boolean>}
*/
warningIgnoreFilters: [],
/**
* Configure [webpack experiments](https://webpack.js.org/configuration/experiments/)
* @type {false | typeof import('webpack').Configuration['experiments']}
*/
experiments: {}
}
});
const index = {
...adhoc,
...app,
...build,
...common,
...dev,
...experimental,
...generate,
...internal,
...nitro,
...postcss,
...router,
...typescript,
...esbuild,
...oxc,
...vite,
...webpack
};
export { index as NuxtConfigSchema };