refactor(nuxt)!: cleanup schema and split nuxt 2 types (#8487)

This commit is contained in:
pooya parsa 2022-10-27 12:36:37 +02:00 committed by GitHub
parent 24b06309ec
commit 265db50515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 566 additions and 2550 deletions

View File

@ -74,7 +74,6 @@ description: Nuxt Kit provides composable utilities to help interacting with Nux
[source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/nitro.ts) [source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/nitro.ts)
- ~~`addServerMiddleware(serverMiddleware)`~~
- `addServerHandler (handler)` - `addServerHandler (handler)`
- `addDevServerHandler (handler)` - `addDevServerHandler (handler)`
- `useNitro()` (only usable after `ready` hook) - `useNitro()` (only usable after `ready` hook)

View File

@ -13,13 +13,13 @@ export function addLayout (this: any, template: NuxtTemplate, name?: string) {
if (isNuxt2(nuxt)) { if (isNuxt2(nuxt)) {
// Nuxt 2 adds layouts in options // Nuxt 2 adds layouts in options
const layout = nuxt.options.layouts[layoutName] const layout = (nuxt.options as any).layouts[layoutName]
if (layout) { if (layout) {
return logger.warn( return logger.warn(
`Not overriding \`${layoutName}\` (provided by \`${layout}\`) with \`${src || filename}\`.` `Not overriding \`${layoutName}\` (provided by \`${layout}\`) with \`${src || filename}\`.`
) )
} }
nuxt.options.layouts[layoutName] = `./${filename}` (nuxt.options as any).layouts[layoutName] = `./${filename}`
if (name === 'error') { if (name === 'error') {
this.addErrorLayout(filename) this.addErrorLayout(filename)
} }

View File

@ -34,11 +34,12 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
} }
// Filter layers // Filter layers
nuxtConfig._layers = layers.filter(layer => layer.configFile && !layer.configFile.endsWith('.nuxtrc')) const _layers = layers.filter(layer => layer.configFile && !layer.configFile.endsWith('.nuxtrc'))
;(nuxtConfig as any)._layers = _layers
// Ensure at least one layer remains (without nuxt.config) // Ensure at least one layer remains (without nuxt.config)
if (!nuxtConfig._layers.length) { if (!_layers.length) {
nuxtConfig._layers.push({ _layers.push({
cwd, cwd,
config: { config: {
rootDir: cwd, rootDir: cwd,

View File

@ -3,7 +3,6 @@ import type { Nuxt, ModuleContainer } from '@nuxt/schema'
import { chainFn } from '../internal/task' import { chainFn } from '../internal/task'
import { addTemplate } from '../template' import { addTemplate } from '../template'
import { addLayout } from '../layout' import { addLayout } from '../layout'
import { addServerMiddleware } from '../nitro'
import { isNuxt2 } from '../compatibility' import { isNuxt2 } from '../compatibility'
import { addPluginTemplate } from '../plugin' import { addPluginTemplate } from '../plugin'
import { useNuxt } from '../context' import { useNuxt } from '../context'
@ -44,7 +43,8 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
requireModule, requireModule,
addModule: requireModule, addModule: requireModule,
addServerMiddleware, // TODO
addServerMiddleware: () => { },
addTemplate (template) { addTemplate (template) {
if (typeof template === 'string') { if (typeof template === 'string') {
@ -66,7 +66,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
addErrorLayout (dst) { addErrorLayout (dst) {
const relativeBuildDir = relative(nuxt.options.rootDir, nuxt.options.buildDir) const relativeBuildDir = relative(nuxt.options.rootDir, nuxt.options.buildDir)
nuxt.options.ErrorPage = `~/${relativeBuildDir}/${dst}` ;(nuxt as any).options.ErrorPage = `~/${relativeBuildDir}/${dst}`
}, },
extendBuild (fn) { extendBuild (fn) {
@ -80,7 +80,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
extendRoutes (fn) { extendRoutes (fn) {
if (isNuxt2(nuxt)) { if (isNuxt2(nuxt)) {
nuxt.options.router.extendRoutes = chainFn(nuxt.options.router.extendRoutes, fn) (nuxt.options.router as any).extendRoutes = chainFn((nuxt.options.router as any).extendRoutes, fn)
} else { } else {
nuxt.hook('pages:extend', async (pages, ...args) => { nuxt.hook('pages:extend', async (pages, ...args) => {
const maybeRoutes = await fn(pages, ...args) const maybeRoutes = await fn(pages, ...args)

View File

@ -109,12 +109,14 @@ function nuxt2Shims (nuxt: Nuxt) {
// Support virtual templates with getContents() by writing them to .nuxt directory // Support virtual templates with getContents() by writing them to .nuxt directory
let virtualTemplates: ResolvedNuxtTemplate[] let virtualTemplates: ResolvedNuxtTemplate[]
// @ts-ignore Nuxt 2 hook
nuxt.hook('builder:prepared', (_builder, buildOptions) => { nuxt.hook('builder:prepared', (_builder, buildOptions) => {
virtualTemplates = buildOptions.templates.filter(t => t.getContents) virtualTemplates = buildOptions.templates.filter((t: any) => t.getContents)
for (const template of virtualTemplates) { for (const template of virtualTemplates) {
buildOptions.templates.splice(buildOptions.templates.indexOf(template), 1) buildOptions.templates.splice(buildOptions.templates.indexOf(template), 1)
} }
}) })
// @ts-ignore Nuxt 2 hook
nuxt.hook('build:templates', async (templates) => { nuxt.hook('build:templates', async (templates) => {
const context = { const context = {
nuxt, nuxt,

View File

@ -1,14 +1,6 @@
import type { NodeMiddleware } from 'h3'
import type { NitroEventHandler, NitroDevEventHandler, Nitro } from 'nitropack' import type { NitroEventHandler, NitroDevEventHandler, Nitro } from 'nitropack'
import { useNuxt } from './context' import { useNuxt } from './context'
export interface LegacyServerMiddleware {
route?: string,
path?: string,
handle?: NodeMiddleware | string
handler: NodeMiddleware | string
}
/** /**
* normalize handler object * normalize handler object
* *
@ -22,15 +14,6 @@ function normalizeHandlerMethod (handler: NitroEventHandler) {
} }
} }
/**
* Adds a new server middleware to the end of the server middleware array.
*
* @deprecated Use addServerHandler instead
*/
export function addServerMiddleware (middleware: LegacyServerMiddleware) {
useNuxt().options.serverMiddleware.push(middleware)
}
/** /**
* Adds a nitro server handler * Adds a nitro server handler
* *

View File

@ -5,6 +5,7 @@ import { isNuxt2 } from './compatibility'
export function extendPages (cb: NuxtHooks['pages:extend']) { export function extendPages (cb: NuxtHooks['pages:extend']) {
const nuxt = useNuxt() const nuxt = useNuxt()
if (isNuxt2(nuxt)) { if (isNuxt2(nuxt)) {
// @ts-expect-error
nuxt.hook('build:extendRoutes', cb) nuxt.hook('build:extendRoutes', cb)
} else { } else {
nuxt.hook('pages:extend', cb) nuxt.hook('pages:extend', cb)

View File

@ -92,10 +92,10 @@ export default defineNuxtCommand({
await currentNuxt.hooks.callHook('listen', listener.server, listener) await currentNuxt.hooks.callHook('listen', listener.server, listener)
const address = listener.server.address() as AddressInfo const address = listener.server.address() as AddressInfo
currentNuxt.options.server.url = listener.url currentNuxt.options.devServer.url = listener.url
currentNuxt.options.server.port = address.port currentNuxt.options.devServer.port = address.port
currentNuxt.options.server.host = address.address currentNuxt.options.devServer.host = address.address
currentNuxt.options.server.https = listener.https currentNuxt.options.devServer.https = listener.https
await Promise.all([ await Promise.all([
writeTypes(currentNuxt).catch(console.error), writeTypes(currentNuxt).catch(console.error),

View File

@ -100,6 +100,7 @@ export const writeTypes = async (nuxt: Nuxt) => {
// This is needed for Nuxt 2 which clears the build directory again before building // This is needed for Nuxt 2 which clears the build directory again before building
// https://github.com/nuxt/nuxt.js/blob/dev/packages/builder/src/builder.js#L144 // https://github.com/nuxt/nuxt.js/blob/dev/packages/builder/src/builder.js#L144
// @ts-expect-error
nuxt.hook('builder:prepared', writeFile) nuxt.hook('builder:prepared', writeFile)
await writeFile() await writeFile()

View File

@ -30,10 +30,10 @@ export async function build (nuxt: Nuxt) {
}) })
} }
await nuxt.callHook('build:before', { nuxt }, nuxt.options.build) await nuxt.callHook('build:before')
if (!nuxt.options._prepare) { if (!nuxt.options._prepare) {
await bundle(nuxt) await bundle(nuxt)
await nuxt.callHook('build:done', { nuxt }) await nuxt.callHook('build:done')
} }
if (!nuxt.options.dev) { if (!nuxt.options.dev) {

View File

@ -1,7 +1,7 @@
import { existsSync, promises as fsp } from 'node:fs' import { existsSync, promises as fsp } from 'node:fs'
import { resolve, join } from 'pathe' import { resolve, join } from 'pathe'
import { createNitro, createDevServer, build, prepare, copyPublicAssets, writeTypes, scanHandlers, prerender, Nitro } from 'nitropack' import { createNitro, createDevServer, build, prepare, copyPublicAssets, writeTypes, scanHandlers, prerender, Nitro } from 'nitropack'
import type { NitroEventHandler, NitroDevEventHandler, NitroConfig } from 'nitropack' import type { NitroConfig } from 'nitropack'
import type { Nuxt } from '@nuxt/schema' import type { Nuxt } from '@nuxt/schema'
import { resolvePath } from '@nuxt/kit' import { resolvePath } from '@nuxt/kit'
import defu from 'defu' import defu from 'defu'
@ -12,9 +12,6 @@ import { distDir } from '../dirs'
import { ImportProtectionPlugin } from './plugins/import-protection' import { ImportProtectionPlugin } from './plugins/import-protection'
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// Resolve handlers
const { handlers, devHandlers } = await resolveHandlers(nuxt)
// Resolve config // Resolve config
const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig
const nitroConfig: NitroConfig = defu(_nitroConfig, <NitroConfig>{ const nitroConfig: NitroConfig = defu(_nitroConfig, <NitroConfig>{
@ -33,7 +30,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
renderer: resolve(distDir, 'core/runtime/nitro/renderer'), renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
errorHandler: resolve(distDir, 'core/runtime/nitro/error'), errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
nodeModulesDirs: nuxt.options.modulesDir, nodeModulesDirs: nuxt.options.modulesDir,
handlers, handlers: nuxt.options.serverHandlers,
devHandlers: [], devHandlers: [],
baseURL: nuxt.options.app.baseURL, baseURL: nuxt.options.app.baseURL,
virtual: {}, virtual: {},
@ -58,7 +55,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
.map(dir => ({ dir })) .map(dir => ({ dir }))
], ],
prerender: { prerender: {
crawlLinks: nuxt.options._generate ? nuxt.options.generate.crawler : false, crawlLinks: nuxt.options._generate ?? undefined,
routes: ([] as string[]) routes: ([] as string[])
.concat(nuxt.options.generate.routes) .concat(nuxt.options.generate.routes)
.concat(nuxt.options._generate ? [nuxt.options.ssr ? '/' : '/index.html', '/200.html', '/404.html'] : []) .concat(nuxt.options._generate ? [nuxt.options.ssr ? '/' : '/index.html', '/200.html', '/404.html'] : [])
@ -155,7 +152,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// Setup handlers // Setup handlers
const devMiddlewareHandler = dynamicEventHandler() const devMiddlewareHandler = dynamicEventHandler()
nitro.options.devHandlers.unshift({ handler: devMiddlewareHandler }) nitro.options.devHandlers.unshift({ handler: devMiddlewareHandler })
nitro.options.devHandlers.push(...devHandlers) nitro.options.devHandlers.push(...nuxt.options.devServerHandlers)
nitro.options.handlers.unshift({ nitro.options.handlers.unshift({
route: '/__nuxt_error', route: '/__nuxt_error',
lazy: true, lazy: true,
@ -185,7 +182,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
} else { } else {
const distDir = resolve(nuxt.options.rootDir, 'dist') const distDir = resolve(nuxt.options.rootDir, 'dist')
if (!existsSync(distDir)) { if (!existsSync(distDir)) {
await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => {}) await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => { })
} }
} }
} }
@ -193,53 +190,14 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// nuxt dev // nuxt dev
if (nuxt.options.dev) { if (nuxt.options.dev) {
nuxt.hook('build:compile', ({ compiler }) => { nuxt.hook('webpack:compile', ({ compiler }) => { compiler.outputFileSystem = { ...fsExtra, join } as any })
compiler.outputFileSystem = { ...fsExtra, join } as any nuxt.hook('webpack:compiled', () => { nuxt.server.reload() })
}) nuxt.hook('vite:compiled', () => { nuxt.server.reload() })
nuxt.hook('server:devHandler', (h) => { devMiddlewareHandler.set(h) }) nuxt.hook('server:devHandler', (h) => { devMiddlewareHandler.set(h) })
nuxt.server = createDevServer(nitro) nuxt.server = createDevServer(nitro)
nuxt.hook('build:resources', () => {
nuxt.server.reload()
})
const waitUntilCompile = new Promise<void>(resolve => nitro.hooks.hook('compiled', () => resolve())) const waitUntilCompile = new Promise<void>(resolve => nitro.hooks.hook('compiled', () => resolve()))
nuxt.hook('build:done', () => waitUntilCompile) nuxt.hook('build:done', () => waitUntilCompile)
} }
} }
async function resolveHandlers (nuxt: Nuxt) {
const handlers: NitroEventHandler[] = [...nuxt.options.serverHandlers]
const devHandlers: NitroDevEventHandler[] = [...nuxt.options.devServerHandlers]
// Map legacy serverMiddleware to handlers
for (let m of nuxt.options.serverMiddleware) {
if (typeof m === 'string' || typeof m === 'function' /* legacy middleware */) { m = { handler: m } }
const route = m.path || m.route || '/'
const handler = m.handler || m.handle
if (typeof handler !== 'string' || typeof route !== 'string') {
devHandlers.push({ route, handler })
} else {
delete m.handler
delete m.path
handlers.push({
...m,
route,
middleware: true,
handler: await resolvePath(handler)
})
}
}
return {
handlers,
devHandlers
}
}
declare module 'nitropack' {
interface NitroRouteConfig {
ssr?: boolean
}
interface NitroRouteOptions {
ssr?: boolean
}
}

View File

@ -1,6 +1,6 @@
import { join, normalize, resolve } from 'pathe' import { join, normalize, resolve } from 'pathe'
import { createHooks, createDebugger } from 'hookable' import { createHooks, createDebugger } from 'hookable'
import type { Nuxt, NuxtOptions, NuxtConfig, ModuleContainer, NuxtHooks } from '@nuxt/schema' import type { Nuxt, NuxtOptions, NuxtConfig, NuxtHooks } from '@nuxt/schema'
import { loadNuxtConfig, LoadNuxtOptions, nuxtCtx, installModule, addComponent, addVitePlugin, addWebpackPlugin, tryResolveModule, addPlugin } from '@nuxt/kit' import { loadNuxtConfig, LoadNuxtOptions, nuxtCtx, installModule, addComponent, addVitePlugin, addWebpackPlugin, tryResolveModule, addPlugin } from '@nuxt/kit'
// Temporary until finding better placement // Temporary until finding better placement
/* eslint-disable import/no-restricted-paths */ /* eslint-disable import/no-restricted-paths */
@ -114,7 +114,7 @@ async function initNuxt (nuxt: Nuxt) {
) )
// Init user modules // Init user modules
await nuxt.callHook('modules:before', { nuxt } as ModuleContainer) await nuxt.callHook('modules:before')
const modulesToInstall = [ const modulesToInstall = [
...nuxt.options.buildModules, ...nuxt.options.buildModules,
...nuxt.options.modules, ...nuxt.options.modules,
@ -212,7 +212,7 @@ async function initNuxt (nuxt: Nuxt) {
} }
} }
await nuxt.callHook('modules:done', { nuxt } as ModuleContainer) await nuxt.callHook('modules:done')
// Normalize windows transpile paths added by modules // Normalize windows transpile paths added by modules
nuxt.options.build.transpile = nuxt.options.build.transpile.map(t => typeof t === 'string' ? normalize(t) : t) nuxt.options.build.transpile = nuxt.options.build.transpile.map(t => typeof t === 'string' ? normalize(t) : t)

View File

@ -4,3 +4,12 @@ export * from './dist/index'
declare global { declare global {
const defineNuxtConfig: typeof import('nuxt/config')['defineNuxtConfig'] const defineNuxtConfig: typeof import('nuxt/config')['defineNuxtConfig']
} }
declare module 'nitropack' {
interface NitroRouteConfig {
ssr?: boolean
}
interface NitroRouteRules {
ssr?: boolean
}
}

View File

@ -15,7 +15,7 @@ export default defineBuildConfig({
} }
} }
}, },
'src/index' 'src/index',
], ],
externals: [ externals: [
// Type imports // Type imports

View File

@ -1,479 +0,0 @@
import { resolve, join } from 'pathe'
import { existsSync, readdirSync } from 'node:fs'
import defu from 'defu'
import { defineUntypedSchema } from 'untyped'
import type { AppHeadMetaObject } from '../types/meta'
export default defineUntypedSchema({
/**
* Vue.js config
* @version 2
* @version 3
*/
vue: {
/**
* Properties that will be set directly on `Vue.config` for vue@2.
*
* @see [vue@2 Documentation](https://v2.vuejs.org/v2/api/#Global-Config)
* @type {typeof import('vue/types/vue').VueConfiguration}
* @version 2
*/
config: {
silent: {
$resolve: async (val, get) => val ?? !(await get('dev'))
},
performance: {
$resolve: async (val, get) => val ?? await get('dev')
},
},
/**
* Options for the Vue compiler that will be passed at build time.
* @see [documentation](https://vuejs.org/api/application.html#app-config-compileroptions)
* @type {typeof import('@vue/compiler-core').CompilerOptions}
* @version 3
*/
compilerOptions: {}
},
/**
* Nuxt App configuration.
* @version 2
* @version 3
*/
app: {
/**
* The base path of your Nuxt application.
*
* This can 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: async (val) => val || 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: async (val) => val || process.env.NUXT_APP_BUILD_ASSETS_DIR || '/_nuxt/',
},
/**
* The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set).
* @deprecated - use `buildAssetsDir` instead
* @version 2
*/
assetsPath: {
$resolve: async (val, get) => val ?? (await get('buildAssetsDir'))
},
/**
* An absolute URL to serve the public folder from (production-only).
*
* 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) => (await get('dev')) ? '' : (process.env.NUXT_APP_CDN_URL ?? 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 type="text/css">:root { color: red }</style>
* { children: ':root { color: red }', type: 'text/css' }
* ],
* noscript: [
* // <noscript>Javascript is required</noscript>
* { children: 'Javascript is required' }
* ]
* }
* }
* ```
* @type {typeof import('../src/types/config').NuxtAppConfig['head']}
* @version 3
*/
head: {
$resolve: async (val, get) => {
const resolved: Required<AppHeadMetaObject> = defu(val, await get('meta'), {
meta: [],
link: [],
style: [],
script: [],
noscript: []
})
// provides default charset and viewport if not set
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 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 https://vuejs.org/api/built-in-components.html#transition
* @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']}
*/
pageTransition: 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 https://vuejs.org/api/built-in-components.html#keepalive
* @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']}
*/
keepalive: false,
},
/**
* The path to an HTML template file for rendering Nuxt responses.
* Uses `<srcDir>/app.html` if it exists, or the Nuxt's default template if not.
*
* @example
* ```html
* <!DOCTYPE html>
* <html {{ HTML_ATTRS }}>
* <head {{ HEAD_ATTRS }}>
* {{ HEAD }}
* </head>
* <body {{ BODY_ATTRS }}>
* {{ APP }}
* </body>
* </html>
* ```
* @version 2
*/
appTemplatePath: {
$resolve: async (val, get) => {
if (val) {
return resolve(await get('srcDir'), val)
}
if (existsSync(join(await get('srcDir'), 'app.html'))) {
return join(await get('srcDir'), 'app.html')
}
return resolve(await get('buildDir'), 'views/app.template.html')
}
},
/**
* Enable or disable Vuex store.
*
* By default, it is enabled if there is a `store/` directory.
* @version 2
*/
store: {
$resolve: async (val, get) => val !== false &&
existsSync(join(await get('srcDir'), await get('dir.store'))) &&
readdirSync(join(await get('srcDir'), await get('dir.store')))
.find(filename => filename !== 'README.md' && filename[0] !== '.')
},
/**
* Options to pass directly to `vue-meta`.
*
* @see [documentation](https://vue-meta.nuxtjs.org/api/#plugin-options).
* @type {typeof import('vue-meta').VueMetaOptions}
* @version 2
*/
vueMeta: null,
/**
* Set default configuration for `<head>` on every page.
*
* @see [documentation](https://vue-meta.nuxtjs.org/api/#metainfo-properties) for specifics.
* @type {typeof import('vue-meta').MetaInfo}
* @version 2
*/
head: {
/** Each item in the array maps to a newly-created `<meta>` element, where object properties map to attributes. */
meta: [],
/** Each item in the array maps to a newly-created `<link>` element, where object properties map to attributes. */
link: [],
/** Each item in the array maps to a newly-created `<style>` element, where object properties map to attributes. */
style: [],
/** Each item in the array maps to a newly-created `<script>` element, where object properties map to attributes. */
script: []
},
/**
* @type {typeof import('../src/types/meta').AppHeadMetaObject}
* @version 3
* @deprecated - use `head` instead
*/
meta: {
meta: [],
link: [],
style: [],
script: []
},
/**
* Configuration for the Nuxt `fetch()` hook.
* @version 2
*/
fetch: {
/** Whether to enable `fetch()` on the server. */
server: true,
/** Whether to enable `fetch()` on the client. */
client: true
},
/**
* 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.
*
* @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)[]}
* @version 2
*/
plugins: [],
/**
* You may want to extend plugins or change their order. For this, you can pass
* a function using `extendPlugins`. It accepts an array of plugin objects and
* should return an array of plugin objects.
* @type {(plugins: Array<{ src: string, mode?: 'client' | 'server' }>) => Array<{ src: string, mode?: 'client' | 'server' }>}
* @version 2
*/
extendPlugins: null,
/**
* 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[]}
* @version 2
* @version 3
*/
css: {
$resolve: val => (val ?? []).map((c: any) => c.src || c)
},
/**
* An object where each key name maps to a path to a layout .vue file.
*
* Normally, there is no need to configure this directly.
* @type {Record<string, string>}
* @version 2
*/
layouts: {},
/**
* Set a custom error page layout.
*
* Normally, there is no need to configure this directly.
* @type {string}
* @version 2
*/
ErrorPage: null,
/**
* Configure the Nuxt loading progress bar component that's shown between
* routes. Set to `false` to disable. You can also customize it or create
* your own component.
* @version 2
*/
loading: {
/** CSS color of the progress bar. */
color: 'black',
/**
* CSS color of the progress bar when an error appended while rendering
* the route (if data or fetch sent back an error, for example).
*/
failedColor: 'red',
/** Height of the progress bar (used in the style property of the progress bar). */
height: '2px',
/**
* In ms, wait for the specified time before displaying the progress bar.
* Useful for preventing the bar from flashing.
*/
throttle: 200,
/**
* In ms, the maximum duration of the progress bar, Nuxt assumes that the
* route will be rendered before 5 seconds.
*/
duration: 5000,
/** Keep animating progress bar when loading takes longer than duration. */
continuous: false,
/** Set the direction of the progress bar from right to left. */
rtl: false,
/** Set to `false` to remove default progress bar styles (and add your own). */
css: true
},
/**
* Show a loading spinner while the page is loading (only when `ssr: false`).
*
* Set to `false` to disable. Alternatively, you can pass a string name or an object for more
* configuration. The name can refer to an indicator from [SpinKit](https://tobiasahlin.com/spinkit/)
* or a path to an HTML template of the indicator source code (in this case, all the
* other options will be passed to the template).
* @version 2
*/
loadingIndicator: {
$resolve: async (val, get) => {
val = typeof val === 'string' ? { name: val } : val
return defu(val, {
name: 'default',
color: await get('loading.color') || '#D3D3D3',
color2: '#F5F5F5',
background: (await get('manifest') && await get('manifest.theme_color')) || 'white',
dev: await get('dev'),
loading: await get('messages.loading')
})
}
},
/**
* Used to set the default properties of the page transitions.
*
* You can either pass a string (the transition name) or an object with properties to bind
* to the `<Transition>` component that will wrap your pages.
*
* @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html)
* @see [vue@3 documentation](https://vuejs.org/guide/built-ins/transition-group.html#enter-leave-transitions)
* @version 2
*/
pageTransition: {
$resolve: async (val, get) => {
val = typeof val === 'string' ? { name: val } : val
return defu(val, {
name: 'page',
mode: 'out-in',
appear: await get('render.ssr') === false || Boolean(val),
appearClass: 'appear',
appearActiveClass: 'appear-active',
appearToClass: 'appear-to'
})
}
},
/**
* Used to set the default properties of the layout transitions.
*
* You can either pass a string (the transition name) or an object with properties to bind
* to the `<Transition>` component that will wrap your layouts.
*
* @see [vue@2 documentation](https://v2.vuejs.org/v2/guide/transitions.html)
* @see [vue@3 documentation](https://vuejs.org/guide/built-ins/transition-group.html#enter-leave-transitions)
* @version 2
*/
layoutTransition: {
$resolve: val => {
val = typeof val === 'string' ? { name: val } : val
return defu(val, {
name: 'layout',
mode: 'out-in'
})
}
},
/**
* You can disable specific Nuxt features that you do not want.
* @version 2
*/
features: {
/** Set to false to disable Nuxt vuex integration */
store: true,
/** Set to false to disable layouts */
layouts: true,
/** Set to false to disable Nuxt integration with `vue-meta` and the `head` property */
meta: true,
/** Set to false to disable middleware */
middleware: true,
/** Set to false to disable transitions */
transitions: true,
/** Set to false to disable support for deprecated features and aliases */
deprecations: true,
/** Set to false to disable the Nuxt `validate()` hook */
validate: true,
/** Set to false to disable the Nuxt `asyncData()` hook */
useAsyncData: true,
/** Set to false to disable the Nuxt `fetch()` hook */
fetch: true,
/** Set to false to disable `$nuxt.isOnline` */
clientOnline: true,
/** Set to false to disable prefetching behavior in `<NuxtLink>` */
clientPrefetch: true,
/** Set to false to disable extra component aliases like `<NLink>` and `<NChild>` */
componentAliases: true,
/** Set to false to disable the `<ClientOnly>` component (see [docs](https://github.com/egoist/vue-client-only)) */
componentClientOnly: true
}
})

View File

@ -8,11 +8,8 @@ export default defineUntypedSchema({
* pages, layouts (and other components) without needing to explicitly import them. * pages, layouts (and other components) without needing to explicitly import them.
* *
* @default {{ dirs: [`~/components`] }} * @default {{ dirs: [`~/components`] }}
* @see [Nuxt 3](https://v3.nuxtjs.org/guide/directory-structure/components) and * @see https://v3.nuxtjs.org/guide/directory-structure/components
* [Nuxt 2](https://nuxtjs.org/docs/directory-structure/components/) documentation
* @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']} * @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']}
* @version 2
* @version 3
*/ */
components: { components: {
$resolve: (val) => { $resolve: (val) => {
@ -34,7 +31,6 @@ export default defineUntypedSchema({
* *
* @see [Nuxt 3 documentation](https://v3.nuxtjs.org/guide/directory-structure/composables) * @see [Nuxt 3 documentation](https://v3.nuxtjs.org/guide/directory-structure/composables)
* @type {typeof import('../src/types/imports').ImportsOptions} * @type {typeof import('../src/types/imports').ImportsOptions}
* @version 3
*/ */
imports: { imports: {
global: false, global: false,
@ -46,7 +42,6 @@ export default defineUntypedSchema({
* enabled if you have a `pages/` directory in your source folder. * enabled if you have a `pages/` directory in your source folder.
* *
* @type {boolean} * @type {boolean}
* @version 3
*/ */
pages: undefined, pages: undefined,
@ -56,7 +51,6 @@ export default defineUntypedSchema({
* @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. * @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information.
* *
* @type {boolean} * @type {boolean}
* @version 3
*/ */
telemetry: undefined telemetry: undefined
}) })

View File

@ -0,0 +1,196 @@
import { defineUntypedSchema } from 'untyped'
import defu from 'defu'
import type { AppHeadMetaObject } from '../types/meta'
export default defineUntypedSchema({
/**
* Vue.js config
*/
vue: {
/**
* Options for the Vue compiler that will be passed at build time.
* @see [documentation](https://vuejs.org/api/application.html#app-config-compileroptions)
* @type {typeof import('@vue/compiler-core').CompilerOptions}
*/
compilerOptions: {}
},
/**
* Nuxt App configuration.
*/
app: {
/**
* The base path of your Nuxt application.
*
* This can 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: async (val) => val || 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: async (val) => val || process.env.NUXT_APP_BUILD_ASSETS_DIR || '/_nuxt/',
},
/**
* An absolute URL to serve the public folder from (production-only).
*
* 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) => (await get('dev')) ? '' : (process.env.NUXT_APP_CDN_URL ?? 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 type="text/css">:root { color: red }</style>
* { children: ':root { color: red }', type: 'text/css' }
* ],
* noscript: [
* // <noscript>Javascript is required</noscript>
* { children: 'Javascript is required' }
* ]
* }
* }
* ```
* @type {typeof import('../src/types/config').NuxtAppConfig['head']}
*/
head: {
$resolve: async (val, get) => {
const resolved: Required<AppHeadMetaObject> = defu(val, await get('meta'), {
meta: [],
link: [],
style: [],
script: [],
noscript: []
})
// provides default charset and viewport if not set
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 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 https://vuejs.org/api/built-in-components.html#transition
* @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']}
*/
pageTransition: 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 https://vuejs.org/api/built-in-components.html#keepalive
* @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']}
*/
keepalive: false,
},
/**
* 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.
*
* @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 => (val ?? []).map((c: any) => c.src || c)
}
})

View File

@ -1,15 +1,12 @@
import { defineUntypedSchema } from 'untyped'
import defu from 'defu' import defu from 'defu'
import { join } from 'pathe' import { join } from 'pathe'
import { isCI, isTest } from 'std-env'
import { normalizeURL, withTrailingSlash } from 'ufo'
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** /**
* The builder to use for bundling the Vue part of your application. * The builder to use for bundling the Vue part of your application.
* *
* @type {'vite' | 'webpack' | { bundle: (nuxt: typeof import('../src/types/nuxt').Nuxt) => Promise<void> }} * @type {'vite' | 'webpack' | { bundle: (nuxt: typeof import('../src/types/nuxt').Nuxt) => Promise<void> }}
* @version 3
*/ */
builder: { builder: {
$resolve: async (val, get) => { $resolve: async (val, get) => {
@ -23,11 +20,11 @@ export default defineUntypedSchema({
return map[val] || val || (await get('vite') === false ? map.webpack : map.vite) return map[val] || val || (await get('vite') === false ? map.webpack : map.vite)
} }
}, },
/** /**
* Whether to generate sourcemaps. * Whether to generate sourcemaps.
* *
* @type {boolean | { server?: boolean, client?: boolean }} * @type {boolean | { server?: boolean, client?: boolean }}
* @version 3
*/ */
sourcemap: { sourcemap: {
$resolve: async (val, get) => { $resolve: async (val, get) => {
@ -40,445 +37,11 @@ export default defineUntypedSchema({
}) })
}, },
}, },
/** /**
* Shared build configuration. * Shared build configuration.
* @version 2
* @version 3
*/ */
build: { build: {
/**
* Suppresses most of the build output log.
*
* It is enabled by default when a CI or test environment is detected.
*
* @see [std-env](https://github.com/unjs/std-env)
* @version 2
* @version 3
*/
quiet: Boolean(isCI || isTest),
/**
* 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 | typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options | typeof import('rollup-plugin-visualizer').PluginVisualizerOptions}
*/
analyze: {
$resolve: async (val, get) => {
if (val !== true) {
return val ?? false
}
const rootDir = await get('rootDir')
return {
template: 'treemap',
projectRoot: rootDir,
filename: join(rootDir, '.nuxt/stats', '{name}.html')
}
}
},
/**
* Enable the profiler in webpackbar.
*
* It is normally enabled by CLI argument `--profile`.
*
* @see [webpackbar](https://github.com/unjs/webpackbar#profile)
* @version 2
*/
profile: process.argv.includes('--profile'),
/**
* Enables Common CSS Extraction using
* [Vue Server Renderer guidelines](https://ssr.vuejs.org/guide/css.html).
*
* Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, your CSS will be extracted
* into separate files, usually one per component. This allows caching your CSS and
* JavaScript separately and is worth trying if you have a lot of global or shared CSS.
*
* @example
* ```js
* export default {
* build: {
* 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 {
* build: {
* extractCSS: true,
* optimization: {
* splitChunks: {
* cacheGroups: {
* styles: {
* name: 'styles',
* test: /\.(css|vue)$/,
* chunks: 'all',
* enforce: true
* }
* }
* }
* }
* }
* }
* ```
* @version 2
*/
extractCSS: false,
/**
* Enables CSS source map support (defaults to true in development)
* @version 2
*/
cssSourceMap: {
$resolve: async (val, get) => val ?? (await get('sourcemap.client') || await get('sourcemap.server')) ?? await get('dev')
},
/**
* Creates special webpack bundle for SSR renderer. It is normally not necessary to change this value.
* @version 2
*/
ssr: undefined,
/**
* Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) when building app with webpack.
*
* @warning This is an unstable feature.
* @version 2
*/
parallel: {
$resolve: async (val, get) => await get('build.extractCSS') ? false : Boolean(val)
},
/**
* Enable caching for [`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#options)
* and [`cache-loader`](https://github.com/webpack-contrib/cache-loader#cache-loader).
*
* @warning This is an unstable feature.
* @version 2
*/
cache: false,
/**
* Inline server bundle dependencies.
*
* This mode bundles `node_modules` that are normally preserved as externals in the server build.
*
* @warning Runtime dependencies (modules, `nuxt.config`, server middleware and the static directory) are not bundled.
* This feature only disables use of [webpack-externals](https://webpack.js.org/configuration/externals/) for server-bundle.
*
* @note You can enable standalone bundling by passing `--standalone` via the command line.
*
* @see [context](https://github.com/nuxt/nuxt.js/pull/4661)
* @version 2
*/
standalone: false,
/**
* If you are uploading your dist files to a CDN, you can set the publicPath to your CDN.
*
* @note This is only applied in production.
*
* The value of this property at runtime will override the configuration of an app that
* has already been built.
*
* @example
* ```js
* build: {
* publicPath: process.env.PUBLIC_PATH || 'https://cdn.nuxtjs.org'
* }
* ```
* @version 2
*/
publicPath: {
$resolve: async (val, get) => val ? withTrailingSlash(normalizeURL(val)) : (await get('app').buildAssetsDir)
},
/**
* The polyfill library to load to provide URL and URLSearchParams.
*
* Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)).
* @version 2
*/
serverURLPolyfill: 'url',
/**
* Customize bundle filenames.
*
* To understand a bit more about the use of manifests, take a look at [this 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, ((arg: any) => string)>}
* @version 2
*/
filenames: {
app: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`,
chunk: ({ isDev, isModern }: any) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[contenthash:7]${isModern ? '.modern' : ''}.js`,
css: ({ isDev }: any) => isDev ? '[name].css' : 'css/[contenthash:7].css',
img: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
font: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
video: ({ isDev }: any) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
},
/**
* Customize the options of Nuxt's integrated webpack loaders.
* @version 2
*/
loaders: {
$resolve: async (val, get) => {
const styleLoaders = [
'css', 'cssModules', 'less',
'sass', 'scss', 'stylus', 'vueStyle'
]
for (const name of styleLoaders) {
const loader = val[name]
if (loader && loader.sourcemap === undefined) {
loader.sourcemap = Boolean(await get('build.cssSourceMap'))
}
}
return val
},
file: { esModule: false },
fontUrl: { esModule: false, limit: 1000 },
imgUrl: { esModule: false, limit: 1000 },
pugPlain: {},
vue: {
productionMode: { $resolve: async (val, get) => val ?? !(await get('dev')) },
transformAssetUrls: {
video: 'src',
source: 'src',
object: 'src',
embed: 'src'
},
compilerOptions: { $resolve: async (val, get) => val ?? await get('vue.compilerOptions') },
},
css: {
importLoaders: 0,
esModule: false
},
cssModules: {
importLoaders: 0,
esModule: false,
modules: {
localIdentName: '[local]_[hash:base64:5]'
}
},
less: {},
sass: {
sassOptions: {
indentedSyntax: true
}
},
scss: {},
stylus: {},
vueStyle: {}
},
/**
* @deprecated Use [style-resources-module](https://github.com/nuxt-community/style-resources-module/)
* @version 2
*/
styleResources: {},
/**
* Add webpack plugins.
*
* @example
* ```js
* import webpack from 'webpack'
* import { version } from './package.json'
* // ...
* plugins: [
* new webpack.DefinePlugin({
* 'process.VERSION': version
* })
* ]
* ```
* @version 2
*/
plugins: [],
/**
* Terser plugin options.
*
* Set to false to disable this plugin, or pass an object of options.
*
* @see [terser-webpack-plugin documentation](https://github.com/webpack-contrib/terser-webpack-plugin)
*
* @note Enabling sourcemap will leave `//# sourcemappingURL` linking comment at
* the end of each output file if webpack `config.devtool` is set to `source-map`.
* @version 2
*/
terser: {},
/**
* Enables the [HardSourceWebpackPlugin](https://github.com/mzgoddard/hard-source-webpack-plugin) for improved caching.
*
* @warning unstable
* @version 2
*/
hardSource: false,
/**
* Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle.
* @version 2
*/
aggressiveCodeRemoval: false,
/**
* OptimizeCSSAssets plugin options.
*
* Defaults to true when `extractCSS` is enabled.
*
* @see [optimize-css-assets-webpack-plugin documentation](https://github.com/NMFR/optimize-css-assets-webpack-plugin).
* @version 2
*/
optimizeCSS: {
$resolve: async (val, get) => val ?? (await get('build.extractCSS') ? {} : false)
},
/**
* Configure [webpack optimization](https://webpack.js.org/configuration/optimization/).
* @version 2
*/
optimization: {
runtimeChunk: 'single',
/** Set minimize to false to disable all minimizers. (It is disabled in development by default) */
minimize: {
$resolve: async (val, get) => val ?? !(await get('dev'))
},
/** You can set minimizer to a customized array of plugins. */
minimizer: undefined,
splitChunks: {
chunks: 'all',
automaticNameDelimiter: '/',
cacheGroups: {}
}
},
/**
* Whether to split code for `layout`, `pages` and `commons` chunks.
*
* Commons libs include `vue`, `vue-loader`, `vue-router`, `vuex`, etc.
* @version 2
*/
splitChunks: {
layouts: false,
pages: true,
commons: true
},
/**
* Nuxt will automatically detect the current version of `core-js` in your project (`'auto'`),
* or you can specify which version you want to use (`2` or `3`).
* @version 2
*/
corejs: 'auto',
/**
* Customize your Babel configuration.
*
* See [babel-loader options](https://github.com/babel/babel-loader#options) and
* [babel options](https://babeljs.io/docs/en/options).
*
* @note `.babelrc` is ignored by default.
* @version 2
*/
babel: {
configFile: false,
babelrc: false,
/**
* An array of Babel plugins to load, or a function that takes webpack context and returns
* an array of Babel plugins.
*
* For more information see [Babel plugins options](https://babeljs.io/docs/en/options#plugins)
* and [babel-loader options](https://github.com/babel/babel-loader#options).
*/
plugins: [],
/**
* The Babel presets to be applied.
*
* @note The presets configured here will be applied to both the client and the server
* build. The target will be set by Nuxt accordingly (client/server). If you want to configure
* the preset differently for the client or the server build, please use presets as a function.
*
* @warning It is highly recommended to use the default preset instead customizing.
*
* @example
* ```js
* export default {
* build: {
* babel: {
* presets({ isServer }, [ preset, options ]) {
* // change options directly
* options.targets = isServer ? '...' : '...'
* options.corejs = '...'
* // return nothing
* }
* }
* }
* }
* ```
*
* @example
* ```js
* export default {
* build: {
* babel: {
* presets({ isServer }, [preset, options]) {
* return [
* [
* preset,
* {
* targets: isServer ? '...' : '...',
* ...options
* }
* ],
* [
* // Other presets
* ]
* ]
* }
* }
* }
* }
* ```
*/
presets: {},
cacheDirectory: {
$resolve: async (val, get) => val ?? (await get('dev'))
}
},
/** /**
* If you want to transpile specific dependencies with Babel, you can add them here. * 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 * Each item in transpile can be a package name, a function, a string or regex object matching the
@ -490,80 +53,12 @@ export default defineUntypedSchema({
* ```js * ```js
transpile: [({ isLegacy }) => isLegacy && 'ky'] transpile: [({ isLegacy }) => isLegacy && 'ky']
* ``` * ```
* @version 2
* @version 3
* @type {Array<string | RegExp | Function>} * @type {Array<string | RegExp | Function>}
*/ */
transpile: { transpile: {
$resolve: val => [].concat(val).filter(Boolean) $resolve: val => [].concat(val).filter(Boolean)
}, },
/**
* Customize PostCSS Loader plugins.
* Sames options as https://github.com/webpack-contrib/postcss-loader#options
* @version 2
*/
postcss: {
execute: undefined,
postcssOptions: {
$resolve: async (val, get) => {
// Ensure we return the same object in `build.postcss.postcssOptions as `postcss`
// so modules which modify the configuration continue to work.
const postcssOptions = await get('postcss')
Object.assign(postcssOptions, defu(postcssOptions, val))
return postcssOptions
}
},
sourcemap: undefined,
implementation: undefined,
order: ''
},
/** @version 2 */
html: {
/**
* Configuration for the html-minifier plugin used to minify HTML files created
* during the build process (will be applied for all modes).
*
* @warning If you make changes, they won't be merged with the defaults!
*
* @example
* ```js
* export default {
* html: {
* minify: {
* collapseBooleanAttributes: true,
* decodeEntities: true,
* minifyCSS: true,
* minifyJS: true,
* processConditionalComments: true,
* removeEmptyAttributes: true,
* removeRedundantAttributes: true,
* trimCustomFragments: true,
* useShortDoctype: true
* }
* }
* }
* ```
*/
minify: {
collapseBooleanAttributes: true,
decodeEntities: true,
minifyCSS: true,
minifyJS: true,
processConditionalComments: true,
removeEmptyAttributes: true,
removeRedundantAttributes: true,
trimCustomFragments: true,
useShortDoctype: true
}
},
/**
* Allows setting a different app template (other than `@nuxt/vue-app`)
* @version 2
*/
template: undefined,
/** /**
* You can provide your own templates which will be rendered based * You can provide your own templates which will be rendered based
* on Nuxt configuration. This feature is specially useful for using with modules. * on Nuxt configuration. This feature is specially useful for using with modules.
@ -583,75 +78,35 @@ export default defineUntypedSchema({
* } * }
* ] * ]
* ``` * ```
* @version 2
* @version 3
*/ */
templates: [], templates: [],
/** /**
* You can provide your custom files to watch and regenerate after changes. * Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them.
* *
* This feature is especially useful for using with modules. * 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 * @example
* ```js * ```js
watch: ['~/.nuxt/support.js'] * analyze: {
* analyzerMode: 'static'
* }
* ``` * ```
* @version 2 * @type {boolean | typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options | typeof import('rollup-plugin-visualizer').PluginVisualizerOptions}
*
*/ */
watch: [], analyze: {
/** $resolve: async (val, get) => {
* See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. if (val !== true) {
* @version 2 return val ?? false
*/ }
devMiddleware: { const rootDir = await get('rootDir')
stats: 'none' return {
}, template: 'treemap',
/** projectRoot: rootDir,
* See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options. filename: join(rootDir, '.nuxt/stats', '{name}.html')
* @version 2 }
*/
hotMiddleware: {},
/** @version 2 */
vendor: {
$meta: {
deprecated: 'vendor has been deprecated since nuxt 2'
} }
}, },
/**
* Set to `'none'` or `false` to disable stats printing out after a build.
* @version 2
*/
stats: {
$resolve: async (val, get) => (val === 'none' || (await get('build.quiet'))) ? false : val,
excludeAssets: [
/.map$/,
/index\..+\.html$/,
/vue-ssr-(client|modern)-manifest.json/
]
},
/**
* Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin).
* @version 2
*/
friendlyErrors: true,
/**
* Additional extensions (beyond `['vue', 'js']` to support in `pages/`, `layouts/`, `middleware/`, etc.)
* @version 2
*/
additionalExtensions: [],
/**
* Filters to hide build warnings.
* @version 2
*/
warningIgnoreFilters: [],
/**
* Set to true to scan files within symlinks in the build (such as within `pages/`).
* @version 2
*/
followSymlinks: false
} }
}) })

View File

@ -1,16 +0,0 @@
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
/**
* Add a message to the CLI banner by adding a string to this array.
* @type {string[]}
* @version 2
*/
badgeMessages: [],
/**
* Change the color of the 'Nuxt.js' title in the CLI banner.
* @version 2
*/
bannerColor: 'green'
})

View File

@ -1,15 +1,10 @@
import { defineUntypedSchema } from 'untyped'
import { join, resolve } from 'pathe' import { join, resolve } from 'pathe'
import { isDebug, isDevelopment } from 'std-env' import { isDebug, isDevelopment } from 'std-env'
import createRequire from 'create-require'
import { pascalCase } from 'scule'
import jiti from 'jiti'
import defu from 'defu' import defu from 'defu'
import { findWorkspaceDir } from 'pkg-types' import { findWorkspaceDir } from 'pkg-types'
import { RuntimeConfig } from '../types/config' import { RuntimeConfig } from '../types/config'
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** /**
* Extend project from multiple local or remote sources. * Extend project from multiple local or remote sources.
@ -20,7 +15,6 @@ export default defineUntypedSchema({
* *
* @type {string|string[]} * @type {string|string[]}
* *
* @version 3
*/ */
extends: null, extends: null,
@ -33,7 +27,6 @@ export default defineUntypedSchema({
* *
* @type {string} * @type {string}
* *
* @version 3
*/ */
theme: null, theme: null,
@ -45,8 +38,6 @@ export default defineUntypedSchema({
* current/working directory. * current/working directory.
* *
* It is normally not needed to configure this option. * It is normally not needed to configure this option.
* @version 2
* @version 3
*/ */
rootDir: { rootDir: {
$resolve: val => typeof val === 'string' ? resolve(val) : process.cwd() $resolve: val => typeof val === 'string' ? resolve(val) : process.cwd()
@ -59,7 +50,6 @@ export default defineUntypedSchema({
* your workspace directory automatically, but you can override it here. * your workspace directory automatically, but you can override it here.
* *
* It is normally not needed to configure this option. * It is normally not needed to configure this option.
* @version 3
*/ */
workspaceDir: { workspaceDir: {
$resolve: async (val, get) => val ? resolve(await get('rootDir'), val) : await findWorkspaceDir(await get('rootDir')).catch(() => get('rootDir')) $resolve: async (val, get) => val ? resolve(await get('rootDir'), val) : await findWorkspaceDir(await get('rootDir')).catch(() => get('rootDir'))
@ -93,8 +83,6 @@ export default defineUntypedSchema({
* ------| store/ * ------| store/
* ------| server/ * ------| server/
* ``` * ```
* @version 2
* @version 3
*/ */
srcDir: { srcDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || '.') $resolve: async (val, get) => resolve(await get('rootDir'), val || '.')
@ -106,7 +94,6 @@ export default defineUntypedSchema({
* *
* If a relative path is specified, it will be relative to your `rootDir`. * If a relative path is specified, it will be relative to your `rootDir`.
* *
* @version 3
*/ */
serverDir: { serverDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || resolve(await get('srcDir'), 'server')) $resolve: async (val, get) => resolve(await get('rootDir'), val || resolve(await get('srcDir'), 'server'))
@ -124,340 +111,11 @@ export default defineUntypedSchema({
* buildDir: 'nuxt-build' * buildDir: 'nuxt-build'
* } * }
* ``` * ```
* @version 2
* @version 3
*/ */
buildDir: { buildDir: {
$resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt') $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.
*
* At the moment, it prints out hook names and timings on the server, and
* logs hook arguments as well in the browser.
*
* @version 2
* @version 3
*/
debug: {
$resolve: async (val, get) => val ?? isDebug
},
/**
* 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 `<script type="module">`
* and the legacy bundle with `<script nomodule>`. It will also provide a
* `<link rel="modulepreload">` for the modern bundle. Every browser that understands
* the module type will load the modern bundle while older browsers fall back to the
* legacy (transpiled) bundle.
*
* If you have set `modern: true` and are generating your app or have `ssr: false`,
* modern will be set to `'client'`.
*
* If you have set `modern: true` and are serving your app, modern will be set to `'server'`.
*
* @see [concept of modern mode](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/)
* @type {'server' | 'client' | boolean}
* @version 2
*/
modern: undefined,
/**
* 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.
*
* @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 | string | [typeof import('../src/types/module').NuxtModule | string, Record<string, any>])[]}
* @version 2
* @version 3
*/
modules: [],
/**
* Modules that are only required during development and build time.
*
* 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.
*
* @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 () {}
* ]
* ```
*
* @note In Nuxt 2, using `buildModules` helps to make production startup faster and also significantly
* decreases the size of `node_modules` in production deployments. Please refer to each
* module's documentation to see if it is recommended to use `modules` or `buildModules`.
*
* @type {(typeof import('../src/types/module').NuxtModule | string | [typeof import('../src/types/module').NuxtModule | string, Record<string, any>])[]}
* @version 2
* @deprecated This is no longer needed in Nuxt 3 and Nuxt Bridge; all modules should be added to `modules` instead.
*/
buildModules: [],
/**
* Built-in ad-hoc modules.
*
* @private
*/
_modules: [],
/**
* Installed module metadata.
*
* @version 3
* @private
*/
_installedModules: [],
/**
* Allows customizing the global ID used in the main HTML template as well as the main
* Vue instance name and other options.
* @version 2
*/
globalName: {
$resolve: val => (typeof val === 'string' && /^[a-zA-Z]+$/.test(val)) ? val.toLocaleLowerCase() : 'nuxt'
},
/**
* Customizes specific global names (they are based on `globalName` by default).
* @version 2
*/
globals: {
/** @type {(globalName: string) => string} */
id: (globalName: string) => `__${globalName}`,
/** @type {(globalName: string) => string} */
nuxt: (globalName: string) => `$${globalName}`,
/** @type {(globalName: string) => string} */
context: (globalName: string) => `__${globalName.toUpperCase()}__`,
/** @type {(globalName: string) => string} */
pluginPrefix: (globalName: string) => globalName,
/** @type {(globalName: string) => string} */
readyCallback: (globalName: string) => `on${pascalCase(globalName)}Ready`,
/** @type {(globalName: string) => string} */
loadedCallback: (globalName: string) => `_on${pascalCase(globalName)}Loaded`
},
/**
* Server middleware are connect/express/h3-shaped functions that handle server-side requests. They
* run on the server and before the Vue renderer.
*
* By adding entries to `serverMiddleware` you can register additional routes without the need
* for an external server.
*
* You can pass a string, which can be the name of a node dependency or a path to a file. You
* can also pass an object with `path` and `handler` keys (`handler` can be a path or a
* function).
*
* @note If you pass a function directly, it will only run in development mode.
*
* @example
* ```js
* serverMiddleware: [
* // Will register redirect-ssl npm package
* 'redirect-ssl',
* // Will register file from project server-middleware directory to handle /server-middleware/* requires
* { path: '/server-middleware', handler: '~/server-middleware/index.js' },
* // We can create custom instances too, but only in development mode, they are ignored for the production bundle.
* { path: '/static2', handler: serveStatic(fileURLToPath(new URL('./static2', import.meta.url))) }
* ]
* ```
*
* @note If you don't want middleware to run on all routes you should use the object
* form with a specific path.
*
* If you pass a string handler, Nuxt will expect that file to export a default function
* that handles `(req, res, next) => void`.
*
* @example
* ```js
* export default function (req, res, next) {
* // req is the Node.js http request object
* console.log(req.url)
* // res is the Node.js http response object
* // next is a function to call to invoke the next middleware
* // Don't forget to call next at the end if your middleware is not an endpoint!
* next()
* }
* ```
*
* Alternatively, it can export a connect/express/h3-type app instance.
* @example
* ```js
* import bodyParser from 'body-parser'
* import createApp from 'express'
* const app = createApp()
* app.use(bodyParser.json())
* app.all('/getJSON', (req, res) => {
* res.json({ data: 'data' })
* })
* export default app
* ```
*
* Alternatively, instead of passing an array of `serverMiddleware`, you can pass an object
* whose keys are the paths and whose values are the handlers (string or function).
* @example
* ```js
* export default {
* serverMiddleware: {
* '/a': '~/server-middleware/a.js',
* '/b': '~/server-middleware/b.js',
* '/c': '~/server-middleware/c.js'
* }
* }
* ```
*
* @version 2
* @deprecated Use `serverHandlers` instead
*/
serverMiddleware: {
$resolve: (val: any) => {
if (!val) {
return []
}
if (!Array.isArray(val)) {
return Object.entries(val).map(([path, handler]) => ({ path, handler }))
}
return val
}
},
/** /**
* Used to set the modules directories for path resolving (for example, webpack's * Used to set the modules directories for path resolving (for example, webpack's
* `resolveLoading`, `nodeExternals` and `postcss`). * `resolveLoading`, `nodeExternals` and `postcss`).
@ -472,7 +130,6 @@ export default defineUntypedSchema({
* modulesDir: ['../../node_modules'] * modulesDir: ['../../node_modules']
* } * }
* ``` * ```
* @version 2
*/ */
modulesDir: { modulesDir: {
$default: ['node_modules'], $default: ['node_modules'],
@ -482,82 +139,121 @@ export default defineUntypedSchema({
] ]
}, },
/**
* Whether Nuxt is running in development mode.
*
* Normally, you should not need to set this.
*/
dev: Boolean(isDevelopment),
/**
* Whether your app is being unit tested.
*/
test: Boolean(isDevelopment),
/**
* 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.
*
*/
debug: {
$resolve: async (val, get) => val ?? isDebug
},
/**
* 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.
*/
ssr: {
$resolve: (val) => 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.
*
* @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 | string | [typeof import('../src/types/module').NuxtModule | string, Record<string, any>])[]}
*/
modules: [],
/** @deprecated Use `modules` instead */
buildModules: [],
/** /**
* Customize default directory structure used by Nuxt. * Customize default directory structure used by Nuxt.
* *
* It is better to stick with defaults unless needed. * It is better to stick with defaults unless needed.
* @version 2
* @version 3
*/ */
dir: { dir: {
/** /**
* The assets directory (aliased as `~assets` in your build). * The assets directory (aliased as `~assets` in your build).
* @version 2
*/ */
assets: 'assets', assets: 'assets',
/**
* The directory containing app template files like `app.html` and `router.scrollBehavior.js`
* @version 2
*/
app: 'app',
/** /**
* The layouts directory, each file of which will be auto-registered as a Nuxt layout. * The layouts directory, each file of which will be auto-registered as a Nuxt layout.
* @version 2
* @version 3
*/ */
layouts: 'layouts', layouts: 'layouts',
/** /**
* The middleware directory, each file of which will be auto-registered as a Nuxt middleware. * The middleware directory, each file of which will be auto-registered as a Nuxt middleware.
* @version 3
* @version 2
*/ */
middleware: 'middleware', middleware: 'middleware',
/** /**
* The directory which will be processed to auto-generate your application page routes. * The directory which will be processed to auto-generate your application page routes.
* @version 2
* @version 3
*/ */
pages: 'pages', pages: 'pages',
/** /**
* The plugins directory, each file of which will be auto-registered as a Nuxt plugin. * The plugins directory, each file of which will be auto-registered as a Nuxt plugin.
* @version 3
*/ */
plugins: 'plugins', plugins: 'plugins',
/** /**
* The directory containing your static files, which will be directly accessible via the Nuxt server * 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. * and copied across into your `dist` folder when your app is generated.
* @version 3
*/ */
public: { public: {
$resolve: async (val, get) => val || await get('dir.static') || 'public', $resolve: async (val, get) => val || await get('dir.static') || 'public',
}, },
/** @version 2 */
static: { static: {
$schema: { deprecated: 'use `dir.public` option instead' }, $schema: { deprecated: 'use `dir.public` option instead' },
$resolve: async (val, get) => val || await get('dir.public') || 'public', $resolve: async (val, get) => val || await get('dir.public') || 'public',
}, }
/**
* The folder which will be used to auto-generate your Vuex store structure.
* @version 2
*/
store: 'store'
}, },
/** /**
* The extensions that should be resolved by the Nuxt resolver. * The extensions that should be resolved by the Nuxt resolver.
* @version 2
* @version 3
*/ */
extensions: { extensions: {
$resolve: val => ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'].concat(val).filter(Boolean) $resolve: val => ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'].concat(val).filter(Boolean)
}, },
/**
* The style extensions that should be resolved by the Nuxt resolver (for example, in `css` property).
* @version 2
*/
styleExtensions: ['.css', '.pcss', '.postcss', '.styl', '.stylus', '.scss', '.sass', '.less'],
/** /**
* You can improve your DX by defining additional aliases to access custom directories * You can improve your DX by defining additional aliases to access custom directories
* within your JavaScript and CSS. * within your JavaScript and CSS.
@ -601,8 +297,6 @@ export default defineUntypedSchema({
* ``` * ```
* *
* @type {Record<string, string>} * @type {Record<string, string>}
* @version 2
* @version 3
*/ */
alias: { alias: {
$resolve: async (val, get) => ({ $resolve: async (val, get) => ({
@ -627,24 +321,18 @@ export default defineUntypedSchema({
* ignorecase: false * ignorecase: false
* } * }
* ``` * ```
* @version 2
* @version 3
*/ */
ignoreOptions: undefined, ignoreOptions: undefined,
/** /**
* Any file in `pages/`, `layouts/`, `middleware/` or `store/` will be ignored during * Any file in `pages/`, `layouts/`, `middleware/` or `store/` will be ignored during
* building if its filename starts with the prefix specified by `ignorePrefix`. * building if its filename starts with the prefix specified by `ignorePrefix`.
* @version 2
* @version 3
*/ */
ignorePrefix: '-', ignorePrefix: '-',
/** /**
* More customizable than `ignorePrefix`: all files matching glob patterns specified * More customizable than `ignorePrefix`: all files matching glob patterns specified
* inside the `ignore` array will be ignored in building. * inside the `ignore` array will be ignored in building.
* @version 2
* @version 3
*/ */
ignore: { ignore: {
$resolve: async (val, get) => [ $resolve: async (val, get) => [
@ -655,34 +343,8 @@ export default defineUntypedSchema({
].concat(val).filter(Boolean) ].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`. * The watchers property lets you overwrite watchers configuration in your `nuxt.config`.
* @version 2
* @version 3
*/ */
watchers: { watchers: {
/** An array of event types, which, when received, will cause the watcher to restart. */ /** An array of event types, which, when received, will cause the watcher to restart. */
@ -705,15 +367,6 @@ export default defineUntypedSchema({
} }
}, },
/**
* 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, * Hooks are listeners to Nuxt events that are typically used in modules,
* but are also available in `nuxt.config`. * but are also available in `nuxt.config`.
@ -741,8 +394,6 @@ export default defineUntypedSchema({
* } * }
* } * }
* ``` * ```
* @version 2
* @version 3
* @type {typeof import('../src/types/hooks').NuxtHooks} * @type {typeof import('../src/types/hooks').NuxtHooks}
*/ */
hooks: null, hooks: null,
@ -772,7 +423,6 @@ export default defineUntypedSchema({
* } * }
* ``` * ```
* @type {typeof import('../src/types/config').RuntimeConfig} * @type {typeof import('../src/types/config').RuntimeConfig}
* @version 3
*/ */
runtimeConfig: { runtimeConfig: {
$resolve: async (val: RuntimeConfig, get) => defu(val, { $resolve: async (val: RuntimeConfig, get) => defu(val, {
@ -789,16 +439,12 @@ export default defineUntypedSchema({
/** /**
* @type {typeof import('../src/types/config').PrivateRuntimeConfig} * @type {typeof import('../src/types/config').PrivateRuntimeConfig}
* @version 2
* @version 3
* @deprecated Use `runtimeConfig` option. * @deprecated Use `runtimeConfig` option.
*/ */
privateRuntimeConfig: {}, privateRuntimeConfig: {},
/** /**
* @type {typeof import('../src/types/config').PublicRuntimeConfig} * @type {typeof import('../src/types/config').PublicRuntimeConfig}
* @version 2
* @version 3
* @deprecated Use `runtimeConfig` option with `public` key (`runtimeConfig.public.*`). * @deprecated Use `runtimeConfig` option with `public` key (`runtimeConfig.public.*`).
*/ */
publicRuntimeConfig: {}, publicRuntimeConfig: {},
@ -810,7 +456,6 @@ export default defineUntypedSchema({
* It will be merged with `app.config` file as default value. * It will be merged with `app.config` file as default value.
* *
* @type {typeof import('../src/types/config').AppConfig} * @type {typeof import('../src/types/config').AppConfig}
* @version 3
*/ */
appConfig: {}, appConfig: {},
}) })

View File

@ -0,0 +1,38 @@
import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({
devServer: {
/**
* Whether to enable HTTPS.
*
* @example
* ```
* import { fileURLToPath } from 'node:url'
* export default {
* server: {
* https: {
* key: fs.readFileSync(fileURLToPath(new URL('./server.key', import.meta.url))),
* cert: fs.readFileSync(fileURLToPath(new URL('./server.crt', import.meta.url)))
* }
* }
* }
* ```
*
*
* @type {false | { key: string; cert: string }}
*
*/
https: false,
/** Dev server listening port */
port: process.env.NUXT_PORT || process.env.NITRO_PORT || process.env.PORT || 3000,
/** Dev server listening host */
host: process.env.NUXT_HOST || process.env.NITRO_HOST || process.env.HOST || 'localhost',
/**
* Listening dev server url
*/
url: 'http://localhost:3000',
}
})

View File

@ -1,7 +1,6 @@
import { defineUntypedSchema } from 'untyped' import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** @version 3 */
experimental: { experimental: {
/** /**
* Set to true to generate an async entry point for the Vue bundle (for module federation support). * Set to true to generate an async entry point for the Vue bundle (for module federation support).
@ -61,7 +60,7 @@ export default defineUntypedSchema({
* @type {boolean | ((id?: string) => boolean)} * @type {boolean | ((id?: string) => boolean)}
*/ */
inlineSSRStyles: { inlineSSRStyles: {
async $resolve (val, get) { async $resolve(val, get) {
if (val === false || (await get('dev')) || (await get('ssr')) === false || (await get('builder')) === '@nuxt/webpack-builder') { if (val === false || (await get('dev')) || (await get('ssr')) === false || (await get('builder')) === '@nuxt/webpack-builder') {
return false return false
} }

View File

@ -1,18 +1,7 @@
import { resolve } from 'pathe' import { defineUntypedSchema } from 'untyped'
import { joinURL } from 'ufo'
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default <SchemaDefinition>{
/**
* Directory name that holds all the assets and generated pages for a `static` build.
*/
dir: {
$resolve: async (val = 'dist', get) => resolve((await get('rootDir')), val)
},
export default defineUntypedSchema({
generate: {
/** /**
* The routes to generate. * The routes to generate.
* *
@ -74,103 +63,6 @@ export default <SchemaDefinition>{
* An array of string or regular expressions that will prevent generation * An array of string or regular expressions that will prevent generation
* of routes matching them. The routes will still be accessible when `fallback` is set. * of routes matching them. The routes will still be accessible when `fallback` is set.
*/ */
exclude: [], exclude: []
/** The number of routes that are generated concurrently in the same thread. */
concurrency: 500,
/**
* Interval in milliseconds between two render cycles to avoid flooding a potential
* API with calls.
*/
interval: 0,
/**
* Set to `false` to disable creating a directory + `index.html` for each route.
*
* @example
* ```bash
* # subFolders: true
* -| dist/
* ---| index.html
* ---| about/
* -----| index.html
* ---| products/
* -----| item/
* -------| index.html
*
* # subFolders: false
* -| dist/
* ---| index.html
* ---| about.html
* ---| products/
* -----| item.html
* ```
*/
subFolders: true,
/**
* The path to the fallback HTML file.
*
* Set this as the error page in your static server configuration, so that unknown
* routes can be rendered (on the client-side) by Nuxt.
*
* * If unset or set to a falsy value, the name of the fallback HTML file will be `200.html`.
* * If set to `true`, the filename will be `404.html`.
* * If you provide a string as a value, it will be used instead.
*
* @note Multiple services (e.g. Netlify) detect a `404.html` automatically. If
* you configure your web server on your own, please consult its documentation
* to find out how to set up an error page (and set it to the `404.html` file).
*/
fallback: { $resolve: val => val === true ? '400.html' : (val || '200.html') },
/**
* Set to `false` to disable generating pages discovered through crawling relative
* links in generated pages.
*/
crawler: true,
/** Set to `false` to disable generating a `manifest.js` with a list of all generated pages. */
manifest: true,
/** Set to `false` to disable generating a `.nojekyll` file (which aids compatibility with GitHub Pages). */
nojekyll: true,
/**
* Configure the cache (used with `static` target to avoid rebuilding when no files have changed).
*
* Set to `false` to disable completely.
*/
cache: {
/** An array of files or directories to ignore. (It can also be a function that returns an array.) */
ignore: [],
/**
* Options to pass to [`globby`](https://github.com/sindresorhus/globby), which
* is used to generate a 'snapshot' of the source files.
*/
globbyOptions: {
gitignore: true
} }
}, })
staticAssets: {
/** The directory underneath `/_nuxt/`, where static assets (payload, state and manifest files) will live. */
dir: 'static',
/**
* The full path to the directory underneath `/_nuxt/` where static assets
* (payload, state and manifest files) will live.
*/
base: {
$resolve: async (val, get) => val || joinURL((await get('app')).buildAssetsDir, (await get('generate.dir')))
},
/** The full path to the versioned directory where static assets for the current build are located. */
versionBase: {
$resolve: async (val, get) => val || joinURL((await get('generate.base')), (await get('generate.version')))
},
/** A unique string to uniquely identify payload versions (defaults to the current timestamp). */
version: {
$resolve: val => val || (String(Math.round(Date.now() / 1000)))
}
}
}

View File

@ -1,57 +1,31 @@
import adhoc from './adhoc'
import _adhoc from './_adhoc' import app from './app'
import _app from './_app'
import _common from './_common'
import _internal from './_internal'
import build from './build' import build from './build'
import messages from './messages' import common from './common'
import render from './render' import dev from './dev'
import router from './router' import experimental from './experimental'
import server from './server'
import cli from './cli'
import generate from './generate' import generate from './generate'
import internal from './internal'
import nitro from './nitro'
import postcss from './postcss' import postcss from './postcss'
import router from './router'
import typescript from './typescript' import typescript from './typescript'
import vite from './vite' import vite from './vite'
import webpack from './webpack' import webpack from './webpack'
import nitro from './nitro'
import experimental from './experimental'
/*
TODO for top level normalizations: (nuxt2)
- transition => pageTransition
- export => generate
- gzip => compressor
- Apply preset
- render.etag.hash should be a function
- deprecated devModules
- set consola level to 0 if build.quite is true
- Ad-hoc: loading-screen, components and telemtry
- build.indicator and build.loadingScreen
- build.crossorigin => render.crossorigin
- render.csp.unsafeInlineCompatiblity => render.csp.unsafeInlineCompatibility
- guards: rootDir:buildDir rootDir:generate.dir srcDir:buildDir srcDir:generate.dir
- _publicPath (original value of publicPath)
- options.build.babel.presets (array) warn @nuxtjs/babel-preset-app => @nuxt/babel-preset-app
*/
export default { export default {
..._adhoc, ...adhoc,
..._app, ...app,
..._common, ...build,
..._internal, ...common,
...dev,
...experimental,
...generate,
...internal,
...nitro,
...postcss, ...postcss,
...router,
...typescript, ...typescript,
...vite, ...vite,
...webpack, ...webpack
...nitro,
...experimental,
// Legacy
...build,
messages,
render,
router,
server,
cli,
generate,
} }

View File

@ -22,5 +22,9 @@ export default defineUntypedSchema({
/** @private */ /** @private */
_nuxtConfigFiles: [], _nuxtConfigFiles: [],
/** @private */ /** @private */
appDir: '' appDir: '',
/** @private */
_installedModules: [],
/** @private */
_modules: []
}) })

View File

@ -1,23 +0,0 @@
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default <SchemaDefinition> {
/** The text that displays on the Nuxt loading indicator when `ssr: false`. */
loading: 'Loading...',
/** The 404 text on the default Nuxt error page. */
error_404: 'This page could not be found',
/** The text to display on the default Nuxt error page when there has been a server error. */
server_error: 'Server error',
/** The text (linked to nuxtjs.org) that appears on the built-in Nuxt error page. */
nuxtjs: 'Nuxt',
/** The text (linked to the home page) that appears on the built-in Nuxt error page. */
back_to_home: 'Back to the home page',
/** The message that will display on a white screen if the built-in Nuxt error page can't be rendered. */
server_error_details: 'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
/** The default error title (if there isn't a specific error message) on the built-in Nuxt error page. */
client_error: 'Error',
/** The error message (in debug mode) on the built-in Nuxt error page. */
client_error_details: 'An error occurred while rendering the page. Check developer tools console for details.'
}

View File

@ -7,8 +7,6 @@ export default defineUntypedSchema({
* @see https://nitro.unjs.io/config/ * @see https://nitro.unjs.io/config/
* *
* @type {typeof import('nitropack')['NitroConfig']} * @type {typeof import('nitropack')['NitroConfig']}
* @version 2
* @version 3
*/ */
nitro: { nitro: {
routeRules: { routeRules: {
@ -27,7 +25,6 @@ export default defineUntypedSchema({
* @see https://nitro.unjs.io/config/#routes * @see https://nitro.unjs.io/config/#routes
* *
* @type {typeof import('nitropack')['NitroConfig']['routeRules']} * @type {typeof import('nitropack')['NitroConfig']['routeRules']}
* @version 3
*/ */
routeRules: {}, routeRules: {},
@ -53,7 +50,6 @@ export default defineUntypedSchema({
* ``` * ```
* *
* @type {typeof import('nitropack')['NitroEventHandler'][]} * @type {typeof import('nitropack')['NitroEventHandler'][]}
* @version 3
*/ */
serverHandlers: [], serverHandlers: [],
@ -63,7 +59,6 @@ export default defineUntypedSchema({
* @see https://nitro.unjs.io/guide/introduction/routing * @see https://nitro.unjs.io/guide/introduction/routing
* *
* @type {typeof import('nitropack')['NitroDevEventHandler'][]} * @type {typeof import('nitropack')['NitroDevEventHandler'][]}
* @version 3
*/ */
devServerHandlers: [] devServerHandlers: []
}) })

View File

@ -3,11 +3,11 @@ import createResolver from 'postcss-import-resolver'
import { defineUntypedSchema } from 'untyped' import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** @version 3 */
postcss: { postcss: {
/** Path to postcss config file. */ /** Path to postcss config file. */
/** @type string | false */ /** @type string | false */
config: false, config: false,
/** /**
* Options for configuring PostCSS plugins. * Options for configuring PostCSS plugins.
* *

View File

@ -1,298 +0,0 @@
import { SchemaDefinition } from 'untyped'
/**
* @version 2
*/
export default <SchemaDefinition>{
/**
* Use this option to customize the Vue SSR bundle renderer.
* This option is skipped if `ssr: false`.
*
* Read [docs for Vue 2](https://ssr.vuejs.org/api/#renderer-options) here.
*/
bundleRenderer: {
shouldPrefetch: () => false,
shouldPreload: (_fileWithoutQuery: string, asType: string) => ['script', 'style'].includes(asType),
/** enabled by default for development */
runInNewContext: {
$resolve: async (val, get) => val ?? (await get('dev'))
}
},
/**
* Configure the crossorigin attribute on `<link rel="stylesheet">` and `<script>`
* tags in generated HTML. [More information](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin).
*/
crossorigin: undefined,
/**
* Adds prefetch and preload links for faster initial page load time.
* You probably don't want to disable this option unless you have many pages and routes.
*/
resourceHints: true,
/**
* Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time.
*
* This option is automatically set based on global SSR value if not provided.
* This can be useful to dynamically enable/disable SSR at runtime after image builds
* (with docker, for example).
*/
ssr: undefined,
/**
* Forward server-side logs to the browser for better debugging (only available in development).
*
* Set to `collapsed` to collapse the logs, or `false` to disable.
*/
ssrLog: {
$resolve: async (val, get) => (await get('dev')) ? Boolean(val) : false
},
/**
* Configuration for HTTP2 push headers.
*/
http2: {
/** Set to true to enable HTTP2 push headers. */
push: false,
/** @deprecated */
shouldPush: null,
/**
* You can control what links to push using this function. It receives `req`,
* `res`, `publicPath` and a `preloadFiles` array.
*
* You can add your own assets to the array as well. Using `req` and `res`
* you can decide what links to push based on the request headers, for example
* using the cookie with application version.
*
* Assets will be joined together with `,` and passed as a single `Link` header.
*
* @example
* ```js
* pushAssets: (req, res, publicPath, preloadFiles) =>
* preloadFiles
* .filter(f => f.asType === 'script' && f.file === 'runtime.js')
* .map(f => `<${publicPath}${f.file}>; rel=preload; as=${f.asType}`)
* ```
*/
pushAssets: null
},
/**
* Configure the behavior of the `static/` directory.
*
* See [serve-static docs](https://github.com/expressjs/serve-static) for possible options.
*/
static: {
/**
* Whether to add the router base to your static assets.
*
* @note some URL rewrites might not respect the prefix.
*
* @example
* Assets: favicon.ico
* Router base: /t
* With `prefix: true` (default): /t/favicon.ico
* With `prefix: false`: /favicon.ico
*/
prefix: true
},
/**
* Configure server compression.
*
* Set to `false` to disable compression. You can also pass an object of options
* for [compression middleware](https://www.npmjs.com/package/compression), or
* use your own middleware by passing it in directly - for example,
* `otherComp({ myOptions: 'example' })`.
*
* @type {boolean | object | Function}
*/
compressor: {
threshold: 0
},
/**
* To disable etag for pages set `etag: false`. See
* [etag docs](https://github.com/jshttp/etag) for possible options.
* You can use your own hash function by specifying etag.hash:
*
* @example
* ```js
* import { murmurHash128 } from 'murmurhash-native'
*
* export default {
* render: {
* etag: {
* hash: html => murmurHash128(html)
* }
* }
* }
* ```
* In this example we are using `murmurhash-native`, which is faster
* for larger HTML body sizes. Note that the weak option is ignored
* when specifying your own hash function.
*/
etag: {
hash: false,
weak: false
},
/**
* Use this to configure Content-Security-Policy to load external resources. [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
*
* Set to `true` to enable, or you can pass options to fine-tune your CSP options.
*
* **Prerequisites**:
* These CSP settings are only effective when using Nuxt with `mode: 'server'`
* to serve your SSR application.
*
* **Updating settings**:
* These settings are read by the Nuxt server directly from `nuxt.config`.
* This means changes to these settings take effect when the server is restarted.
* There is no need to rebuild the application to update CSP settings.
*
* @example
* ```js
* export default {
* render: {
* csp: {
* hashAlgorithm: 'sha256',
* policies: {
* 'script-src': [
* 'https://www.google-analytics.com',
* 'https://name.example.com'
* ],
* 'report-uri': ['https://report.example.com/report-csp-violations']
* },
* addMeta: true
* }
* }
* }
* ```
*
* The following example allows Google Analytics, LogRocket.io, and Sentry.io
* for logging and analytic tracking.
*
* Review [this blog on Sentry.io](https://blog.sentry.io/2018/09/04/how-sentry-captures-csp-violations)
* to learn what tracking link you should use.
* @example
* ```js
* // PRIMARY_HOSTS = `loc.example-website.com`
* export default {
* render: {
* csp: {
* reportOnly: true,
* hashAlgorithm: 'sha256',
* policies: {
* 'default-src': ["'self'"],
* 'img-src': ['https:', '*.google-analytics.com'],
* 'worker-src': ["'self'", `blob:`, PRIMARY_HOSTS, '*.logrocket.io'],
* 'style-src': ["'self'", "'unsafe-inline'", PRIMARY_HOSTS],
* 'script-src': [
* "'self'",
* "'unsafe-inline'",
* PRIMARY_HOSTS,
* 'sentry.io',
* '*.sentry-cdn.com',
* '*.google-analytics.com',
* '*.logrocket.io'
* ],
* 'connect-src': [PRIMARY_HOSTS, 'sentry.io', '*.google-analytics.com'],
* 'form-action': ["'self'"],
* 'frame-ancestors': ["'none'"],
* 'object-src': ["'none'"],
* 'base-uri': [PRIMARY_HOSTS],
* 'report-uri': [
* `https://sentry.io/api/<project>/security/?sentry_key=<key>`
* ]
* }
* }
* }
* }
* ```
*/
csp: {
$resolve: async (val, get) => {
if (!val) { return false }
return {
hashAlgorithm: 'sha256',
allowedSources: undefined,
/** Policies to be added to the response `Content-Security-Policy` HTTP header. */
policies: undefined,
/**
* Whether to add `<meta http-equiv="Content-Security-Policy"/>` to the `<head>`.
* This is independent of the `csp.policies` configuration and the complete set
* of the defined policies will still be added to the HTTP response header.
*
* @note CSP hashes will not be added as `<meta>` if `script-src` policy
* contains 'unsafe-inline'. This is due to browsers ignoring 'unsafe-inline'
* if hashes are present. (Set option `unsafeInlineCompatibility` to true to
* disable this behavior.)
*/
addMeta: Boolean((await get('target')) === 'static'),
/**
* Set option `unsafeInlineCompatibility` to `true` if you want both hashes and
* 'unsafe-inline' for CSPv1 compatibility. In that case the `<meta>` tag will
* still only contain the hashes of the inline `<script>` tags, and the policies
* defined under `csp.policies` will be used in the `Content-Security-Policy`
* HTTP response header.
*/
unsafeInlineCompatibility: false,
reportOnly: (await get('debug')),
...val
}
}
},
/**
* Options used for serving distribution files. Only applicable in production.
*
* See [serve-static docs](https://www.npmjs.com/package/serve-static) for possible options.
*/
dist: {
index: false,
maxAge: '1y'
},
/**
* Configure fallback behavior for [`serve-placeholder` middleware](https://github.com/nuxt/serve-placeholder).
*
* Example of allowing `.js` extension for routing (for example, `/repos/nuxt.js`):
*
* @example
* ```js
* export default {
* render: {
* fallback: {
* static: {
* // Avoid sending 404 for these extensions
* handlers: {
* '.js': false
* }
* }
* }
* }
* }
* ```
*/
fallback: {
/**
* For routes matching the publicPath (`/_nuxt/*`).
* Disable by setting to `false`.
*/
dist: {},
/**
* For all other routes (`/*`).
* Disable by setting to `false`.
*/
static: {
skipUnknown: true,
handlers: {
'.htm': false,
'.html': false
}
}
}
}

View File

@ -1,172 +1,18 @@
import { normalizeURL, withTrailingSlash } from 'ufo'
import { defineUntypedSchema } from 'untyped' import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
router: {
/** /**
* Additional options passed to `vue-router`. * Additional options passed to `vue-router`.
* *
* Note: Only JSON serializable options should be passed by nuxt config. * Note: Only JSON serializable options should be passed by nuxt config.
* *
* For more control, you can use `app/router.optionts.ts` file. * For more control, you can use `app/router.options.ts` file.
* *
* @see [documentation](https://router.vuejs.org/api/interfaces/routeroptions.html). * @see [documentation](https://router.vuejs.org/api/interfaces/routeroptions.html).
* @type {import('../src/types/router').RouterConfigSerializable} * @type {import('../src/types/router').RouterConfigSerializable}
* *
* @version 3
*/ */
options: {}, options: {}
/**
* Configure the router mode.
*
* For server-side rendering it is not recommended to change it.
* @version 2
*/
mode: 'history',
/**
* The base URL of the app. For example, if the entire single page application is
* served under `/app/`, then base should use the value `'/app/'`.
*
* This can be useful if you need to serve Nuxt as a different context root, from
* within a bigger web site.
* @version 2
*/
base: {
$resolve: async (val, get) => val ? withTrailingSlash(normalizeURL(val)) : (await get('app')).baseURL
},
/** @private */
_routerBaseSpecified: {
$resolve: async (_val, get) => typeof (await get('router.base')) === 'string'
},
/** @version 2 */
routes: [],
/**
* This allows changing the separator between route names that Nuxt uses.
*
* Imagine we have the page file `pages/posts/_id.vue`. Nuxt will generate the
* route name programmatically, in this case `posts-id`. If you change the routeNameSplitter
* config to `/` the name will change to `posts/id`.
* @version 2
*/
routeNameSplitter: '-',
/**
* Set the default(s) middleware for every page of the application.
* @version 2
*/
middleware: {
$resolve: val => Array.isArray(val) ? val : [val].filter(Boolean)
},
/**
* Globally configure `<nuxt-link>` default active class.
* @version 2
*/
linkActiveClass: 'nuxt-link-active',
/**
* Globally configure `<nuxt-link>` default exact active class.
* @version 2
*/
linkExactActiveClass: 'nuxt-link-exact-active',
/**
* Globally configure `<nuxt-link>` default prefetch class (feature disabled by default).
* @version 2
*/
linkPrefetchedClass: false,
/**
* You can pass a function to extend the routes created by Nuxt.
*
* @example
* ```js
* import { fileURLToPath } from 'url'
* export default {
* router: {
* extendRoutes(routes, resolve) {
* routes.push({
* name: 'custom',
* path: '*',
* component: fileURLToPath(new URL('./pages/404.vue', import.meta.url))
* })
* }
* }
* }
* ```
* @version 2
*/
extendRoutes: null,
/**
* The `scrollBehavior` option lets you define a custom behavior for the scroll
* position between the routes. This method is called every time a page is
* rendered. To learn more about it, see the `vue-router` documentation.
*
* @see [vue-router `scrollBehavior` documentation](https://router.vuejs.org/guide/advanced/scroll-behavior.html).
* @version 2
*/
scrollBehavior: {
$schema: {
deprecated: 'router.scrollBehavior` property is deprecated in favor of using `~/app/router.scrollBehavior.js` file, learn more: https://nuxtjs.org/api/configuration-router#scrollbehavior'
} }
},
/**
* Provide custom query string parse function. Overrides the default.
* @version 2
*/
parseQuery: false,
/**
* Provide custom query string stringify function. Overrides the default.
* @version 2
*/
stringifyQuery: false,
/**
* Controls whether the router should fall back to hash mode when the browser
* does not support history.pushState, but mode is set to history.
*
* Setting this to `false` essentially makes every router-link navigation a full
* page refresh in IE9. This is useful when the app is server-rendered and needs
* to work in IE9, because a hash mode URL does not work with SSR.
* @version 2
*/
fallback: false,
/**
* Configure `<nuxt-link>` to prefetch the code-splitted page when detected within
* the viewport. Requires [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to be supported (see [Caniuse](https://caniuse.com/intersectionobserver)).
* @version 2
*/
prefetchLinks: true,
/**
* When using `nuxt generate` with target: 'static', Nuxt will generate a
* payload.js for each page.
*
* With this option enabled, Nuxt will automatically prefetch the payload of the
* linked page when the `<nuxt-link>` is visible in the viewport, making instant navigation.
* @version 2
*/
prefetchPayloads: true,
/**
* If this option is set to `true`, trailing slashes will be appended to every
* route. If set to `false`, they'll be removed.
*
* @warning This option should not be set without preparation and has to
* be tested thoroughly. When setting `trailingSlash` to something else than
* `undefined`, the opposite route will stop working. Thus, 301 redirects should
* be in place and your internal linking has to be adapted correctly. If you set
* `trailingSlash` to `true`, then only `example.com/abc/` will work, but not
* `example.com/abc`. On `false`, it's vice-versa.
* @version 2
*/
trailingSlash: undefined
}) })

View File

@ -1,50 +0,0 @@
import { SchemaDefinition } from 'untyped'
/** @version 2 */
export default <SchemaDefinition>{
/**
* Whether to enable HTTPS.
*
* @example
* ```
* import { fileURLToPath } from 'node:url'
* export default {
* server: {
* https: {
* key: fs.readFileSync(fileURLToPath(new URL('./server.key', import.meta.url))),
* cert: fs.readFileSync(fileURLToPath(new URL('./server.crt', import.meta.url)))
* }
* }
* }
* ```
*
* @version 2
*
* @type {false | { key: string; cert: string }}
*
* @deprecated This option is ignored with Bridge and Nuxt 3
*/
https: false,
/** @deprecated This option is ignored with Bridge and Nuxt 3 */
port: process.env.NUXT_PORT || process.env.PORT || process.env.npm_package_config_nuxt_port || 3000,
/** @deprecated This option is ignored with Bridge and Nuxt 3 */
host: process.env.NUXT_HOST || process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost',
/** @deprecated This option is ignored with Bridge and Nuxt 3 */
socket: process.env.UNIX_SOCKET || process.env.npm_package_config_unix_socket,
/**
* Enabling timing adds a middleware to measure the time elapsed during
* server-side rendering and adds it to the headers as 'Server-Timing'.
*
* Apart from true/false, this can be an object for providing options.
* Currently, only `total` is supported (which directly tracks the whole
* time spent on server-side rendering.
*/
/** @deprecated This option is ignored with Bridge and Nuxt 3 */
timing: (val: any) => val ? ({ total: true, ...val }) : false,
/**
* Listening dev server url
*/
url: 'http://localhost:3000',
}

View File

@ -4,8 +4,6 @@ export default defineUntypedSchema({
/** /**
* Configuration for Nuxt's TypeScript integration. * Configuration for Nuxt's TypeScript integration.
* *
* @version 2
* @version 3
*/ */
typescript: { typescript: {
/** /**
@ -38,7 +36,8 @@ export default defineUntypedSchema({
/** /**
* Generate a `*.vue` shim. * Generate a `*.vue` shim.
* *
* We recommend instead either enabling [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) or adding **TypeScript Vue Plugin (Volar)** 👉 [[Download](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)]. * We recommend instead either enabling [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) or adding
* TypeScript Vue Plugin (Volar)** 👉 [[Download](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)].
*/ */
shim: true shim: true
} }

View File

@ -10,7 +10,6 @@ export default defineUntypedSchema({
* Please note that not all vite options are supported in Nuxt. * Please note that not all vite options are supported in Nuxt.
* *
* @type {typeof import('../src/types/config').ViteConfig} * @type {typeof import('../src/types/config').ViteConfig}
* @version 3
*/ */
vite: { vite: {
root: { root: {

View File

@ -2,7 +2,6 @@ import { join } from 'pathe'
import { defineUntypedSchema } from 'untyped' import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** @version 3 */
webpack: { webpack: {
/** /**
* Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. * Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them.
@ -219,9 +218,7 @@ export default defineUntypedSchema({
* *
* @type {false | typeof import('terser-webpack-plugin').BasePluginOptions & typeof import('terser-webpack-plugin').DefinedDefaultMinimizerAndOptions<any>} * @type {false | typeof import('terser-webpack-plugin').BasePluginOptions & typeof import('terser-webpack-plugin').DefinedDefaultMinimizerAndOptions<any>}
*/ */
terser: { terser: {},
},
/** /**
* Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. * Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle.
@ -257,6 +254,7 @@ export default defineUntypedSchema({
cacheGroups: {} cacheGroups: {}
} }
}, },
/** /**
* Customize PostCSS Loader. * Customize PostCSS Loader.
* Same options as https://github.com/webpack-contrib/postcss-loader#options * Same options as https://github.com/webpack-contrib/postcss-loader#options
@ -283,15 +281,18 @@ export default defineUntypedSchema({
devMiddleware: { devMiddleware: {
stats: 'none' stats: 'none'
}, },
/** /**
* See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options. * 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 }} * @type {typeof import('webpack-hot-middleware').MiddlewareOptions & { client?: typeof import('webpack-hot-middleware').ClientOptions }}
*/ */
hotMiddleware: {}, hotMiddleware: {},
/** /**
* Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). * Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin).
*/ */
friendlyErrors: true, friendlyErrors: true,
/** /**
* Filters to hide build warnings. * Filters to hide build warnings.
* @type {Array<(warn: typeof import('webpack').WebpackError) => boolean>} * @type {Array<(warn: typeof import('webpack').WebpackError) => boolean>}

View File

@ -11,7 +11,6 @@ type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? {
export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> { export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> {
// Avoid DeepPartial for vite config interface (#4772) // Avoid DeepPartial for vite config interface (#4772)
vite?: ConfigSchema['vite'] vite?: ConfigSchema['vite']
[key: string]: any
} }
// TODO: Expose ConfigLayer<T> from c12 // TODO: Expose ConfigLayer<T> from c12

View File

@ -1,43 +1,23 @@
import type { Server as HttpServer, IncomingMessage, ServerResponse } from 'node:http'
import type { Server as HttpsServer } from 'node:https'
import type { Compiler, Configuration, Stats } from 'webpack'
import type { TSConfig } from 'pkg-types' import type { TSConfig } from 'pkg-types'
import type { Server as HttpServer } from 'node:http'
import type { Server as HttpsServer } from 'node:https'
import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite' import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite'
import type { Manifest } from 'vue-bundle-renderer' import type { Manifest } from 'vue-bundle-renderer'
import type { EventHandler } from 'h3' import type { EventHandler } from 'h3'
import type { ModuleContainer } from './module'
import type { NuxtTemplate, Nuxt, NuxtApp, ResolvedNuxtTemplate } from './nuxt'
import type { Import, InlinePreset } from 'unimport' import type { Import, InlinePreset } from 'unimport'
import type { NuxtConfig, NuxtOptions } from './config' import type { Compiler, Configuration, Stats } from 'webpack'
import type { Nuxt, NuxtApp, ResolvedNuxtTemplate } from './nuxt'
import type { Nitro, NitroConfig } from 'nitropack' import type { Nitro, NitroConfig } from 'nitropack'
import type { Component, ComponentsOptions } from './components' import type { Component, ComponentsOptions } from './components'
import { NuxtCompatibility, NuxtCompatibilityIssues } from '..' import { NuxtCompatibility, NuxtCompatibilityIssues } from '..'
export type HookResult = Promise<void> | void
type HookResult = Promise<void> | void
type Builder = any
type Generator = any
type Server = any
type WatchEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'
interface PreloadFile {
asType: 'script' | 'style' | 'font'
extension: string
file: string
fileWithoutQuery: string
}
type RenderResult = {
html: string
cspScriptSrcHashes: string[]
error: any
redirected: boolean
preloadFiles: PreloadFile[]
}
// https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html // https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
export type TSReference = { types: string } | { path: string } export type TSReference = { types: string } | { path: string }
export type WatchEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'
export type NuxtPage = { export type NuxtPage = {
name?: string name?: string
path: string path: string
@ -74,20 +54,29 @@ export interface NuxtHooks {
// Kit // Kit
'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult 'kit:compatibility': (compatibility: NuxtCompatibility, issues: NuxtCompatibilityIssues) => HookResult
// nuxt // Nuxt
'ready': (nuxt: Nuxt) => HookResult
'close': (nuxt: Nuxt) => HookResult
'modules:before': () => HookResult
'modules:done': () => HookResult
'app:resolve': (app: NuxtApp) => HookResult 'app:resolve': (app: NuxtApp) => HookResult
'app:templates': (app: NuxtApp) => HookResult 'app:templates': (app: NuxtApp) => HookResult
'app:templatesGenerated': (app: NuxtApp) => HookResult 'app:templatesGenerated': (app: NuxtApp) => HookResult
'builder:generateApp': (options?: GenerateAppOptions) => HookResult
'pages:extend': (pages: NuxtPage[]) => HookResult 'build:before': () => HookResult
'build:done': () => HookResult
'build:manifest': (manifest: Manifest) => HookResult 'build:manifest': (manifest: Manifest) => HookResult
'builder:generateApp': (options?: GenerateAppOptions) => HookResult
'builder:watch': (event: WatchEvent, path: string) => HookResult
'pages:extend': (pages: NuxtPage[]) => HookResult
'server:devHandler': (handler: EventHandler) => HookResult 'server:devHandler': (handler: EventHandler) => HookResult
// Auto imports // Auto imports
'imports:sources': (presets: ImportPresetWithDeprecation[]) => HookResult
'imports:extend': (imports: Import[]) => HookResult
'imports:dirs': (dirs: string[]) => HookResult
/** @deprecated Please use `imports:sources` hook */ /** @deprecated Please use `imports:sources` hook */
'autoImports:sources': (presets: ImportPresetWithDeprecation[]) => HookResult 'autoImports:sources': (presets: ImportPresetWithDeprecation[]) => HookResult
/** @deprecated Please use `imports:extend` hook */ /** @deprecated Please use `imports:extend` hook */
@ -95,114 +84,39 @@ export interface NuxtHooks {
/** @deprecated Please use `imports:dirs` hook */ /** @deprecated Please use `imports:dirs` hook */
'autoImports:dirs': (dirs: string[]) => HookResult 'autoImports:dirs': (dirs: string[]) => HookResult
'imports:sources': (presets: ImportPresetWithDeprecation[]) => HookResult
'imports:extend': (imports: Import[]) => HookResult
'imports:dirs': (dirs: string[]) => HookResult
// Components // Components
'components:dirs': (dirs: ComponentsOptions['dirs']) => HookResult 'components:dirs': (dirs: ComponentsOptions['dirs']) => HookResult
'components:extend': (components: Component[]) => HookResult 'components:extend': (components: Component[]) => HookResult
// @nuxt/builder // Nitropack
'build:before':
(builder: Builder, buildOptions: NuxtOptions['build']) => HookResult
'builder:prepared': (builder: Builder, buildOptions: NuxtOptions['build']) => HookResult
'builder:extendPlugins': (plugins: NuxtOptions['plugins']) => HookResult
'build:templates': (templates: {
templateVars: Record<string, any>,
templatesFiles: NuxtTemplate[],
resolve: (...args: string[]) => string
}) => HookResult
'build:extendRoutes': (routes: any[], resolve: (...args: string[]) => string) => HookResult
'build:done': (builder: Builder) => HookResult
'watch:restart': (event: { event: string, path: string }) => HookResult
// 'watch:fileChanged': (builder: Builder, fileName: string) => HookResult
'builder:watch': (event: WatchEvent, path: string) => HookResult
// nitropack
'nitro:config': (nitroConfig: NitroConfig) => HookResult 'nitro:config': (nitroConfig: NitroConfig) => HookResult
'nitro:init': (nitro: Nitro) => HookResult 'nitro:init': (nitro: Nitro) => HookResult
'nitro:build:before': (nitro: Nitro) => HookResult 'nitro:build:before': (nitro: Nitro) => HookResult
// @nuxt/cli // Nuxi
'generate:cache:ignore': (ignore: string[]) => HookResult
'config': (options: NuxtConfig) => HookResult
'run:before': (options: { argv: string[], cmd: { name: string, usage: string, description: string, options: Record<string, any> }, rootDir: string }) => HookResult
// nuxi
'build:error': (error: Error) => HookResult 'build:error': (error: Error) => HookResult
'prepare:types': (options: { references: TSReference[], declarations: string[], tsConfig: TSConfig }) => HookResult 'prepare:types': (options: { references: TSReference[], declarations: string[], tsConfig: TSConfig }) => HookResult
// @nuxt/core
'ready': (nuxt: Nuxt) => HookResult
'close': (nuxt: Nuxt) => HookResult
'modules:before': (moduleContainer: ModuleContainer, modules?: any[]) => HookResult
'modules:done': (moduleContainer: ModuleContainer) => HookResult
// 'webpack:done': () => HookResult
// @nuxt/server
'render:before': (server: Server, renderOptions: NuxtOptions['render']) => HookResult
'render:setupMiddleware': (app: any) => HookResult
'render:errorMiddleware': (app: any) => HookResult
'render:done': (server: Server) => HookResult
'listen': (listenerServer: HttpServer | HttpsServer, listener: any) => HookResult 'listen': (listenerServer: HttpServer | HttpsServer, listener: any) => HookResult
'server:nuxt:renderLoading': (req: IncomingMessage, res: ServerResponse) => HookResult
'render:route': (url: string, result: RenderResult, context: any) => HookResult
'render:routeDone': (url: string, result: RenderResult, context: any) => HookResult
'render:beforeResponse': (url: string, result: RenderResult, context: any) => HookResult
// @nuxt/vue-renderer // Vite
'render:resourcesLoaded': (resources: any) => HookResult
'vue-renderer:context': (renderContext: any) => HookResult
'vue-renderer:spa:prepareContext': (renderContext: any) => HookResult
'vue-renderer:spa:templateParams': (templateParams: Record<string, any>) => HookResult
'vue-renderer:ssr:prepareContext': (renderContext: any) => HookResult
'vue-renderer:ssr:context': (renderContext: any) => HookResult
// '_render:context': (nuxt: Nuxt) => HookResult
// 'render:routeContext': (renderContext: any) => HookResult
'vue-renderer:ssr:csp': (cspScriptSrcHashes: string[]) => HookResult
'vue-renderer:ssr:templateParams': (templateParams: Record<string, any>, renderContext: any) => HookResult
// @nuxt/webpack
'webpack:config': (webpackConfigs: Configuration[]) => HookResult
'webpack:devMiddleware': (middleware: (req: IncomingMessage, res: ServerResponse, next: (err?: any) => any) => any) => HookResult
'webpack:hotMiddleware': (middleware: (req: IncomingMessage, res: ServerResponse, next: (err?: any) => any) => any) => HookResult
'server:devMiddleware': (middleware: (req: IncomingMessage, res: ServerResponse, next: (err?: any) => any) => any) => HookResult
'build:compile': (options: { name: string, compiler: Compiler }) => HookResult
'build:compiled': (options: { name: string, compiler: Compiler, stats: Stats }) => HookResult
'build:resources': (mfs?: Compiler['outputFileSystem']) => HookResult
'bundler:change': (shortPath: string) => void
'bundler:error': () => void
'bundler:done': () => void
'bundler:progress': (statesArray: any[]) => void
// @nuxt/generator
'generate:before': (generator: Generator, generateOptions: NuxtOptions['generate']) => HookResult
'generate:distRemoved': (generator: Generator) => HookResult
'generate:distCopied': (generator: Generator) => HookResult
'generate:route': ({ route, setPayload }: { route: any, setPayload: any }) => HookResult
'generate:page': (page: {
route: any,
path: string,
html: string,
exclude: boolean,
errors: string[]
}) => HookResult
'generate:routeCreated': ({ route, path, errors }: { route: any, path: string, errors: any[] }) => HookResult
'generate:extendRoutes': (routes: any[]) => HookResult
'generate:routeFailed': ({ route, errors }: { route: any, errors: any[] }) => HookResult
'generate:manifest': (manifest: any, generator: Generator) => HookResult
'generate:done': (generator: Generator, errors: any[]) => HookResult
'export:before': (generator: Generator) => HookResult
'export:distRemoved': (generator: Generator) => HookResult
'export:distCopied': (generator: Generator) => HookResult
'export:route': ({ route, setPayload }: { route: any, setPayload: any }) => HookResult
'export:routeCreated': ({ route, path, errors }: { route: any, path: string, errors: any[] }) => HookResult
'export:extendRoutes': ({ routes }: { routes: any[] }) => HookResult
'export:routeFailed': ({ route, errors }: { route: any, errors: any[] }) => HookResult
'export:done': (generator: Generator, { errors }: { errors: any[] }) => HookResult
// vite
'vite:extend': (viteBuildContext: { nuxt: Nuxt, config: ViteInlineConfig }) => HookResult 'vite:extend': (viteBuildContext: { nuxt: Nuxt, config: ViteInlineConfig }) => HookResult
'vite:extendConfig': (viteInlineConfig: ViteInlineConfig, env: { isClient: boolean, isServer: boolean }) => HookResult 'vite:extendConfig': (viteInlineConfig: ViteInlineConfig, env: { isClient: boolean, isServer: boolean }) => HookResult
'vite:serverCreated': (viteServer: ViteDevServer, env: { isClient: boolean, isServer: boolean }) => HookResult 'vite:serverCreated': (viteServer: ViteDevServer, env: { isClient: boolean, isServer: boolean }) => HookResult
'vite:compiled': () => HookResult
// Webpack
'webpack:config': (webpackConfigs: Configuration[]) => HookResult
'webpack:compile': (options: { name: string, compiler: Compiler }) => HookResult
'webpack:compiled': (options: { name: string, compiler: Compiler, stats: Stats }) => HookResult
'webpack:change': (shortPath: string) => void
'webpack:error': () => void
'webpack:done': () => void
'webpack:progress': (statesArray: any[]) => void
} }
export type NuxtHookName = keyof NuxtHooks export type NuxtHookName = keyof NuxtHooks

View File

@ -8,6 +8,7 @@ export interface ImportsOptions extends UnimportOptions {
* @default true * @default true
*/ */
autoImport?: boolean autoImport?: boolean
/** /**
* Directories to scan for auto imports. * Directories to scan for auto imports.
* *
@ -15,12 +16,14 @@ export interface ImportsOptions extends UnimportOptions {
* @default ['./composables'] * @default ['./composables']
*/ */
dirs?: string[] dirs?: string[]
/** /**
* Assign auto imported utilities to `globalThis` instead of using built time transformation. * Assign auto imported utilities to `globalThis` instead of using built time transformation.
* *
* @default false * @default false
*/ */
global?: boolean global?: boolean
transform?: { transform?: {
exclude?: RegExp[] exclude?: RegExp[]
include?: RegExp[] include?: RegExp[]

View File

@ -10,7 +10,6 @@ import defu from 'defu'
import type { OutputOptions } from 'rollup' import type { OutputOptions } from 'rollup'
import { defineEventHandler } from 'h3' import { defineEventHandler } from 'h3'
import { cacheDirPlugin } from './plugins/cache-dir' import { cacheDirPlugin } from './plugins/cache-dir'
import { wpfs } from './utils/wpfs'
import type { ViteBuildContext, ViteOptions } from './vite' import type { ViteBuildContext, ViteOptions } from './vite'
import { devStyleSSRPlugin } from './plugins/dev-ssr-css' import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
import { viteNodePlugin } from './vite-node' import { viteNodePlugin } from './vite-node'
@ -89,10 +88,10 @@ export async function buildClient (ctx: ViteBuildContext) {
port: hmrPortDefault, port: hmrPortDefault,
ports: Array.from({ length: 20 }, (_, i) => hmrPortDefault + 1 + i) ports: Array.from({ length: 20 }, (_, i) => hmrPortDefault + 1 + i)
}) })
clientConfig.server = defu(clientConfig.server, <ServerOptions> { clientConfig.server = defu(clientConfig.server, <ServerOptions>{
https: ctx.nuxt.options.server.https, https: ctx.nuxt.options.devServer.https,
hmr: { hmr: {
protocol: ctx.nuxt.options.server.https ? 'wss' : 'ws', protocol: ctx.nuxt.options.devServer.https ? 'wss' : 'ws',
port: hmrPort port: hmrPort
} }
}) })
@ -132,7 +131,7 @@ export async function buildClient (ctx: ViteBuildContext) {
// Build // Build
const start = Date.now() const start = Date.now()
await vite.build(clientConfig) await vite.build(clientConfig)
await ctx.nuxt.callHook('build:resources', wpfs) await ctx.nuxt.callHook('vite:compiled')
logger.info(`Client built in ${Date.now() - start}ms`) logger.info(`Client built in ${Date.now() - start}ms`)
} }
} }

View File

@ -5,7 +5,6 @@ import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
import { logger, resolveModule } from '@nuxt/kit' import { logger, resolveModule } from '@nuxt/kit'
import { joinURL, withoutLeadingSlash, withTrailingSlash } from 'ufo' import { joinURL, withoutLeadingSlash, withTrailingSlash } from 'ufo'
import { ViteBuildContext, ViteOptions } from './vite' import { ViteBuildContext, ViteOptions } from './vite'
import { wpfs } from './utils/wpfs'
import { cacheDirPlugin } from './plugins/cache-dir' import { cacheDirPlugin } from './plugins/cache-dir'
import { initViteNodeServer } from './vite-node' import { initViteNodeServer } from './vite-node'
import { ssrStylesPlugin } from './plugins/ssr-styles' import { ssrStylesPlugin } from './plugins/ssr-styles'
@ -143,7 +142,7 @@ export async function buildServer (ctx: ViteBuildContext) {
await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true }) await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true })
const onBuild = () => ctx.nuxt.callHook('build:resources', wpfs) const onBuild = () => ctx.nuxt.callHook('vite:compiled')
// Production build // Production build
if (!ctx.nuxt.options.dev) { if (!ctx.nuxt.options.dev) {

View File

@ -140,7 +140,7 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
export async function initViteNodeServer (ctx: ViteBuildContext) { export async function initViteNodeServer (ctx: ViteBuildContext) {
// Serialize and pass vite-node runtime options // Serialize and pass vite-node runtime options
const viteNodeServerOptions = { const viteNodeServerOptions = {
baseURL: `${ctx.nuxt.options.server.url}__nuxt_vite_node__`, baseURL: `${ctx.nuxt.options.devServer.url}__nuxt_vite_node__`,
root: ctx.nuxt.options.srcDir, root: ctx.nuxt.options.srcDir,
entryPath: ctx.entry, entryPath: ctx.entry,
base: ctx.ssrServer!.config.base || '/_nuxt/' base: ctx.ssrServer!.config.base || '/_nuxt/'

View File

@ -32,11 +32,7 @@ function clientDevtool (ctx: WebpackConfigContext) {
return return
} }
const scriptPolicy = getCspScriptPolicy(ctx) ctx.config.devtool = 'eval-cheap-module-source-map'
const noUnsafeEval = scriptPolicy && !scriptPolicy.includes('\'unsafe-eval\'')
ctx.config.devtool = noUnsafeEval
? 'cheap-module-source-map'
: 'eval-cheap-module-source-map'
} }
function clientPerformance (ctx: WebpackConfigContext) { function clientPerformance (ctx: WebpackConfigContext) {
@ -94,19 +90,10 @@ function clientPlugins (ctx: WebpackConfigContext) {
analyzerMode: 'static', analyzerMode: 'static',
defaultSizes: 'gzip', defaultSizes: 'gzip',
generateStatsFile: true, generateStatsFile: true,
openAnalyzer: !options.build.quiet, openAnalyzer: true,
reportFilename: resolve(statsDir, `${ctx.name}.html`), reportFilename: resolve(statsDir, `${ctx.name}.html`),
statsFilename: resolve(statsDir, `${ctx.name}.json`), statsFilename: resolve(statsDir, `${ctx.name}.json`),
...options.webpack.analyze === true ? {} : options.webpack.analyze ...options.webpack.analyze === true ? {} : options.webpack.analyze
})) }))
} }
} }
function getCspScriptPolicy (ctx: WebpackConfigContext) {
// TODO
const { csp } = ctx.options.render as any
if (typeof csp === 'object') {
const { policies = {} } = csp
return policies['script-src'] || policies['default-src'] || []
}
}

View File

@ -63,10 +63,7 @@ function basePlugins (ctx: WebpackConfigContext) {
config.plugins.push(new webpack.DefinePlugin(getEnv(ctx))) config.plugins.push(new webpack.DefinePlugin(getEnv(ctx)))
// Friendly errors // Friendly errors
if ( if (ctx.isServer || (ctx.isDev && options.webpack.friendlyErrors)) {
ctx.isServer ||
(ctx.isDev && !options.build.quiet && options.webpack.friendlyErrors)
) {
config.plugins.push( config.plugins.push(
new FriendlyErrorsWebpackPlugin({ new FriendlyErrorsWebpackPlugin({
clearConsole: false, clearConsole: false,
@ -92,23 +89,23 @@ function basePlugins (ctx: WebpackConfigContext) {
// @ts-ignore // @ts-ignore
change: (_, { shortPath }) => { change: (_, { shortPath }) => {
if (!ctx.isServer) { if (!ctx.isServer) {
nuxt.callHook('bundler:change', shortPath) nuxt.callHook('webpack:change', shortPath)
} }
}, },
// @ts-ignore // @ts-ignore
done: ({ state }) => { done: ({ state }) => {
if (state.hasErrors) { if (state.hasErrors) {
nuxt.callHook('bundler:error') nuxt.callHook('webpack:error')
} else { } else {
logger.success(`${state.name} ${state.message}`) logger.success(`${state.name} ${state.message}`)
} }
}, },
allDone: () => { allDone: () => {
nuxt.callHook('bundler:done') nuxt.callHook('webpack:done')
}, },
// @ts-ignore // @ts-ignore
progress ({ statesArray }) { progress ({ statesArray }) {
nuxt.callHook('bundler:progress', statesArray) nuxt.callHook('webpack:progress', statesArray)
} }
} }
})) }))
@ -230,8 +227,6 @@ function getEnv (ctx: WebpackConfigContext) {
'process.env.NODE_ENV': JSON.stringify(ctx.config.mode), 'process.env.NODE_ENV': JSON.stringify(ctx.config.mode),
'process.mode': JSON.stringify(ctx.config.mode), 'process.mode': JSON.stringify(ctx.config.mode),
'process.dev': options.dev, 'process.dev': options.dev,
'process.static': options.target === 'static',
'process.target': JSON.stringify(options.target),
'process.env.VUE_ENV': JSON.stringify(ctx.name), 'process.env.VUE_ENV': JSON.stringify(ctx.name),
'process.browser': ctx.isClient, 'process.browser': ctx.isClient,
'process.client': ctx.isClient, 'process.client': ctx.isClient,
@ -243,10 +238,5 @@ function getEnv (ctx: WebpackConfigContext) {
_env['typeof window'] = _env['typeof document'] = JSON.stringify(!ctx.isServer ? 'object' : 'undefined') _env['typeof window'] = _env['typeof document'] = JSON.stringify(!ctx.isServer ? 'object' : 'undefined')
} }
Object.entries(options.env).forEach(([key, value]) => {
const isNative = ['boolean', 'number'].includes(typeof value)
_env['process.env.' + key] = isNative ? value as string : JSON.stringify(value)
})
return _env return _env
} }

View File

@ -13,7 +13,7 @@ export function registerVirtualModules () {
} }
// Workaround to initialize virtual modules // Workaround to initialize virtual modules
nuxt.hook('build:compile', ({ compiler }) => { nuxt.hook('webpack:compile', ({ compiler }) => {
if (compiler.name === 'server') { writeFiles() } if (compiler.name === 'server') { writeFiles() }
}) })
// Update virtual modules when templates are updated // Update virtual modules when templates are updated

View File

@ -93,9 +93,6 @@ async function createDevMiddleware (compiler: Compiler) {
...hotMiddlewareOptions ...hotMiddlewareOptions
}) })
await nuxt.callHook('webpack:devMiddleware', devMiddleware)
await nuxt.callHook('webpack:hotMiddleware', hotMiddleware)
// Register devMiddleware on server // Register devMiddleware on server
const devHandler = fromNodeMiddleware(devMiddleware as NodeMiddleware) const devHandler = fromNodeMiddleware(devMiddleware as NodeMiddleware)
const hotHandler = fromNodeMiddleware(hotMiddleware as NodeMiddleware) const hotHandler = fromNodeMiddleware(hotMiddleware as NodeMiddleware)
@ -112,13 +109,11 @@ async function compile (compiler: Compiler) {
const { name } = compiler.options const { name } = compiler.options
await nuxt.callHook('build:compile', { name: name!, compiler }) await nuxt.callHook('webpack:compile', { name: name!, compiler })
// Load renderer resources after build // Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => { compiler.hooks.done.tap('load-resources', async (stats) => {
await nuxt.callHook('build:compiled', { name: name!, compiler, stats }) await nuxt.callHook('webpack:compiled', { name: name!, compiler, stats })
// Reload renderer
await nuxt.callHook('build:resources', compiler.outputFileSystem)
}) })
// --- Dev Build --- // --- Dev Build ---
@ -160,7 +155,4 @@ async function compile (compiler: Compiler) {
error.stack = stats.toString('errors-only') error.stack = stats.toString('errors-only')
throw error throw error
} }
// Await for renderer to load resources (programmatic, tests and generate)
await nuxt.callHook('build:resources')
} }

View File

@ -3,6 +3,13 @@ import type { NuxtPage } from '@nuxt/schema'
import { createUnplugin } from 'unplugin' import { createUnplugin } from 'unplugin'
import { withoutLeadingSlash } from 'ufo' import { withoutLeadingSlash } from 'ufo'
// (defined in nuxt/src/core/nitro.ts)
declare module 'nitropack' {
interface NitroRouteConfig {
ssr?: boolean
}
}
export default defineNuxtConfig({ export default defineNuxtConfig({
app: { app: {
pageTransition: true, pageTransition: true,

View File

@ -5,7 +5,7 @@ import type { AppConfig } from '@nuxt/schema'
import type { FetchError } from 'ohmyfetch' import type { FetchError } from 'ohmyfetch'
import { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router' import { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router'
import { defineNuxtConfig } from '~~/../../../packages/nuxt/src' import { defineNuxtConfig } from '~~/../../../packages/nuxt/config'
import type { NavigateToOptions } from '~~/../../../packages/nuxt/dist/app/composables/router' import type { NavigateToOptions } from '~~/../../../packages/nuxt/dist/app/composables/router'
// eslint-disable-next-line import/order // eslint-disable-next-line import/order
import { isVue3 } from '#app' import { isVue3 } from '#app'
@ -107,6 +107,7 @@ describe('modules', () => {
defineNuxtConfig({ sampleModule: { enabled: false } }) defineNuxtConfig({ sampleModule: { enabled: false } })
// @ts-expect-error // @ts-expect-error
defineNuxtConfig({ sampleModule: { other: false } }) defineNuxtConfig({ sampleModule: { other: false } })
// @ts-expect-error
defineNuxtConfig({ undeclaredKey: { other: false } }) defineNuxtConfig({ undeclaredKey: { other: false } })
}) })
}) })