import { join, resolve } from 'pathe'
import { isDevelopment } from 'std-env'
import createRequire from 'create-require'
import { pascalCase } from 'scule'
import jiti from 'jiti'
import defu from 'defu'
import { findWorkspaceDir } from 'pkg-types'
import { RuntimeConfig } from '../types/config'
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* 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:`, `gitlab:`, `bitbucket:` or `https://` to extend from a remote git repository.
*
* @type {string|string[]}
*
* @version 3
*/
extends: null,
/**
* 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}
*
* @version 3
*/
theme: null,
/**
* 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.
* @version 2
* @version 3
*/
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.
* @version 3
*/
workspaceDir: {
$resolve: async (val, get) => val ? resolve(await get('rootDir'), val) : await findWorkspaceDir(await get('rootDir')).catch(() => get('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/
* ------| static/
* ------| store/
* ------| server/
* ```
* @version 2
* @version 3
*/
srcDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || '.')
},
/**
* 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`.
*
* @version 3
*/
serverDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || resolve(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'
* }
* ```
* @version 2
* @version 3
*/
buildDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt')
},
/**
* Whether Nuxt is running in development mode.
*
* Normally, you should not need to set this.
* @version 2
* @version 3
*/
dev: Boolean(isDevelopment),
/**
* Whether your app is being unit tested.
* @version 2
*/
test: Boolean(isDevelopment),
/**
* Set to `true` to enable debug mode.
*
* By default, it's only enabled in development mode.
* @version 2
*/
debug: {
$resolve: async (val, get) => val ?? await get('dev')
},
/**
* The `env` property defines environment variables that should be available
* throughout your app (server- and client-side). They can be assigned using
* server-side environment variables.
*
* @note Nuxt uses webpack's `definePlugin` to define these environment variables.
* This means that the actual `process` or `process.env` from Node.js is neither
* available nor defined. Each of the `env` properties defined here is individually
* mapped to `process.env.xxxx` and converted during compilation.
*
* @note Environment variables starting with `NUXT_ENV_` are automatically injected
* into the process environment.
*
* @version 2
*/
env: {
$default: {},
$resolve: (val) => {
val = { ...val }
for (const key in process.env) {
if (key.startsWith('NUXT_ENV_')) {
val[key] = process.env[key]
}
}
return val
}
},
/**
* Set the method Nuxt uses to require modules, such as loading `nuxt.config`, server
* middleware, and so on - defaulting to `jiti` (which has support for TypeScript and ESM syntax).
*
* @see [jiti](https://github.com/unjs/jiti)
* @type {'jiti' | 'native' | ((p: string | { filename: string }) => NodeRequire)}
* @version 2
*/
createRequire: {
$resolve: (val: any) => {
val = process.env.NUXT_CREATE_REQUIRE || val ||
// @ts-expect-error global type
(typeof globalThis.jest !== 'undefined' ? 'native' : 'jiti')
if (val === 'jiti') {
return (p: string | { filename: string }) => jiti(typeof p === 'string' ? p : p.filename, { esmResolve: true })
}
if (val === 'native') {
return (p: string | { filename: string }) => createRequire(typeof p === 'string' ? p : p.filename)
}
return val
}
},
/**
* Whether your Nuxt app should be built to be served by the Nuxt server (`server`)
* or as static HTML files suitable for a CDN or other static file server (`static`).
*
* This is unrelated to `ssr`.
* @type {'server' | 'static'}
* @version 2
*/
target: {
$resolve: val => ['server', 'static'].includes(val) ? val : 'server'
},
/**
* Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time.
* If set to `false` and combined with `static` target, generated pages will simply display
* a loading screen with no content.
* @version 2
* @version 3
*/
ssr: {
$resolve: (val) => val ?? true,
},
/**
* @deprecated use `ssr` option
*/
mode: {
$resolve: async (val, get) => val || ((await get('ssr')) ? 'spa' : 'universal'),
$schema: { deprecated: '`mode` option is deprecated' }
},
/**
* Whether to produce a separate modern build targeting browsers that support ES modules.
*
* Set to `'server'` to enable server mode, where the Nuxt server checks
* browser version based on the user agent and serves the correct bundle.
*
* Set to `'client'` to serve both the modern bundle with `
*
*
* ```
*
* @type {Record}
* @version 2
* @version 3
*/
alias: {
$resolve: async (val, get) => ({
'~~': await get('rootDir'),
'@@': await get('rootDir'),
'~': await get('srcDir'),
'@': await get('srcDir'),
[await get('dir.assets')]: join(await get('srcDir'), await get('dir.assets')),
[await get('dir.public')]: join(await get('srcDir'), await get('dir.public')),
...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
* }
* ```
* @version 2
* @version 3
*/
ignoreOptions: undefined,
/**
* Any file in `pages/`, `layouts/`, `middleware/` or `store/` will be ignored during
* building if its filename starts with the prefix specified by `ignorePrefix`.
* @version 2
* @version 3
*/
ignorePrefix: '-',
/**
* More customizable than `ignorePrefix`: all files matching glob patterns specified
* inside the `ignore` array will be ignored in building.
* @version 2
* @version 3
*/
ignore: {
$resolve: async (val, get) => [
'**/*.stories.{js,ts,jsx,tsx}', // ignore storybook files
'**/*.{spec,test}.{js,ts,jsx,tsx}', // ignore tests
'.output',
await get('ignorePrefix') && `**/${await get('ignorePrefix')}*.*`
].concat(val).filter(Boolean)
},
/**
* The watch property lets you watch custom files for restarting the server.
*
* `chokidar` is used to set up the watchers. To learn more about its pattern
* options, see chokidar documentation.
*
* @see [chokidar](https://github.com/paulmillr/chokidar#api)
*
* @example
* ```js
* watch: ['~/custom/*.js']
* ```
* @type {string[]}
* @version 2
*/
watch: {
$resolve: async (val, get) => {
const rootDir = await get('rootDir')
return Array.from(new Set([].concat(val, await get('_nuxtConfigFiles'))
.filter(Boolean).map(p => resolve(rootDir, p))
))
}
},
/**
* The watchers property lets you overwrite watchers configuration in your `nuxt.config`.
* @version 2
* @version 3
*/
watchers: {
/** An array of event types, which, when received, will cause the watcher to restart. */
rewatchOnRawEvents: undefined,
/**
* `watchOptions` to pass directly to webpack.
*
* @see [webpack@4 watch options](https://v4.webpack.js.org/configuration/watch/#watchoptions).
* */
webpack: {
aggregateTimeout: 1000
},
/**
* Options to pass directly to `chokidar`.
*
* @see [chokidar](https://github.com/paulmillr/chokidar#api)
*/
chokidar: {
ignoreInitial: true
}
},
/**
* Your preferred code editor to launch when debugging.
*
* @see [documentation](https://github.com/yyx990803/launch-editor#supported-editors)
* @type {string}
* @version 2
*/
editor: undefined,
/**
* 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'node:fs'
* 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')
* }
* }
* }
* }
* ```
* @version 2
* @version 3
* @type {typeof import('../src/types/hooks').NuxtHooks}
*/
hooks: null,
/**
* 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}
* @version 3
*/
runtimeConfig: {
$resolve: async (val: RuntimeConfig, get) => defu(val, {
...await get('publicRuntimeConfig'),
...await get('privateRuntimeConfig'),
public: await get('publicRuntimeConfig'),
app: {
baseURL: (await get('app')).baseURL,
buildAssetsDir: (await get('app')).buildAssetsDir,
cdnURL: (await get('app')).cdnURL,
}
})
},
/**
* @type {typeof import('../src/types/config').PrivateRuntimeConfig}
* @version 2
* @version 3
* @deprecated Use `runtimeConfig` option.
*/
privateRuntimeConfig: {},
/**
* @type {typeof import('../src/types/config').PublicRuntimeConfig}
* @version 2
* @version 3
* @deprecated Use `runtimeConfig` option with `public` key (`runtimeConfig.public.*`).
*/
publicRuntimeConfig: {},
/**
* 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}
* @version 3
*/
appConfig: {},
})