mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
feat: improve typing of config
This commit is contained in:
parent
0d5d854c63
commit
212283837b
@ -254,7 +254,7 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globPathWithExtensions (path) {
|
globPathWithExtensions(path: string) {
|
||||||
return `${path}/**/*.{${this.supportedExtensions.join(',')}}`
|
return `${path}/**/*.{${this.supportedExtensions.join(',')}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ export default class Builder {
|
|||||||
this.resolveMiddleware(templateContext)
|
this.resolveMiddleware(templateContext)
|
||||||
])
|
])
|
||||||
|
|
||||||
await this.resolvePlugins(templateContext)
|
await this.resolvePlugins()
|
||||||
|
|
||||||
this.addOptionalTemplates(templateContext)
|
this.addOptionalTemplates(templateContext)
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ export default class Builder {
|
|||||||
|
|
||||||
async normalizePlugins () {
|
async normalizePlugins () {
|
||||||
// options.extendPlugins allows for returning a new plugins array
|
// options.extendPlugins allows for returning a new plugins array
|
||||||
if (typeof this.options.extendPlugins === 'function') {
|
if (this.options.extendPlugins instanceof Function) {
|
||||||
const extendedPlugins = this.options.extendPlugins(this.options.plugins)
|
const extendedPlugins = this.options.extendPlugins(this.options.plugins)
|
||||||
|
|
||||||
if (Array.isArray(extendedPlugins)) {
|
if (Array.isArray(extendedPlugins)) {
|
||||||
@ -515,7 +515,7 @@ export default class Builder {
|
|||||||
async resolveCustomTemplates (templateContext) {
|
async resolveCustomTemplates (templateContext) {
|
||||||
// Sanitize custom template files
|
// Sanitize custom template files
|
||||||
this.options.build.templates = this.options.build.templates.map((t) => {
|
this.options.build.templates = this.options.build.templates.map((t) => {
|
||||||
const src = t.src || t
|
const src = typeof t === 'string' ? t : t.src
|
||||||
return {
|
return {
|
||||||
src: r(this.options.srcDir, src),
|
src: r(this.options.srcDir, src),
|
||||||
dst: t.dst || path.basename(src),
|
dst: t.dst || path.basename(src),
|
||||||
@ -524,7 +524,7 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const customTemplateFiles = this.options.build.templates.map(t => t.dst || path.basename(t.src || t))
|
const customTemplateFiles = this.options.build.templates.map(t => t.dst || path.basename(typeof t === 'string' ? t : t.src))
|
||||||
|
|
||||||
const templatePaths = uniq([
|
const templatePaths = uniq([
|
||||||
// Modules & user provided templates
|
// Modules & user provided templates
|
||||||
@ -559,7 +559,7 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async resolveLoadingIndicator ({ templateFiles }) {
|
async resolveLoadingIndicator ({ templateFiles }) {
|
||||||
if (!this.options.loadingIndicator.name) {
|
if (typeof this.options.loadingIndicator !== 'object' || !this.options.loadingIndicator.name) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let indicatorPath = path.resolve(
|
let indicatorPath = path.resolve(
|
||||||
@ -707,7 +707,7 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assignWatcher (key) {
|
assignWatcher (key: string) {
|
||||||
return (watcher) => {
|
return (watcher) => {
|
||||||
if (this.watchers[key]) {
|
if (this.watchers[key]) {
|
||||||
this.watchers[key].close()
|
this.watchers[key].close()
|
||||||
@ -731,7 +731,7 @@ export default class Builder {
|
|||||||
patterns.push(r(this.options.srcDir, this.options.dir.pages))
|
patterns.push(r(this.options.srcDir, this.options.dir.pages))
|
||||||
}
|
}
|
||||||
|
|
||||||
patterns = patterns.map((path, ...args) => upath.normalizeSafe(this.globPathWithExtensions(path), ...args))
|
patterns = patterns.map((path) => upath.normalizeSafe(this.globPathWithExtensions(path)))
|
||||||
|
|
||||||
const refreshFiles = debounce(() => this.generateRoutesAndFiles(), 200)
|
const refreshFiles = debounce(() => this.generateRoutesAndFiles(), 200)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import uniqBy from 'lodash/uniqBy'
|
|||||||
import serialize from 'serialize-javascript'
|
import serialize from 'serialize-javascript'
|
||||||
|
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
|
import { NormalizedConfiguration } from 'nuxt/config'
|
||||||
import { r, wp, wChunk, serializeFunction, isFullStatic } from 'nuxt/utils'
|
import { r, wp, wChunk, serializeFunction, isFullStatic } from 'nuxt/utils'
|
||||||
|
|
||||||
import type Builder from '../builder'
|
import type Builder from '../builder'
|
||||||
@ -11,7 +12,7 @@ export default class TemplateContext {
|
|||||||
templateFiles: string[]
|
templateFiles: string[]
|
||||||
templateVars: any
|
templateVars: any
|
||||||
|
|
||||||
constructor (builder: Builder, options) {
|
constructor(builder: Builder, options: NormalizedConfiguration) {
|
||||||
this.templateFiles = Array.from(builder.template.files)
|
this.templateFiles = Array.from(builder.template.files)
|
||||||
this.templateVars = {
|
this.templateVars = {
|
||||||
nuxtOptions: options,
|
nuxtOptions: options,
|
||||||
|
@ -1,21 +1,29 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import ignore from 'ignore'
|
import ignore from 'ignore'
|
||||||
|
import { NormalizedConfiguration } from 'nuxt/config'
|
||||||
|
|
||||||
type IgnoreInstance = ReturnType<typeof ignore>
|
type IgnoreInstance = ReturnType<typeof ignore>
|
||||||
type IgnoreOptions = Parameters<typeof ignore>[0]
|
type IgnoreOptions = Parameters<typeof ignore>[0]
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
rootDir: string
|
||||||
|
ignore?: IgnoreInstance
|
||||||
|
ignoreArray?: Array<string | IgnoreInstance>
|
||||||
|
ignoreOptions?: IgnoreOptions
|
||||||
|
}
|
||||||
|
|
||||||
export default class Ignore {
|
export default class Ignore {
|
||||||
rootDir: string
|
rootDir: string
|
||||||
ignore?: IgnoreInstance
|
ignore?: IgnoreInstance
|
||||||
ignoreArray?: string | string
|
ignoreArray?: Array<string | IgnoreInstance>
|
||||||
ignoreFile?: string
|
ignoreFile?: string
|
||||||
ignoreOptions?: IgnoreOptions
|
ignoreOptions?: IgnoreOptions
|
||||||
|
|
||||||
constructor (options) {
|
constructor ({ ignoreArray, ignoreOptions, rootDir }: Options) {
|
||||||
this.rootDir = options.rootDir
|
this.rootDir = rootDir
|
||||||
this.ignoreOptions = options.ignoreOptions
|
this.ignoreOptions = ignoreOptions
|
||||||
this.ignoreArray = options.ignoreArray
|
this.ignoreArray = ignoreArray
|
||||||
this.addIgnoresRules()
|
this.addIgnoresRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import minimist, { ParsedArgs } from 'minimist'
|
import minimist, { Opts as MinimistOptions, ParsedArgs } from 'minimist'
|
||||||
import Hookable from 'hookable'
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
import { Nuxt } from 'nuxt/core'
|
|
||||||
import { Builder } from 'nuxt/builder'
|
import { Builder } from 'nuxt/builder'
|
||||||
|
import { CliConfiguration } from 'nuxt/config/options'
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
import { Generator } from 'nuxt/generator'
|
import { Generator } from 'nuxt/generator'
|
||||||
import type { Target } from 'nuxt/utils'
|
|
||||||
|
|
||||||
import { name, version } from '../../package.json'
|
import { name, version } from '../../package.json'
|
||||||
|
|
||||||
@ -26,16 +26,6 @@ export interface Command {
|
|||||||
|
|
||||||
type Hooks = Parameters<Hookable['addHooks']>[0]
|
type Hooks = Parameters<Hookable['addHooks']>[0]
|
||||||
|
|
||||||
interface ExtraOptions {
|
|
||||||
_build?: boolean
|
|
||||||
_cli?: boolean
|
|
||||||
_export?: boolean
|
|
||||||
_generate?: boolean
|
|
||||||
_start?: boolean
|
|
||||||
dev?: boolean
|
|
||||||
server?: boolean
|
|
||||||
target?: Target
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class NuxtCommand extends Hookable {
|
export default class NuxtCommand extends Hookable {
|
||||||
_argv: string[]
|
_argv: string[]
|
||||||
@ -133,7 +123,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return this._parsedArgv
|
return this._parsedArgv
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNuxtConfig (extraOptions: ExtraOptions = {}) {
|
async getNuxtConfig(extraOptions: Partial<CliConfiguration> = {}) {
|
||||||
// Flag to indicate nuxt is running with CLI (not programmatic)
|
// Flag to indicate nuxt is running with CLI (not programmatic)
|
||||||
extraOptions._cli = true
|
extraOptions._cli = true
|
||||||
|
|
||||||
@ -154,7 +144,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNuxt (options) {
|
async getNuxt (options: CliConfiguration) {
|
||||||
|
|
||||||
const nuxt = new Nuxt(options)
|
const nuxt = new Nuxt(options)
|
||||||
await nuxt.ready()
|
await nuxt.ready()
|
||||||
@ -166,12 +156,12 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return new Builder(nuxt)
|
return new Builder(nuxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGenerator (nuxt) {
|
async getGenerator (nuxt: Nuxt) {
|
||||||
const builder = await this.getBuilder(nuxt)
|
const builder = await this.getBuilder(nuxt)
|
||||||
return new Generator(nuxt, builder)
|
return new Generator(nuxt, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
async setLock (lockRelease) {
|
async setLock (lockRelease?: () => Promise<any>) {
|
||||||
if (lockRelease) {
|
if (lockRelease) {
|
||||||
if (this._lockRelease) {
|
if (this._lockRelease) {
|
||||||
consola.warn(`A previous unreleased lock was found, this shouldn't happen and is probably an error in 'nuxt ${this.cmd.name}' command. The lock will be removed but be aware of potential strange results`)
|
consola.warn(`A previous unreleased lock was found, this shouldn't happen and is probably an error in 'nuxt ${this.cmd.name}' command. The lock will be removed but be aware of potential strange results`)
|
||||||
@ -200,7 +190,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getMinimistOptions () {
|
_getMinimistOptions () {
|
||||||
const minimistOptions = {
|
const minimistOptions: MinimistOptions = {
|
||||||
alias: {},
|
alias: {},
|
||||||
boolean: [],
|
boolean: [],
|
||||||
string: [],
|
string: [],
|
||||||
@ -225,7 +215,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getHelp () {
|
_getHelp () {
|
||||||
const options = []
|
const options: [string, string][] = []
|
||||||
let maxOptionLength = 0
|
let maxOptionLength = 0
|
||||||
|
|
||||||
for (const name in this.cmd.options) {
|
for (const name in this.cmd.options) {
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import type { ParsedArgs} from 'minimist'
|
||||||
|
|
||||||
|
import { Configuration } from 'nuxt/config/options'
|
||||||
|
|
||||||
|
import NuxtCommand from '../command'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
port: {
|
port: {
|
||||||
alias: 'p',
|
alias: 'p',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'Port number on which to start the application',
|
description: 'Port number on which to start the application',
|
||||||
prepare (cmd, options, argv) {
|
prepare (_cmd: NuxtCommand, options: Configuration, argv: ParsedArgs) {
|
||||||
if (argv.port) {
|
if (argv.port) {
|
||||||
options.server.port = +argv.port
|
options.server.port = +argv.port
|
||||||
}
|
}
|
||||||
@ -15,7 +20,7 @@ export default {
|
|||||||
alias: 'H',
|
alias: 'H',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'Hostname on which to start the application',
|
description: 'Hostname on which to start the application',
|
||||||
prepare (cmd, options, argv) {
|
prepare (_cmd: NuxtCommand, _options: any, argv: ParsedArgs) {
|
||||||
if (argv.hostname === '') {
|
if (argv.hostname === '') {
|
||||||
consola.fatal('Provided hostname argument has no value')
|
consola.fatal('Provided hostname argument has no value')
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,72 @@
|
|||||||
export default () => ({
|
import type { App } from 'vue'
|
||||||
|
import type { MetaInfo, VueMetaOptions } from 'vue-meta'
|
||||||
|
|
||||||
|
type Plugin = string | { mode?: 'all' | 'client' | 'server', src: string, ssr?: boolean }
|
||||||
|
|
||||||
|
interface AppOptions {
|
||||||
|
css: string[]
|
||||||
|
head: MetaInfo
|
||||||
|
ErrorPage: null | string
|
||||||
|
extendPlugins: null | ((plugins: Plugin[]) => Plugin[])
|
||||||
|
features: {
|
||||||
|
store: boolean
|
||||||
|
layouts: boolean
|
||||||
|
meta: boolean
|
||||||
|
middleware: boolean
|
||||||
|
transitions: boolean
|
||||||
|
deprecations: boolean
|
||||||
|
validate: boolean
|
||||||
|
asyncData: boolean
|
||||||
|
fetch: boolean
|
||||||
|
clientOnline: boolean
|
||||||
|
clientPrefetch: boolean
|
||||||
|
clientUseUrl: boolean
|
||||||
|
componentAliases: boolean
|
||||||
|
componentClientOnly: boolean
|
||||||
|
}
|
||||||
|
fetch: {
|
||||||
|
server: boolean
|
||||||
|
client: boolean
|
||||||
|
}
|
||||||
|
layouts: {}
|
||||||
|
layoutTransition: {
|
||||||
|
name: string
|
||||||
|
mode?: string | 'out-in'
|
||||||
|
}
|
||||||
|
loading: string | false | {
|
||||||
|
color?: string
|
||||||
|
continuous?: boolean
|
||||||
|
css?: boolean
|
||||||
|
duration?: number
|
||||||
|
failedColor?: string
|
||||||
|
height?: string
|
||||||
|
rtl?: boolean
|
||||||
|
throttle?: number
|
||||||
|
}
|
||||||
|
loadingIndicator: string | false | {
|
||||||
|
background?: string
|
||||||
|
color?: string
|
||||||
|
color2?: string
|
||||||
|
name?: string
|
||||||
|
}
|
||||||
|
pageTransition: {
|
||||||
|
name: string
|
||||||
|
mode?: string | 'out-in'
|
||||||
|
appear?: boolean
|
||||||
|
appearClass?: string
|
||||||
|
appearActiveClass?: string
|
||||||
|
appearToClass?: string
|
||||||
|
}
|
||||||
|
plugins: Array<Plugin>
|
||||||
|
vue: {
|
||||||
|
config: Partial<App['config']>
|
||||||
|
}
|
||||||
|
vueMeta: null | VueMetaOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): AppOptions => ({
|
||||||
vue: {
|
vue: {
|
||||||
config: {
|
config: {
|
||||||
silent: undefined, // = !dev
|
|
||||||
performance: undefined // = dev
|
performance: undefined // = dev
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -74,3 +139,34 @@ export default () => ({
|
|||||||
componentClientOnly: true
|
componentClientOnly: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// type NormalizedConfiguration<T extends Record<string, any>> = T & {
|
||||||
|
// pageTransition?: Exclude<T['pageTransition'], string>
|
||||||
|
// layoutTransition?: Exclude<T['layoutTransition'], string>
|
||||||
|
// extensions?: Exclude<T['extensions'], string>
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function normalizeAppConfig<O extends Configuration>(options: O): asserts options is NormalizedConfiguration<O> {
|
||||||
|
// (options as NormalizedConfiguration<O>).__normalized__ = true
|
||||||
|
|
||||||
|
// // Normalize options
|
||||||
|
// if (options.loading === true) {
|
||||||
|
// delete options.loading
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (options.router && typeof options.router.base === 'string') {
|
||||||
|
// (options as NormalizedConfiguration<O>)._routerBaseSpecified = true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (typeof options.pageTransition === 'string') {
|
||||||
|
// options.pageTransition = { name: options.pageTransition }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (typeof options.layoutTransition === 'string') {
|
||||||
|
// options.layoutTransition = { name: options.layoutTransition }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (typeof options.extensions === 'string') {
|
||||||
|
// options.extensions = [options.extensions]
|
||||||
|
// }
|
||||||
|
// }
|
@ -1,8 +1,133 @@
|
|||||||
|
import type { WatchOptions as ChokidarWatchOptions } from 'chokidar'
|
||||||
|
import type { NextHandleFunction, Server as ConnectServer } from 'connect'
|
||||||
|
import type { configHooksT } from 'hookable/types/types'
|
||||||
|
import ignore from 'ignore'
|
||||||
import capitalize from 'lodash/capitalize'
|
import capitalize from 'lodash/capitalize'
|
||||||
import env from 'std-env'
|
import env from 'std-env'
|
||||||
import { TARGETS, MODES } from 'nuxt/utils'
|
import type { Configuration as WebpackConfiguration } from 'webpack'
|
||||||
|
|
||||||
export default () => ({
|
import { TARGETS, MODES, Target, Mode } from 'nuxt/utils'
|
||||||
|
|
||||||
|
import type { NormalizedConfiguration } from '../options'
|
||||||
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
|
type IgnoreOptions = Parameters<typeof ignore>[0]
|
||||||
|
type IgnoreInstance = ReturnType<typeof ignore>
|
||||||
|
|
||||||
|
interface ExtendFunctionContext {
|
||||||
|
isClient: boolean
|
||||||
|
isDev: boolean
|
||||||
|
isLegacy: boolean
|
||||||
|
isModern: boolean
|
||||||
|
isServer: boolean
|
||||||
|
// TODO
|
||||||
|
// loaders: NuxtOptionsLoaders
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtendFunction = (config: WebpackConfiguration, ctx: ExtendFunctionContext) => void
|
||||||
|
|
||||||
|
interface NuxtHooks extends configHooksT {
|
||||||
|
|
||||||
|
build?: {
|
||||||
|
before?(builder: any, buildOptions: any): void
|
||||||
|
compile?(params: { name: 'client' | 'server', compiler: any }): void
|
||||||
|
compiled?(params: { name: 'client' | 'server', compiler: any, stats: any }): void
|
||||||
|
done?(builder: any): void
|
||||||
|
extendRoutes?(routes: any, resolve: any): void
|
||||||
|
templates?(params: { templateFiles: any, templateVars: any, resolve: any }): void
|
||||||
|
}
|
||||||
|
close?(nuxt: any): void
|
||||||
|
error?(error: Error): void
|
||||||
|
generate?: {
|
||||||
|
before?(generator: any, generateOptions: any): void
|
||||||
|
distCopied?(generator: any): void
|
||||||
|
distRemoved?(generator: any): void
|
||||||
|
done?(generator: any): void
|
||||||
|
extendRoutes?(routes: any): void
|
||||||
|
page?(params: { route: any, path: any, html: any }): void
|
||||||
|
routeCreated?(route: any, path: any, errors: any): void
|
||||||
|
routeFailed?(route: any, errors: any): void
|
||||||
|
}
|
||||||
|
listen?(server: any, params: { host: string, port: number | string }): void
|
||||||
|
modules?: {
|
||||||
|
before?(moduleContainer: any, options: any): void
|
||||||
|
done?(moduleContainer: any): void
|
||||||
|
}
|
||||||
|
ready?(nuxt: any): void
|
||||||
|
render?: {
|
||||||
|
before?(renderer: any, options: any): void
|
||||||
|
done?(renderer: any): void
|
||||||
|
errorMiddleware?(app: ConnectServer): void
|
||||||
|
resourcesLoaded?(resources: any): void
|
||||||
|
route?(url: string, result: any, context: any): void
|
||||||
|
routeContext?(context: any): void
|
||||||
|
routeDone?(url: string, result: any, context: any): void
|
||||||
|
beforeResponse?(url: string, result: any, context: any): void
|
||||||
|
setupMiddleware?(app: ConnectServer): void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModuleThis {
|
||||||
|
extendBuild(fn: ExtendFunction): void
|
||||||
|
options: NormalizedConfiguration
|
||||||
|
nuxt: any // TBD
|
||||||
|
[key: string]: any // TBD
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModuleHandler<T = any> = (this: ModuleThis, moduleOptions: T) => Promise<void> | void
|
||||||
|
|
||||||
|
export type NuxtModule = string | ModuleHandler | [string | ModuleHandler, any]
|
||||||
|
|
||||||
|
export type ServerMiddleware = string | { path: string, prefix?: boolean, handler: string | NextHandleFunction } | NextHandleFunction
|
||||||
|
|
||||||
|
interface CommonConfiguration {
|
||||||
|
_modules: NuxtModule[]
|
||||||
|
_nuxtConfigFile?: string
|
||||||
|
alias: Record<string, string>
|
||||||
|
buildDir: string
|
||||||
|
buildModules: NuxtModule[]
|
||||||
|
createRequire?: (module: NodeJS.Module) => NodeJS.Require
|
||||||
|
debug?: boolean
|
||||||
|
dev: boolean
|
||||||
|
dir: { [key in 'app' | 'assets' | 'layouts' | 'middleware' | 'pages' | 'static' | 'store']: string }
|
||||||
|
editor: undefined
|
||||||
|
env: NodeJS.ProcessEnv
|
||||||
|
extensions: string[]
|
||||||
|
globalName?: string,
|
||||||
|
globals: {
|
||||||
|
id: (globalName: string) => string
|
||||||
|
nuxt: (globalName: string) => string
|
||||||
|
context: (globalName: string) => string
|
||||||
|
pluginPrefix: (globalName: string) => string
|
||||||
|
readyCallback: (globalName: string) => string
|
||||||
|
loadedCallback: (globalName: string) => string
|
||||||
|
}
|
||||||
|
hooks: null | ((hook: Hookable['hook']) => void) | NuxtHooks
|
||||||
|
ignoreOptions?: IgnoreOptions
|
||||||
|
ignorePrefix: string
|
||||||
|
ignore: Array<string | IgnoreInstance>
|
||||||
|
// TODO: remove in Nuxt 3
|
||||||
|
mode: Mode
|
||||||
|
modern?: boolean
|
||||||
|
modules: NuxtModule[]
|
||||||
|
privateRuntimeConfig: Record<string, any> | ((env: NodeJS.ProcessEnv) => Record<string, any>)
|
||||||
|
publicRuntimeConfig: Record<string, any> | ((env: NodeJS.ProcessEnv) => Record<string, any>)
|
||||||
|
serverMiddleware: Array<ServerMiddleware> | Record<string, NextHandleFunction>
|
||||||
|
ssr: boolean
|
||||||
|
target: Target
|
||||||
|
test: boolean
|
||||||
|
srcDir?: string
|
||||||
|
modulesDir: string[]
|
||||||
|
styleExtensions: string[]
|
||||||
|
watch: string[]
|
||||||
|
watchers: {
|
||||||
|
rewatchOnRawEvents?: boolean
|
||||||
|
webpack: WebpackConfiguration['watchOptions']
|
||||||
|
chokidar: ChokidarWatchOptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): CommonConfiguration => ({
|
||||||
// Env
|
// Env
|
||||||
dev: Boolean(env.dev),
|
dev: Boolean(env.dev),
|
||||||
test: Boolean(env.test),
|
test: Boolean(env.test),
|
||||||
|
@ -1,27 +1,261 @@
|
|||||||
import env from 'std-env'
|
import env from 'std-env'
|
||||||
|
import type { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
|
||||||
|
|
||||||
|
import type { TransformOptions, PluginItem } from '@babel/core'
|
||||||
|
import type { Options as AutoprefixerOptions } from 'autoprefixer'
|
||||||
|
import type { Options as FileLoaderOptions } from 'file-loader'
|
||||||
|
import type { Options as HtmlMinifierOptions } from 'html-minifier'
|
||||||
|
import type * as Less from 'less'
|
||||||
|
import type { Options as SassOptions } from 'node-sass'
|
||||||
|
import type { Options as OptimizeCssAssetsWebpackPluginOptions } from 'optimize-css-assets-webpack-plugin'
|
||||||
|
import type { Plugin as PostcssPlugin } from 'postcss'
|
||||||
|
import type { Options as PugOptions } from 'pug'
|
||||||
|
import type { TerserPluginOptions } from 'terser-webpack-plugin'
|
||||||
|
import type { VueLoaderOptions } from 'vue-loader'
|
||||||
|
import type {
|
||||||
|
Configuration as WebpackConfiguration, WebpackPluginFunction,
|
||||||
|
|
||||||
|
|
||||||
|
} from 'webpack'
|
||||||
|
import type { Options as WebpackDevMiddlewareOptions } from 'webpack-dev-middleware'
|
||||||
|
import type { MiddlewareOptions as WebpackHotMiddlewareOptions, ClientOptions as WebpackHotMiddlewareClientOptions } from 'webpack-hot-middleware'
|
||||||
|
|
||||||
|
|
||||||
|
interface WebpackEnv {
|
||||||
|
isClient: boolean
|
||||||
|
isDev: boolean
|
||||||
|
isLegacy: boolean
|
||||||
|
isModern: boolean
|
||||||
|
isServer: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BabelPresetEnv {
|
||||||
|
envName: 'client' | 'modern' | 'server'
|
||||||
|
}
|
||||||
|
interface Warning {
|
||||||
|
message: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BabelOptions extends Pick<TransformOptions, Exclude<keyof TransformOptions, 'presets' | 'plugins'>> {
|
||||||
|
cacheCompression?: boolean
|
||||||
|
cacheDirectory?: boolean
|
||||||
|
cacheIdentifier?: string
|
||||||
|
customize?: string | null
|
||||||
|
presets?: ((env: BabelPresetEnv & WebpackEnv, defaultPreset: [string, object]) => PluginItem[] | void) | PluginItem[] | null
|
||||||
|
plugins?: ((env: BabelPresetEnv & WebpackEnv) => NonNullable<TransformOptions['plugins']>) | TransformOptions['plugins']
|
||||||
|
}
|
||||||
|
|
||||||
|
type CssLoaderUrlFunction = (url: string, resourcePath: string) => boolean
|
||||||
|
type CssLoaderImportFunction = (parsedImport: string, resourcePath: string) => boolean
|
||||||
|
type CssLoaderMode = 'global' | 'local'
|
||||||
|
interface CssLoaderModulesOptions {
|
||||||
|
context?: string
|
||||||
|
getLocalIdent?: (context: string, localIdentName: string, localName: string, options: CssLoaderModulesOptions) => string
|
||||||
|
hashPrefix?: string
|
||||||
|
localIdentName?: string
|
||||||
|
localIdentRegExp?: string | RegExp
|
||||||
|
mode?: CssLoaderMode
|
||||||
|
}
|
||||||
|
interface CssLoaderOptions {
|
||||||
|
import?: boolean | CssLoaderImportFunction
|
||||||
|
importLoaders?: number
|
||||||
|
localsConvention?: 'asIs' | 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'
|
||||||
|
modules?: boolean | CssLoaderMode | CssLoaderModulesOptions
|
||||||
|
onlyLocals?: boolean
|
||||||
|
sourceMap?: boolean
|
||||||
|
url?: boolean | CssLoaderUrlFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UrlLoaderOptions {
|
||||||
|
esModule?: boolean
|
||||||
|
// TODO
|
||||||
|
fallback?: any // WebpackLoader
|
||||||
|
limit?: boolean | number | string
|
||||||
|
mimetype?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WebpackEnv {
|
||||||
|
isClient: boolean
|
||||||
|
isDev: boolean
|
||||||
|
isLegacy: boolean
|
||||||
|
isModern: boolean
|
||||||
|
isServer: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostcssOrderPresetFunctions {
|
||||||
|
cssnanoLast: (names: string[]) => string[]
|
||||||
|
presetEnvAndCssnanoLast: (names: string[]) => string[]
|
||||||
|
presetEnvLast: (names: string[]) => string[]
|
||||||
|
}
|
||||||
|
type PostcssOrderPreset = keyof PostcssOrderPresetFunctions
|
||||||
|
interface PostcssVariableMap {
|
||||||
|
customMedia: Record<string, string>
|
||||||
|
customProperties: Record<string, string>
|
||||||
|
customSelectors: Record<string, string>
|
||||||
|
environmentVariables?: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface PostcssConfiguration {
|
||||||
|
order?: PostcssOrderPreset | string[] | ((names: string[], presets: PostcssOrderPresetFunctions) => string[])
|
||||||
|
plugins?: {
|
||||||
|
[key: string]: false | { [key: string]: any }
|
||||||
|
} | ((loader: any) => PostcssPlugin<any>[]) | Array<[string | PostcssPlugin<any>, any] | string | PostcssPlugin<any>>
|
||||||
|
preset?: {
|
||||||
|
autoprefixer?: false | AutoprefixerOptions
|
||||||
|
browsers?: string
|
||||||
|
exportTo?: string | string[] | Partial<PostcssVariableMap> | ((map: PostcssVariableMap) => Partial<PostcssVariableMap>)
|
||||||
|
features?: {
|
||||||
|
[key: string]: boolean | { [key: string]: any }
|
||||||
|
}
|
||||||
|
importFrom?: string | string[] | Partial<PostcssVariableMap> | (() => Partial<PostcssVariableMap>)
|
||||||
|
insertAfter?: { [key: string]: PostcssPlugin<any> }
|
||||||
|
insertBefore?: { [key: string]: PostcssPlugin<any> }
|
||||||
|
preserve?: boolean
|
||||||
|
stage?: 0 | 1 | 2 | 3 | 4 | false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VueStyleOptions {
|
||||||
|
manualInject?: boolean
|
||||||
|
ssrId?: boolean
|
||||||
|
shadowMode?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Loaders {
|
||||||
|
css?: CssLoaderOptions
|
||||||
|
cssModules?: CssLoaderOptions
|
||||||
|
file?: FileLoaderOptions
|
||||||
|
fontUrl?: UrlLoaderOptions
|
||||||
|
imgUrl?: UrlLoaderOptions
|
||||||
|
less?: Less.Options
|
||||||
|
pugPlain?: PugOptions
|
||||||
|
sass?: SassOptions
|
||||||
|
scss?: SassOptions
|
||||||
|
stylus?: any // TBD
|
||||||
|
vue?: VueLoaderOptions
|
||||||
|
vueStyle?: {
|
||||||
|
manualInject?: boolean
|
||||||
|
ssrId?: boolean
|
||||||
|
shadowMode?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Template {
|
||||||
|
/**
|
||||||
|
* Source file. Can be absolute or relative.
|
||||||
|
*/
|
||||||
|
src: string,
|
||||||
|
/**
|
||||||
|
* Destination file within `.nuxt` filter. This filename should be relative to the project `.nuxt` dir
|
||||||
|
*/
|
||||||
|
dst: string,
|
||||||
|
/**
|
||||||
|
* Options are provided to template as `options` key
|
||||||
|
*/
|
||||||
|
options?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
export default () => ({
|
export default () => ({
|
||||||
quiet: Boolean(env.ci || env.test),
|
/**
|
||||||
analyze: false,
|
* @private
|
||||||
profile: process.argv.includes('--profile'),
|
*/
|
||||||
extractCSS: false,
|
_publicPath: '/_nuxt/',
|
||||||
cssSourceMap: undefined,
|
|
||||||
ssr: undefined,
|
additionalExtensions: [] as string[],
|
||||||
parallel: false,
|
aggressiveCodeRemoval: false,
|
||||||
|
/**
|
||||||
|
* Use [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) to let you visualize your bundles and how to optimize them.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
analyze: false as boolean | BundleAnalyzerPlugin.Options,
|
||||||
|
babel: {
|
||||||
|
configFile: false,
|
||||||
|
babelrc: false,
|
||||||
|
cacheDirectory: undefined
|
||||||
|
} as BabelOptions,
|
||||||
|
/**
|
||||||
|
* Enable cache of [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin#options) and [cache-loader](https://github.com/webpack-contrib/cache-loader#cache-loader)
|
||||||
|
*
|
||||||
|
* ⚠️ Experimental
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
cache: false,
|
cache: false,
|
||||||
standalone: false,
|
corejs: undefined as undefined | 'auto' | 2 | 3,
|
||||||
publicPath: '/_nuxt/',
|
crossorigin: undefined as undefined | string,
|
||||||
serverURLPolyfill: 'url',
|
/**
|
||||||
|
* Enables CSS Source Map support.
|
||||||
|
* @default true for dev and `false` for production
|
||||||
|
*/
|
||||||
|
cssSourceMap: undefined as undefined | boolean,
|
||||||
|
devMiddleware: {} as WebpackDevMiddlewareOptions,
|
||||||
|
devtools: undefined as undefined | boolean,
|
||||||
|
extend: null as null | ((
|
||||||
|
config: WebpackConfiguration,
|
||||||
|
ctx: {
|
||||||
|
loaders: Loaders
|
||||||
|
} & WebpackEnv
|
||||||
|
) => void),
|
||||||
|
/**
|
||||||
|
* Enables Common CSS Extraction using Vue Server Renderer guidelines.
|
||||||
|
*
|
||||||
|
* Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, all your CSS will be extracted into separate files, usually one per component. This allows caching your CSS and JavaScript separately and is worth a try in case you have a lot of global or shared CSS.
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
extractCSS: false as boolean | Record<string, any>,
|
||||||
|
/**
|
||||||
|
* Customize bundle filenames.
|
||||||
|
*/
|
||||||
filenames: {
|
filenames: {
|
||||||
// { isDev, isClient, isServer }
|
app: ({ isDev, isModern }: WebpackEnv) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
|
||||||
app: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
|
chunk: ({ isDev, isModern }: WebpackEnv) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
|
||||||
chunk: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
|
css: ({ isDev }: WebpackEnv) => isDev ? '[name].css' : '[name].[contenthash:7].css',
|
||||||
css: ({ isDev }) => isDev ? '[name].css' : '[name].[contenthash:7].css',
|
img: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
|
||||||
img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
|
font: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
|
||||||
font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
|
video: ({ isDev }: WebpackEnv) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
|
||||||
video: ({ isDev }) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
|
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* By default, the build process does not scan files inside symlinks. This boolean includes them, thus allowing usage of symlinks inside folders such as the "pages" folder, for example.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
followSymlinks: false,
|
||||||
|
/**
|
||||||
|
* Enables or disables the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin)
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
friendlyErrors: true,
|
||||||
|
hardSource: false,
|
||||||
|
hotMiddleware: {} as WebpackHotMiddlewareOptions & { client?: WebpackHotMiddlewareClientOptions },
|
||||||
|
html: {
|
||||||
|
/**
|
||||||
|
* Configuration for the [html-minifier plugin](https://github.com/kangax/html-minifier) used to minify HTML files created during the build process (will be applied for all modes).
|
||||||
|
*/
|
||||||
|
minify: {
|
||||||
|
collapseBooleanAttributes: true,
|
||||||
|
decodeEntities: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyJS: true,
|
||||||
|
processConditionalComments: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
trimCustomFragments: true,
|
||||||
|
useShortDoctype: true
|
||||||
|
}
|
||||||
|
} as { minify: HtmlMinifierOptions },
|
||||||
|
indicator: {
|
||||||
|
position: 'bottom-right',
|
||||||
|
backgroundColor: '#2E495E',
|
||||||
|
color: '#00C48D'
|
||||||
|
} as boolean | { position: string, backgroundColor: string, color: string },
|
||||||
|
/**
|
||||||
|
* Customize options of Nuxt.js integrated webpack loaders.
|
||||||
|
*/
|
||||||
loaders: {
|
loaders: {
|
||||||
|
/**
|
||||||
|
* Mor details at https://github.com/webpack-contrib/file-loader#options
|
||||||
|
*/
|
||||||
file: {},
|
file: {},
|
||||||
fontUrl: { limit: 1000 },
|
fontUrl: { limit: 1000 },
|
||||||
imgUrl: { limit: 1000 },
|
imgUrl: { limit: 1000 },
|
||||||
@ -47,18 +281,14 @@ export default () => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
scss: {},
|
scss: {},
|
||||||
|
// tODO
|
||||||
stylus: {},
|
stylus: {},
|
||||||
vueStyle: {}
|
vueStyle: {}
|
||||||
},
|
} as Loaders,
|
||||||
styleResources: {},
|
loadingScreen: {} as Record<string, any> | false,
|
||||||
plugins: [],
|
|
||||||
terser: {},
|
|
||||||
hardSource: false,
|
|
||||||
aggressiveCodeRemoval: false,
|
|
||||||
optimizeCSS: undefined,
|
|
||||||
optimization: {
|
optimization: {
|
||||||
runtimeChunk: 'single',
|
runtimeChunk: 'single',
|
||||||
minimize: undefined,
|
minimize: undefined as boolean | undefined,
|
||||||
minimizer: undefined,
|
minimizer: undefined,
|
||||||
splitChunks: {
|
splitChunks: {
|
||||||
chunks: 'all',
|
chunks: 'all',
|
||||||
@ -69,62 +299,87 @@ export default () => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
} as WebpackConfiguration['optimization'],
|
||||||
splitChunks: {
|
optimizeCSS: undefined as undefined | OptimizeCssAssetsWebpackPluginOptions | boolean,
|
||||||
layouts: false,
|
/**
|
||||||
pages: true,
|
* Enable [thread-loader](https://github.com/webpack-contrib/thread-loader#thread-loader) in webpack building
|
||||||
commons: true
|
*
|
||||||
},
|
* ⚠️ Experimental
|
||||||
babel: {
|
* @default false
|
||||||
configFile: false,
|
*/
|
||||||
babelrc: false,
|
parallel: false,
|
||||||
cacheDirectory: undefined
|
plugins: [] as WebpackPluginFunction[],
|
||||||
},
|
|
||||||
transpile: [], // Name of NPM packages to be transpiled
|
|
||||||
postcss: {
|
postcss: {
|
||||||
preset: {
|
preset: {
|
||||||
// https://cssdb.org/#staging-process
|
// https://cssdb.org/#staging-process
|
||||||
stage: 2
|
stage: 2
|
||||||
}
|
}
|
||||||
},
|
} as string[] | boolean | PostcssConfiguration | (() => PostcssConfiguration),
|
||||||
html: {
|
/**
|
||||||
minify: {
|
* Enable the profiler in [WebpackBar](https://github.com/nuxt/webpackbar#profile)
|
||||||
collapseBooleanAttributes: true,
|
* @default false unless enabled by command line argument `--profile`
|
||||||
decodeEntities: true,
|
*/
|
||||||
minifyCSS: true,
|
profile: process.argv.includes('--profile'),
|
||||||
minifyJS: true,
|
/**
|
||||||
processConditionalComments: true,
|
* Nuxt.js lets you upload your dist files to your CDN for maximum performances, simply set the `publicPath` to your CDN.
|
||||||
removeEmptyAttributes: true,
|
* @default '/_nuxt/'
|
||||||
removeRedundantAttributes: true,
|
* @example
|
||||||
trimCustomFragments: true,
|
```
|
||||||
useShortDoctype: true
|
export default {
|
||||||
|
build: {
|
||||||
|
publicPath: 'https://cdn.nuxtjs.org'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Then, when launching nuxt build, upload the content of .nuxt/dist/client directory to your CDN and voilà!
|
||||||
|
*/
|
||||||
|
publicPath: '/_nuxt/',
|
||||||
|
/**
|
||||||
|
* Suppresses most of the build output log
|
||||||
|
* @default true when a CI or test environment is detected by [std-env](https://github.com/nuxt-contrib/std-env)
|
||||||
|
*/
|
||||||
|
quiet: Boolean(env.ci || env.test),
|
||||||
|
/**
|
||||||
|
* @default 'url'
|
||||||
|
*/
|
||||||
|
serverURLPolyfill: 'url',
|
||||||
|
splitChunks: {
|
||||||
|
layouts: false,
|
||||||
|
pages: true,
|
||||||
|
commons: true
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
template: undefined,
|
* Creates special webpack bundle for SSR renderer.
|
||||||
templates: [],
|
* @default true for universal mode and `false` for spa mode
|
||||||
|
*/
|
||||||
watch: [],
|
ssr: undefined as undefined | boolean,
|
||||||
devMiddleware: {},
|
/**
|
||||||
hotMiddleware: {},
|
*
|
||||||
|
*/
|
||||||
|
standalone: false,
|
||||||
stats: {
|
stats: {
|
||||||
excludeAssets: [
|
excludeAssets: [
|
||||||
/.map$/,
|
/.map$/,
|
||||||
/index\..+\.html$/,
|
/index\..+\.html$/,
|
||||||
/vue-ssr-(client|modern)-manifest.json/
|
/vue-ssr-(client|modern)-manifest.json/
|
||||||
]
|
]
|
||||||
},
|
} as 'none' | false | { excludeAssets: RegExp[] },
|
||||||
friendlyErrors: true,
|
styleResources: {},
|
||||||
additionalExtensions: [],
|
template: undefined,
|
||||||
warningIgnoreFilters: [],
|
/**
|
||||||
|
* Nuxt.js allows you provide your own templates which will be rendered based on Nuxt configuration. This feature is specially useful for using with modules.
|
||||||
|
*/
|
||||||
|
templates: [] as Template[],
|
||||||
|
/**
|
||||||
|
* Terser plugin options. Set to `false` to disable this plugin. See https://github.com/webpack-contrib/terser-webpack-plugin
|
||||||
|
*/
|
||||||
|
terser: {} as TerserPluginOptions | boolean,
|
||||||
|
// Name of NPM packages to be transpiled
|
||||||
|
transpile: [] as Array<string | RegExp | ((context: WebpackEnv) => string | RegExp | undefined)>,
|
||||||
|
warningIgnoreFilters: [] as Array<(warn: Warning) => boolean>,
|
||||||
|
/**
|
||||||
|
* You can provide your custom files to watch and regenerate after changes. This feature is specially useful for using with modules.
|
||||||
|
*/
|
||||||
|
watch: [] as string[],
|
||||||
|
|
||||||
followSymlinks: false,
|
|
||||||
|
|
||||||
loadingScreen: {},
|
|
||||||
indicator: {
|
|
||||||
position: 'bottom-right',
|
|
||||||
backgroundColor: '#2E495E',
|
|
||||||
color: '#00C48D'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
export default () => ({
|
import { Color } from 'chalk'
|
||||||
|
|
||||||
|
export interface CliOptions {
|
||||||
|
badgeMessages: string[]
|
||||||
|
bannerColor: typeof Color
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): CliOptions => ({
|
||||||
badgeMessages: [],
|
badgeMessages: [],
|
||||||
bannerColor: 'green'
|
bannerColor: 'green'
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,33 @@
|
|||||||
|
import { GlobbyOptions } from 'globby'
|
||||||
|
|
||||||
export default () => ({
|
type GenerateRoute = string | { route: string, payload: any }
|
||||||
|
|
||||||
|
type GenerateRoutesFunction = () => (Promise<GenerateRoute[]> | GenerateRoute[])
|
||||||
|
type GenerateRoutesFunctionWithCallback = (callback: (err: Error, routes: GenerateRoute[]) => void) => void
|
||||||
|
|
||||||
|
export interface GenerateOptions {
|
||||||
|
cache?: false | {
|
||||||
|
ignore?: string[] | Function,
|
||||||
|
globbyOptions?: GlobbyOptions
|
||||||
|
}
|
||||||
|
concurrency: number
|
||||||
|
crawler: boolean
|
||||||
|
devtools?: boolean
|
||||||
|
dir: string
|
||||||
|
exclude: RegExp[]
|
||||||
|
fallback: boolean | string
|
||||||
|
interval: number
|
||||||
|
routes: GenerateRoute[] | GenerateRoutesFunction | GenerateRoutesFunctionWithCallback
|
||||||
|
staticAssets: {
|
||||||
|
base?: string
|
||||||
|
versionBase?: string
|
||||||
|
dir?: string
|
||||||
|
version?: string
|
||||||
|
}
|
||||||
|
subFolders: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): GenerateOptions => ({
|
||||||
dir: 'dist',
|
dir: 'dist',
|
||||||
routes: [],
|
routes: [],
|
||||||
exclude: [],
|
exclude: [],
|
||||||
|
@ -9,16 +9,12 @@ import render from './render'
|
|||||||
import router from './router'
|
import router from './router'
|
||||||
import server from './server'
|
import server from './server'
|
||||||
import cli from './cli'
|
import cli from './cli'
|
||||||
import generate from './generate'
|
import generate, { GenerateOptions } from './generate'
|
||||||
|
|
||||||
export const defaultNuxtConfigFile = 'nuxt.config'
|
export const defaultNuxtConfigFile = 'nuxt.config'
|
||||||
|
|
||||||
export function getDefaultNuxtConfig (options = {}) {
|
export const getDefaultNuxtConfig = () =>
|
||||||
if (!options.env) {
|
({
|
||||||
options.env = process.env
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
..._app(),
|
..._app(),
|
||||||
..._common(),
|
..._common(),
|
||||||
build: build(),
|
build: build(),
|
||||||
@ -26,8 +22,11 @@ export function getDefaultNuxtConfig (options = {}) {
|
|||||||
modes: modes(),
|
modes: modes(),
|
||||||
render: render(),
|
render: render(),
|
||||||
router: router(),
|
router: router(),
|
||||||
server: server(options),
|
server: server({ env: process.env }) as ReturnType<typeof server> | boolean,
|
||||||
cli: cli(),
|
cli: cli(),
|
||||||
generate: generate()
|
generate: generate(),
|
||||||
}
|
export: undefined as undefined | GenerateOptions,
|
||||||
}
|
telemetry: undefined as undefined | boolean,
|
||||||
|
})
|
||||||
|
|
||||||
|
export type DefaultConfiguration = ReturnType<typeof getDefaultNuxtConfig>
|
@ -8,7 +8,7 @@ export default () => ({
|
|||||||
render: {
|
render: {
|
||||||
ssr: true
|
ssr: true
|
||||||
}
|
}
|
||||||
},
|
} as const,
|
||||||
[MODES.spa]: {
|
[MODES.spa]: {
|
||||||
build: {
|
build: {
|
||||||
ssr: false
|
ssr: false
|
||||||
@ -16,5 +16,5 @@ export default () => ({
|
|||||||
render: {
|
render: {
|
||||||
ssr: false
|
ssr: false
|
||||||
}
|
}
|
||||||
}
|
} as const
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,75 @@
|
|||||||
// TODO: Refactor @nuxt/server related options into `server.js`
|
// TODO: Refactor @nuxt/server related options into `server.js`
|
||||||
|
import type { ServerResponse } from 'http'
|
||||||
|
import type { Options as EtagOptions } from 'etag'
|
||||||
|
import type { IncomingMessage } from 'connect'
|
||||||
|
import type { CompressionOptions } from 'compression'
|
||||||
|
import type { ServeStaticOptions } from 'serve-static'
|
||||||
|
import type { ServerMiddleware } from './_common'
|
||||||
|
|
||||||
export default () => ({
|
interface PreloadFile {
|
||||||
|
asType: 'script' | 'style' | 'font'
|
||||||
|
extension: string
|
||||||
|
file: string
|
||||||
|
fileWithoutQuery: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServePlaceholderHandler = 'default' | 'css' | 'html' | 'js' | 'json' | 'map' | 'plain' | 'image'
|
||||||
|
interface ServePlaceholderOptions {
|
||||||
|
handlers?: Record<string, ServePlaceholderHandler | null | false>
|
||||||
|
mimes?: Record<ServePlaceholderHandler, string | false | undefined>
|
||||||
|
noCache?: boolean
|
||||||
|
placeholders?: Record<ServePlaceholderHandler, string | Buffer | false>
|
||||||
|
skipUnknown?: boolean
|
||||||
|
statusCode?: false | number
|
||||||
|
}
|
||||||
|
|
||||||
|
type CspPolicyName = 'child-src' | 'connect-src' | 'default-src' | 'font-src' | 'frame-src' | 'img-src' | 'manifest-src' | 'media-src' | 'object-src' | 'prefetch-src' | 'script-src' | 'script-src-elem' | 'script-src-attr' | 'style-src' | 'style-src-elem' | 'style-src-attr' | 'worker-src' | 'base-uri' | 'plugin-types' | 'sandbox' | 'form-action' | 'frame-ancestors' | 'navigate-to' | 'report-uri' | 'report-to' | 'block-all-mixed-content' | 'referrer' | 'require-sri-for' | 'trusted-types' | 'upgrade-insecure-requests'
|
||||||
|
|
||||||
|
interface RenderOptions {
|
||||||
|
bundleRenderer: {
|
||||||
|
shouldPrefetch: () => boolean
|
||||||
|
shouldPreload: (fileWithoutQuery: string, asType: string) => boolean
|
||||||
|
runInNewContext?: boolean
|
||||||
|
}
|
||||||
|
compressor: CompressionOptions | ServerMiddleware | false
|
||||||
|
crossorigin?: 'anonymous' | 'use-credentials' | ''
|
||||||
|
csp: boolean | {
|
||||||
|
addMeta?: boolean
|
||||||
|
allowedSources?: string[]
|
||||||
|
hashAlgorithm?: string
|
||||||
|
policies?: Record<CspPolicyName, string[]>
|
||||||
|
reportOnly?: boolean
|
||||||
|
unsafeInlineCompatibility?: boolean
|
||||||
|
}
|
||||||
|
dist: ServeStaticOptions
|
||||||
|
etag: false | EtagOptions & {
|
||||||
|
hash?: (html: string) => string
|
||||||
|
}
|
||||||
|
fallback?: {
|
||||||
|
dist?: ServePlaceholderOptions
|
||||||
|
static?: ServePlaceholderOptions
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
gzip?: CompressionOptions | ServerMiddleware | false
|
||||||
|
http2?: {
|
||||||
|
push?: boolean
|
||||||
|
shouldPush?: boolean | null
|
||||||
|
pushAssets?: null | ((
|
||||||
|
req: IncomingMessage,
|
||||||
|
res: ServerResponse,
|
||||||
|
publicPath: string,
|
||||||
|
preloadFiles: PreloadFile[]
|
||||||
|
) => string[])
|
||||||
|
}
|
||||||
|
resourceHints: boolean
|
||||||
|
ssr?: boolean
|
||||||
|
ssrLog?: boolean | 'collapsed'
|
||||||
|
static: ServeStaticOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): RenderOptions => ({
|
||||||
bundleRenderer: {
|
bundleRenderer: {
|
||||||
shouldPrefetch: () => false,
|
shouldPrefetch: () => false,
|
||||||
shouldPreload: (fileWithoutQuery, asType) => ['script', 'style'].includes(asType),
|
shouldPreload: (fileWithoutQuery, asType) => ['script', 'style'].includes(asType),
|
||||||
@ -15,9 +84,7 @@ export default () => ({
|
|||||||
shouldPush: null,
|
shouldPush: null,
|
||||||
pushAssets: null
|
pushAssets: null
|
||||||
},
|
},
|
||||||
static: {
|
static: {},
|
||||||
prefix: true
|
|
||||||
},
|
|
||||||
compressor: {
|
compressor: {
|
||||||
threshold: 0
|
threshold: 0
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,36 @@
|
|||||||
export default () => ({
|
import { RouteRecordRaw, ScrollBehavior } from 'vue-router'
|
||||||
|
|
||||||
|
type UnionToIntersection<T> = (T extends any ? (k: T) => void : never) extends ((k: infer U) => void) ? U : never
|
||||||
|
type RouteConfig = UnionToIntersection<RouteRecordRaw>
|
||||||
|
|
||||||
|
export interface Route extends Pick<RouteConfig, Exclude<keyof RouteConfig, 'children' | 'component'>> {
|
||||||
|
children?: Route[]
|
||||||
|
chunkName?: string
|
||||||
|
chunkNames?: Record<string, string>
|
||||||
|
component?: RouteConfig['component'] | string
|
||||||
|
}
|
||||||
|
interface Middleware { }
|
||||||
|
|
||||||
|
export interface RouterConfigurationNormalized {
|
||||||
|
base: string
|
||||||
|
extendRoutes?(routes: Route[], resolve: (...pathSegments: string[]) => string): void
|
||||||
|
fallback: boolean
|
||||||
|
linkActiveClass: string | false
|
||||||
|
linkExactActiveClass: string | false
|
||||||
|
linkPrefetchedClass: string | false
|
||||||
|
middleware: Middleware[]
|
||||||
|
mode: 'history' | 'hash'
|
||||||
|
parseQuery: boolean
|
||||||
|
prefetchLinks: boolean
|
||||||
|
prefetchPayloads: boolean
|
||||||
|
routes: Route[]
|
||||||
|
routeNameSplitter: string
|
||||||
|
scrollBehavior: null | ScrollBehavior
|
||||||
|
stringifyQuery: boolean
|
||||||
|
trailingSlash?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): RouterConfigurationNormalized => ({
|
||||||
mode: 'history',
|
mode: 'history',
|
||||||
base: '/',
|
base: '/',
|
||||||
routes: [],
|
routes: [],
|
||||||
|
@ -1,5 +1,19 @@
|
|||||||
export default ({ env = {} } = {}) => ({
|
export interface ServerProcessEnv extends NodeJS.ProcessEnv {
|
||||||
https: false,
|
NUXT_HOST?: string
|
||||||
|
NUXT_PORT?: string
|
||||||
|
HOST?: string
|
||||||
|
PORT?: string
|
||||||
|
UNIX_SOCKET?: string
|
||||||
|
npm_package_config_nuxt_port?: string
|
||||||
|
npm_package_config_nuxt_host?: string
|
||||||
|
npm_package_config_unix_socket?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ env = {} }: { env?: ServerProcessEnv } = {}) => ({
|
||||||
|
https: false as false | {
|
||||||
|
cert?: string | Buffer
|
||||||
|
key?: string | Buffer
|
||||||
|
},
|
||||||
port: env.NUXT_PORT ||
|
port: env.NUXT_PORT ||
|
||||||
env.PORT ||
|
env.PORT ||
|
||||||
env.npm_package_config_nuxt_port ||
|
env.npm_package_config_nuxt_port ||
|
||||||
@ -10,5 +24,5 @@ export default ({ env = {} } = {}) => ({
|
|||||||
'localhost',
|
'localhost',
|
||||||
socket: env.UNIX_SOCKET ||
|
socket: env.UNIX_SOCKET ||
|
||||||
env.npm_package_config_unix_socket,
|
env.npm_package_config_unix_socket,
|
||||||
timing: false
|
timing: false as false | { total: boolean }
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export { defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
|
export { defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
|
||||||
export { getNuxtConfig } from './options'
|
export { getNuxtConfig, Configuration, NormalizedConfiguration } from './options'
|
||||||
export { loadNuxtConfig } from './load'
|
export { loadNuxtConfig } from './load'
|
||||||
|
@ -11,10 +11,15 @@ import * as rc from 'rc9'
|
|||||||
|
|
||||||
import { LoadOptions } from 'nuxt/core/load'
|
import { LoadOptions } from 'nuxt/core/load'
|
||||||
import { defaultNuxtConfigFile } from './config'
|
import { defaultNuxtConfigFile } from './config'
|
||||||
|
import { CliConfiguration, Configuration } from 'nuxt/config/options'
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const isJest = typeof jest !== 'undefined'
|
const isJest = typeof jest !== 'undefined'
|
||||||
|
|
||||||
|
const interopDefault = (obj: any) => {
|
||||||
|
return 'default' in obj ? obj.default : obj
|
||||||
|
}
|
||||||
|
|
||||||
export interface EnvConfig {
|
export interface EnvConfig {
|
||||||
dotenv?: string
|
dotenv?: string
|
||||||
env?: NodeJS.ProcessEnv & { _applied?: boolean }
|
env?: NodeJS.ProcessEnv & { _applied?: boolean }
|
||||||
@ -31,7 +36,7 @@ export async function loadNuxtConfig ({
|
|||||||
}: LoadOptions = {}) {
|
}: LoadOptions = {}) {
|
||||||
rootDir = path.resolve(rootDir)
|
rootDir = path.resolve(rootDir)
|
||||||
|
|
||||||
let options = {}
|
let options: CliConfiguration = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
configFile = require.resolve(path.resolve(rootDir, configFile))
|
configFile = require.resolve(path.resolve(rootDir, configFile))
|
||||||
@ -66,17 +71,11 @@ export async function loadNuxtConfig ({
|
|||||||
// Clear cache
|
// Clear cache
|
||||||
clearRequireCache(configFile)
|
clearRequireCache(configFile)
|
||||||
const _require = createRequire(module)
|
const _require = createRequire(module)
|
||||||
options = _require(configFile) || {}
|
let _config: Configuration | ((ctx: Record<string, any>) => Promise<Configuration>) = interopDefault(_require(configFile) || {})
|
||||||
if (options.default) {
|
|
||||||
options = options.default
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options === 'function') {
|
if (typeof _config === 'function') {
|
||||||
try {
|
try {
|
||||||
options = await options(configContext)
|
options = interopDefault(await _config(configContext))
|
||||||
if (options.default) {
|
|
||||||
options = options.default
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
consola.error(error)
|
consola.error(error)
|
||||||
consola.fatal('Error while fetching async configuration')
|
consola.fatal('Error while fetching async configuration')
|
||||||
|
@ -1,97 +1,104 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import defaultsDeep from 'lodash/defaultsDeep'
|
import consola from 'consola'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
|
import destr from 'destr'
|
||||||
|
import defaultsDeep from 'lodash/defaultsDeep'
|
||||||
import pick from 'lodash/pick'
|
import pick from 'lodash/pick'
|
||||||
import uniq from 'lodash/uniq'
|
import uniq from 'lodash/uniq'
|
||||||
import consola from 'consola'
|
|
||||||
import destr from 'destr'
|
|
||||||
import { TARGETS, MODES, guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule, urlJoin, getPKG } from 'nuxt/utils'
|
|
||||||
import { defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
|
|
||||||
|
|
||||||
export function getNuxtConfig (_options) {
|
import { TARGETS, MODES, guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule, urlJoin, getPKG, Target, Mode } from 'nuxt/utils'
|
||||||
|
|
||||||
|
import { DefaultConfiguration, defaultNuxtConfigFile, getDefaultNuxtConfig } from './config'
|
||||||
|
import { deleteProp, mergeConfigs, setProp, overrideProp, Optional } from './transformers'
|
||||||
|
import type { EnvConfig } from 'nuxt/config/load'
|
||||||
|
|
||||||
|
interface InputConfiguration {
|
||||||
|
appTemplatePath?: string
|
||||||
|
layoutTransition?: string | DefaultConfiguration['layoutTransition']
|
||||||
|
loading?: true | false | DefaultConfiguration['loading']
|
||||||
|
manifest?: {
|
||||||
|
theme_color?: string
|
||||||
|
}
|
||||||
|
pageTransition?: string | DefaultConfiguration['pageTransition']
|
||||||
|
rootDir?: string
|
||||||
|
store?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Configuration extends InputConfiguration, Optional<Omit<DefaultConfiguration, keyof InputConfiguration>> { }
|
||||||
|
|
||||||
|
export interface CliConfiguration extends Configuration {
|
||||||
|
// cli
|
||||||
|
_build?: boolean
|
||||||
|
_cli?: boolean
|
||||||
|
_export?: boolean
|
||||||
|
_generate?: boolean
|
||||||
|
_start?: boolean
|
||||||
|
_ready?: boolean
|
||||||
|
_legacyGenerate?: boolean
|
||||||
|
_env?: NodeJS.ProcessEnv
|
||||||
|
_envConfig?: EnvConfig
|
||||||
|
_nuxtConfigFiles?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNuxtConfig(_options: Configuration) {
|
||||||
// Prevent duplicate calls
|
// Prevent duplicate calls
|
||||||
if (_options.__normalized__) {
|
if ('__normalized__' in _options) {
|
||||||
return _options
|
return _options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return normalizeConfig(_options as CliConfiguration)
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeConfig(_options: CliConfiguration) {
|
||||||
// Clone options to prevent unwanted side-effects
|
// Clone options to prevent unwanted side-effects
|
||||||
const options = Object.assign({}, _options)
|
const _config: CliConfiguration = Object.assign({}, _options)
|
||||||
options.__normalized__ = true
|
|
||||||
|
setProp(_config, '__normalized__', true as const)
|
||||||
|
|
||||||
// Normalize options
|
// Normalize options
|
||||||
if (options.loading === true) {
|
if (_config.loading === true) {
|
||||||
delete options.loading
|
deleteProp(_config, 'loading')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
setProp(_config, '_routerBaseSpecified', _config.router && typeof _config.router.base === 'string')
|
||||||
options.router &&
|
|
||||||
options.router.middleware &&
|
overrideProp(_config, 'pageTransition', typeof _config.pageTransition === 'string' ? { name: _config.pageTransition } : _config.pageTransition)
|
||||||
!Array.isArray(options.router.middleware)
|
overrideProp(_config, 'layoutTransition', typeof _config.layoutTransition === 'string' ? { name: _config.layoutTransition } : _config.layoutTransition)
|
||||||
) {
|
|
||||||
options.router.middleware = [options.router.middleware]
|
if (typeof _config.extensions === 'string') {
|
||||||
|
_config.extensions = [_config.extensions]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.router && typeof options.router.base === 'string') {
|
overrideProp(_config, 'globalName',
|
||||||
options._routerBaseSpecified = true
|
(isNonEmptyString(_config.globalName) && /^[a-zA-Z]+$/.test(_config.globalName))
|
||||||
}
|
? _config.globalName.toLowerCase()
|
||||||
|
|
||||||
// TODO: Remove for Nuxt 3
|
|
||||||
// router.scrollBehavior -> app/router.scrollBehavior.js
|
|
||||||
if (options.router && typeof options.router.scrollBehavior !== 'undefined') {
|
|
||||||
consola.warn('`router.scrollBehavior` property is deprecated in favor of using `~/app/router.scrollBehavior.js` file, learn more: https://nuxtjs.org/api/configuration-router#scrollbehavior')
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove for Nuxt 3
|
|
||||||
// transition -> pageTransition
|
|
||||||
if (typeof options.transition !== 'undefined') {
|
|
||||||
consola.warn('`transition` property is deprecated in favor of `pageTransition` and will be removed in Nuxt 3')
|
|
||||||
options.pageTransition = options.transition
|
|
||||||
delete options.transition
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options.pageTransition === 'string') {
|
|
||||||
options.pageTransition = { name: options.pageTransition }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options.layoutTransition === 'string') {
|
|
||||||
options.layoutTransition = { name: options.layoutTransition }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options.extensions === 'string') {
|
|
||||||
options.extensions = [options.extensions]
|
|
||||||
}
|
|
||||||
|
|
||||||
options.globalName = (isNonEmptyString(options.globalName) && /^[a-zA-Z]+$/.test(options.globalName))
|
|
||||||
? options.globalName.toLowerCase()
|
|
||||||
// use `` for preventing replacing to nuxt-edge
|
// use `` for preventing replacing to nuxt-edge
|
||||||
: 'nuxt'
|
: 'nuxt'
|
||||||
|
)
|
||||||
|
|
||||||
// Resolve rootDir
|
// Resolve rootDir
|
||||||
options.rootDir = isNonEmptyString(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
|
overrideProp(_config, 'rootDir',
|
||||||
|
isNonEmptyString(_config.rootDir) ? path.resolve(_config.rootDir) : process.cwd()
|
||||||
|
)
|
||||||
|
|
||||||
// Apply defaults by ${buildDir}/dist/build.config.js
|
// Apply defaults by ${buildDir}/dist/build.config.js
|
||||||
// TODO: Unsafe operation.
|
// TODO: Unsafe operation.
|
||||||
// const buildDir = options.buildDir || defaults.buildDir
|
// const buildDir = _config.buildDir || defaults.buildDir
|
||||||
// const buildConfig = resolve(options.rootDir, buildDir, 'build.config.js')
|
// const buildConfig = resolve(_config.rootDir, buildDir, 'build.config.js')
|
||||||
// if (existsSync(buildConfig)) {
|
// if (existsSync(buildConfig)) {
|
||||||
// defaultsDeep(options, require(buildConfig))
|
// defaultsDeep(_config, require(buildConfig))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Apply defaults
|
|
||||||
const nuxtConfig = getDefaultNuxtConfig()
|
|
||||||
|
|
||||||
nuxtConfig.build._publicPath = nuxtConfig.build.publicPath
|
|
||||||
|
|
||||||
// Fall back to default if publicPath is falsy
|
// Fall back to default if publicPath is falsy
|
||||||
if (options.build && !options.build.publicPath) {
|
if (_config.build && !_config.build.publicPath) {
|
||||||
options.build.publicPath = undefined
|
_config.build.publicPath = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultsDeep(options, nuxtConfig)
|
// Apply defaults
|
||||||
|
const options = mergeConfigs(_config, getDefaultNuxtConfig())
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
options.target = options.target || 'server'
|
|
||||||
if (!Object.values(TARGETS).includes(options.target)) {
|
if (!Object.values(TARGETS).includes(options.target)) {
|
||||||
consola.warn(`Unknown target: ${options.target}. Falling back to server`)
|
consola.warn(`Unknown target: ${options.target}. Falling back to server`)
|
||||||
options.target = 'server'
|
options.target = 'server'
|
||||||
@ -127,16 +134,16 @@ export function getNuxtConfig (_options) {
|
|||||||
const hasGenerateDir = isNonEmptyString(options.generate.dir)
|
const hasGenerateDir = isNonEmptyString(options.generate.dir)
|
||||||
|
|
||||||
// Resolve srcDir
|
// Resolve srcDir
|
||||||
options.srcDir = hasSrcDir
|
overrideProp(options, 'srcDir', hasSrcDir
|
||||||
? path.resolve(options.rootDir, options.srcDir)
|
? path.resolve(options.rootDir, options.srcDir)
|
||||||
: options.rootDir
|
: options.rootDir)
|
||||||
|
|
||||||
// Resolve buildDir
|
// Resolve buildDir
|
||||||
options.buildDir = path.resolve(options.rootDir, options.buildDir)
|
overrideProp(options, 'buildDir', path.resolve(options.rootDir, options.buildDir))
|
||||||
|
|
||||||
// Aliases
|
// Aliases
|
||||||
const { rootDir, srcDir, dir: { assets: assetsDir, static: staticDir } } = options
|
const { rootDir, srcDir, dir: { assets: assetsDir, static: staticDir } } = options
|
||||||
options.alias = {
|
overrideProp(options, 'alias', {
|
||||||
'~~': rootDir,
|
'~~': rootDir,
|
||||||
'@@': rootDir,
|
'@@': rootDir,
|
||||||
'~': srcDir,
|
'~': srcDir,
|
||||||
@ -144,18 +151,14 @@ export function getNuxtConfig (_options) {
|
|||||||
[assetsDir]: path.join(srcDir, assetsDir),
|
[assetsDir]: path.join(srcDir, assetsDir),
|
||||||
[staticDir]: path.join(srcDir, staticDir),
|
[staticDir]: path.join(srcDir, staticDir),
|
||||||
...options.alias
|
...options.alias
|
||||||
}
|
})
|
||||||
|
|
||||||
// Default value for _nuxtConfigFile
|
// Default value for _nuxtConfigFile
|
||||||
if (!options._nuxtConfigFile) {
|
overrideProp(options, '_nuxtConfigFile', options._nuxtConfigFile || path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`))
|
||||||
options._nuxtConfigFile = path.resolve(options.rootDir, `${defaultNuxtConfigFile}.js`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options._nuxtConfigFiles) {
|
setProp(options, '_nuxtConfigFiles', (options as any)._nuxtConfigFiles || [
|
||||||
options._nuxtConfigFiles = [
|
|
||||||
options._nuxtConfigFile
|
options._nuxtConfigFile
|
||||||
]
|
])
|
||||||
}
|
|
||||||
|
|
||||||
// Watch for config file changes
|
// Watch for config file changes
|
||||||
options.watch.push(...options._nuxtConfigFiles)
|
options.watch.push(...options._nuxtConfigFiles)
|
||||||
@ -190,9 +193,9 @@ export function getNuxtConfig (_options) {
|
|||||||
|
|
||||||
const mandatoryExtensions = ['js', 'mjs']
|
const mandatoryExtensions = ['js', 'mjs']
|
||||||
|
|
||||||
options.extensions = mandatoryExtensions
|
overrideProp(options, 'extensions', mandatoryExtensions
|
||||||
.filter(ext => !options.extensions.includes(ext))
|
.filter(ext => !options.extensions.includes(ext))
|
||||||
.concat(options.extensions)
|
.concat(options.extensions))
|
||||||
|
|
||||||
// If app.html is defined, set the template path to the user template
|
// If app.html is defined, set the template path to the user template
|
||||||
if (options.appTemplatePath === undefined) {
|
if (options.appTemplatePath === undefined) {
|
||||||
@ -204,8 +207,8 @@ export function getNuxtConfig (_options) {
|
|||||||
options.appTemplatePath = path.resolve(options.srcDir, options.appTemplatePath)
|
options.appTemplatePath = path.resolve(options.srcDir, options.appTemplatePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
options.build.publicPath = options.build.publicPath.replace(/([^/])$/, '$1/')
|
overrideProp(options.build, 'publicPath', options.build.publicPath.replace(/([^/])$/, '$1/'))
|
||||||
options.build._publicPath = options.build._publicPath.replace(/([^/])$/, '$1/')
|
overrideProp(options.build, '_publicPath', options.build._publicPath.replace(/([^/])$/, '$1/'))
|
||||||
|
|
||||||
// Ignore publicPath on dev
|
// Ignore publicPath on dev
|
||||||
if (options.dev && isUrl(options.build.publicPath)) {
|
if (options.dev && isUrl(options.build.publicPath)) {
|
||||||
@ -233,7 +236,7 @@ export function getNuxtConfig (_options) {
|
|||||||
options.loadingIndicator = Object.assign(
|
options.loadingIndicator = Object.assign(
|
||||||
{
|
{
|
||||||
name: 'default',
|
name: 'default',
|
||||||
color: (options.loading && options.loading.color) || '#D3D3D3',
|
color: (options.loading && typeof options.loading !== 'string' && typeof options.loading !== 'boolean' && options.loading.color) || '#D3D3D3',
|
||||||
color2: '#F5F5F5',
|
color2: '#F5F5F5',
|
||||||
background: (options.manifest && options.manifest.theme_color) || 'white',
|
background: (options.manifest && options.manifest.theme_color) || 'white',
|
||||||
dev: options.dev,
|
dev: options.dev,
|
||||||
@ -244,15 +247,13 @@ export function getNuxtConfig (_options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug errors
|
// Debug errors
|
||||||
if (options.debug === undefined) {
|
overrideProp(options, 'debug', options.debug ?? options.dev)
|
||||||
options.debug = options.dev
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate that etag.hash is a function, if not unset it
|
// Validate that etag.hash is a function, if not unset it
|
||||||
if (options.render.etag) {
|
if (options.render.etag) {
|
||||||
const { hash } = options.render.etag
|
const { hash } = options.render.etag
|
||||||
if (hash) {
|
if (hash) {
|
||||||
const isFn = typeof hash === 'function'
|
const isFn = hash instanceof Function
|
||||||
if (!isFn) {
|
if (!isFn) {
|
||||||
options.render.etag.hash = undefined
|
options.render.etag.hash = undefined
|
||||||
|
|
||||||
@ -273,64 +274,26 @@ export function getNuxtConfig (_options) {
|
|||||||
unsafeInlineCompatibility: false,
|
unsafeInlineCompatibility: false,
|
||||||
reportOnly: options.debug
|
reportOnly: options.debug
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: Remove this if statement in Nuxt 3, we will stop supporting this typo (more on: https://github.com/nuxt/nuxt.js/pull/6583)
|
|
||||||
if (options.render.csp.unsafeInlineCompatiblity) {
|
|
||||||
consola.warn('Using `unsafeInlineCompatiblity` is deprecated and will be removed in Nuxt 3. Use `unsafeInlineCompatibility` instead.')
|
|
||||||
options.render.csp.unsafeInlineCompatibility = options.render.csp.unsafeInlineCompatiblity
|
|
||||||
delete options.render.csp.unsafeInlineCompatiblity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cssSourceMap
|
// cssSourceMap
|
||||||
if (options.build.cssSourceMap === undefined) {
|
overrideProp(options.build, 'cssSourceMap', options.build.cssSourceMap ?? options.dev)
|
||||||
options.build.cssSourceMap = options.dev
|
|
||||||
}
|
|
||||||
|
|
||||||
const babelConfig = options.build.babel
|
|
||||||
// babel cacheDirectory
|
// babel cacheDirectory
|
||||||
if (babelConfig.cacheDirectory === undefined) {
|
const babelConfig = options.build.babel
|
||||||
babelConfig.cacheDirectory = options.dev
|
overrideProp(options.build.babel, 'cacheDirectory', babelConfig.cacheDirectory ?? options.dev)
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove this warn in Nuxt 3
|
|
||||||
if (Array.isArray(babelConfig.presets)) {
|
|
||||||
const warnPreset = (presetName) => {
|
|
||||||
const oldPreset = '@nuxtjs/babel-preset-app'
|
|
||||||
const newPreset = '@nuxt/babel-preset-app'
|
|
||||||
if (presetName.includes(oldPreset)) {
|
|
||||||
presetName = presetName.replace(oldPreset, newPreset)
|
|
||||||
consola.warn('@nuxtjs/babel-preset-app has been deprecated, please use @nuxt/babel-preset-app.')
|
|
||||||
}
|
|
||||||
return presetName
|
|
||||||
}
|
|
||||||
babelConfig.presets = babelConfig.presets.map((preset) => {
|
|
||||||
const hasOptions = Array.isArray(preset)
|
|
||||||
if (hasOptions) {
|
|
||||||
preset[0] = warnPreset(preset[0])
|
|
||||||
} else if (typeof preset === 'string') {
|
|
||||||
preset = warnPreset(preset)
|
|
||||||
}
|
|
||||||
return preset
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vue config
|
// Vue config
|
||||||
const vueConfig = options.vue.config
|
const vueConfig = options.vue.config
|
||||||
|
|
||||||
if (vueConfig.silent === undefined) {
|
overrideProp(options.vue.config, 'performance', vueConfig.performance !== undefined ? vueConfig.performance : options.dev)
|
||||||
vueConfig.silent = !options.dev
|
|
||||||
}
|
|
||||||
if (vueConfig.performance === undefined) {
|
|
||||||
vueConfig.performance = options.dev
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge custom env with variables
|
// merge custom env with variables
|
||||||
const eligibleEnvVariables = pick(process.env, Object.keys(process.env).filter(k => k.startsWith('NUXT_ENV_')))
|
const eligibleEnvVariables = pick(process.env, Object.keys(process.env).filter(k => k.startsWith('NUXT_ENV_')))
|
||||||
Object.assign(options.env, eligibleEnvVariables)
|
overrideProp(options, 'env', Object.assign(options.env, eligibleEnvVariables))
|
||||||
|
|
||||||
// Normalize ignore
|
// Normalize ignore
|
||||||
options.ignore = options.ignore ? [].concat(options.ignore) : []
|
overrideProp(options, 'ignore', options.ignore ? Array.from(options.ignore) : [])
|
||||||
|
|
||||||
// Append ignorePrefix glob to ignore
|
// Append ignorePrefix glob to ignore
|
||||||
if (typeof options.ignorePrefix === 'string') {
|
if (typeof options.ignorePrefix === 'string') {
|
||||||
@ -349,24 +312,23 @@ export function getNuxtConfig (_options) {
|
|||||||
options.pageTransition.appear = true
|
options.pageTransition.appear = true
|
||||||
}
|
}
|
||||||
|
|
||||||
options.render.ssrLog = options.dev
|
overrideProp(options.render, 'ssrLog', options.dev
|
||||||
? options.render.ssrLog === undefined || options.render.ssrLog
|
? options.render.ssrLog === undefined || options.render.ssrLog
|
||||||
: false
|
: false)
|
||||||
|
|
||||||
// We assume the SPA fallback path is 404.html (for GitHub Pages, Surge, etc.)
|
// We assume the SPA fallback path is 404.html (for GitHub Pages, Surge, etc.)
|
||||||
if (options.generate.fallback === true) {
|
overrideProp(options.generate, 'fallback', options.generate.fallback === true ? '404.html' : options.generate.fallback)
|
||||||
options.generate.fallback = '404.html'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.build.stats === 'none' || options.build.quiet === true) {
|
if (options.build.stats === 'none' || options.build.quiet === true) {
|
||||||
options.build.stats = false
|
options.build.stats = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vendor backward compatibility with nuxt 1.x
|
// @pi0 - surely this can go
|
||||||
if (typeof options.build.vendor !== 'undefined') {
|
// // Vendor backward compatibility with nuxt 1.x
|
||||||
delete options.build.vendor
|
// if (typeof options.build.vendor !== 'undefined') {
|
||||||
consola.warn('vendor has been deprecated due to webpack4 optimization')
|
// delete options.build.vendor
|
||||||
}
|
// consola.warn('vendor has been deprecated due to webpack4 optimization')
|
||||||
|
// }
|
||||||
|
|
||||||
// Disable CSS extraction due to incompatibility with thread-loader
|
// Disable CSS extraction due to incompatibility with thread-loader
|
||||||
if (options.build.extractCSS && options.build.parallel) {
|
if (options.build.extractCSS && options.build.parallel) {
|
||||||
@ -375,17 +337,10 @@ export function getNuxtConfig (_options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build.extractCSS.allChunks has no effect
|
// build.extractCSS.allChunks has no effect
|
||||||
if (typeof options.build.extractCSS.allChunks !== 'undefined') {
|
if (typeof options.build.extractCSS !== 'boolean' && typeof options.build.extractCSS.allChunks !== 'undefined') {
|
||||||
consola.warn('build.extractCSS.allChunks has no effect from v2.0.0. Please use build.optimization.splitChunks settings instead.')
|
consola.warn('build.extractCSS.allChunks has no effect from v2.0.0. Please use build.optimization.splitChunks settings instead.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// devModules has been renamed to buildModules
|
|
||||||
if (typeof options.devModules !== 'undefined') {
|
|
||||||
consola.warn('`devModules` has been renamed to `buildModules` and will be removed in Nuxt 3.')
|
|
||||||
options.buildModules.push(...options.devModules)
|
|
||||||
delete options.devModules
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable minimize for production builds
|
// Enable minimize for production builds
|
||||||
if (options.build.optimization.minimize === undefined) {
|
if (options.build.optimization.minimize === undefined) {
|
||||||
options.build.optimization.minimize = !options.dev
|
options.build.optimization.minimize = !options.dev
|
||||||
@ -397,11 +352,11 @@ export function getNuxtConfig (_options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { loaders } = options.build
|
const { loaders } = options.build
|
||||||
const vueLoader = loaders.vue
|
// const vueLoader = loaders.vue
|
||||||
if (vueLoader.productionMode === undefined) {
|
// if (vueLoader.productionMode === undefined) {
|
||||||
vueLoader.productionMode = !options.dev
|
// vueLoader.productionMode = !options.dev
|
||||||
}
|
// }
|
||||||
const styleLoaders = [
|
const styleLoaders: Array<keyof typeof loaders> = [
|
||||||
'css', 'cssModules', 'less',
|
'css', 'cssModules', 'less',
|
||||||
'sass', 'scss', 'stylus', 'vueStyle'
|
'sass', 'scss', 'stylus', 'vueStyle'
|
||||||
]
|
]
|
||||||
@ -412,7 +367,7 @@ export function getNuxtConfig (_options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options.build.transpile = [].concat(options.build.transpile || [])
|
overrideProp(options.build, 'transpile', Array.from(options.build.transpile || []))
|
||||||
|
|
||||||
if (options.build.quiet === true) {
|
if (options.build.quiet === true) {
|
||||||
consola.level = 0
|
consola.level = 0
|
||||||
@ -420,32 +375,22 @@ export function getNuxtConfig (_options) {
|
|||||||
|
|
||||||
// Use runInNewContext for dev mode by default
|
// Use runInNewContext for dev mode by default
|
||||||
const { bundleRenderer } = options.render
|
const { bundleRenderer } = options.render
|
||||||
if (typeof bundleRenderer.runInNewContext === 'undefined') {
|
overrideProp(options.render.bundleRenderer, 'runInNewContext', bundleRenderer.runInNewContext ?? options.dev)
|
||||||
bundleRenderer.runInNewContext = options.dev
|
|
||||||
|
// const { timing } = options.server
|
||||||
|
if (options.server && typeof options.server !== 'boolean' && options.server.timing) {
|
||||||
|
overrideProp(options.server, 'timing', { total: true, ...options.server.timing })
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove this if statement in Nuxt 3
|
|
||||||
if (options.build.crossorigin) {
|
|
||||||
consola.warn('Using `build.crossorigin` is deprecated and will be removed in Nuxt 3. Please use `render.crossorigin` instead.')
|
|
||||||
options.render.crossorigin = options.build.crossorigin
|
|
||||||
delete options.build.crossorigin
|
|
||||||
}
|
|
||||||
|
|
||||||
const { timing } = options.server
|
overrideProp(options, 'serverMiddleware', Array.isArray(options.serverMiddleware) ? options.serverMiddleware : Object.entries(options.serverMiddleware)
|
||||||
if (timing) {
|
|
||||||
options.server.timing = { total: true, ...timing }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPureObject(options.serverMiddleware)) {
|
|
||||||
options.serverMiddleware = Object.entries(options.serverMiddleware)
|
|
||||||
.map(([path, handler]) => ({ path, handler }))
|
.map(([path, handler]) => ({ path, handler }))
|
||||||
}
|
)
|
||||||
|
|
||||||
// Generate staticAssets
|
// Generate staticAssets
|
||||||
const { staticAssets } = options.generate
|
const { staticAssets } = options.generate
|
||||||
if (!staticAssets.version) {
|
overrideProp(options.generate.staticAssets, 'version', options.generate.staticAssets.version || String(Math.round(Date.now() / 1000)))
|
||||||
staticAssets.version = String(Math.round(Date.now() / 1000))
|
|
||||||
}
|
|
||||||
if (!staticAssets.base) {
|
if (!staticAssets.base) {
|
||||||
const publicPath = isUrl(options.build.publicPath) ? '' : options.build.publicPath // "/_nuxt" or custom CDN URL
|
const publicPath = isUrl(options.build.publicPath) ? '' : options.build.publicPath // "/_nuxt" or custom CDN URL
|
||||||
staticAssets.base = urlJoin(publicPath, staticAssets.dir)
|
staticAssets.base = urlJoin(publicPath, staticAssets.dir)
|
||||||
@ -492,3 +437,5 @@ export function getNuxtConfig (_options) {
|
|||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NormalizedConfiguration = ReturnType<typeof normalizeConfig>
|
38
packages/nuxt3/src/config/transformers.ts
Normal file
38
packages/nuxt3/src/config/transformers.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { defaultsDeep } from 'lodash'
|
||||||
|
|
||||||
|
export type Optional<T> = {
|
||||||
|
-readonly [K in keyof T]?: T[K] extends Function ? T[K] : T[K] extends RegExp ? T[K] : T[K] extends Promise<any> ? T[K] : T[K] extends Array<infer R> ? Array<R> : Optional<T[K]>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setProp<O extends Record<string, any>, K extends string, V>(obj: O, key: K, value: V): asserts obj is O & { [key in K]: V } {
|
||||||
|
(obj as { [key in K]: V })[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
type Override<O extends Record<string, any>, K extends keyof O, V> = K extends Array<infer A> ? {
|
||||||
|
[P in keyof O]: K extends P ? O[P] extends Array<infer T> ? Array<A & T> : K | O[P] : O[P]
|
||||||
|
} : O & { [key in K]: V }
|
||||||
|
|
||||||
|
export function overrideProp<O extends Record<string, any>, K extends keyof O, V>(obj: O, key: K, value: V): asserts obj is Override<O, K, V> {
|
||||||
|
(obj as { [key in K]: V })[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteProp<O extends Record<string, any>, K extends string>(obj: O, key: K): asserts obj is Exclude<O, K> {
|
||||||
|
delete obj[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
type MergeArrays<S, T> = S extends Array<infer A1> ? T extends Array<infer A2> ? Array<A1 | A2> : T | Array<A1> : T | S
|
||||||
|
type MergeObjects<S extends Record<string, any>, T extends Record<string, any>> = Omit<S & T, keyof S & keyof T> & {
|
||||||
|
-readonly [K in keyof S & keyof T]: Merge<S[K], T[K]>
|
||||||
|
}
|
||||||
|
type Merge<S, T> = S extends Array<any> ? MergeArrays<S, T> : S extends Function ? S | T : S extends RegExp ? S | T : S extends Promise<any> ? S | T : T extends Function ? S | T : S extends Record<string, any> ? T extends Record<string, any> ? MergeObjects<S, T> : S | T : MergeArrays<S, T>
|
||||||
|
|
||||||
|
// let b: Merged<{ test: string, another: number[] }, { third: () => void, another: string[] }> = {} as any
|
||||||
|
// b.another
|
||||||
|
// let c = b
|
||||||
|
// c.
|
||||||
|
|
||||||
|
// T extends Array<infer A> ? Array<Merged<A, S>> : T
|
||||||
|
|
||||||
|
export function mergeConfigs<Dest extends Record<string, any>, Source extends Record<string, any>>(dest: Dest, source: Source): Merge<Dest, Source> {
|
||||||
|
return defaultsDeep(dest, source)
|
||||||
|
}
|
@ -16,8 +16,8 @@ export interface LoadOptions {
|
|||||||
rootDir?: string
|
rootDir?: string
|
||||||
envConfig?: EnvConfig
|
envConfig?: EnvConfig
|
||||||
configFile?: string
|
configFile?: string
|
||||||
configContext?: {}
|
configContext?: Record<string, any>,
|
||||||
configOverrides?: {},
|
configOverrides?: Record<string, any>,
|
||||||
createRequire?: (module: NodeJS.Module) => NodeJS.Require
|
createRequire?: (module: NodeJS.Module) => NodeJS.Require
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,24 +3,29 @@ import fs from 'fs'
|
|||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
|
||||||
import { chainFn, sequence } from 'nuxt/utils'
|
import type { NormalizedConfiguration } from 'nuxt/config'
|
||||||
|
import { chainFn, Mode, sequence } from 'nuxt/utils'
|
||||||
|
|
||||||
import Nuxt from './nuxt'
|
import Nuxt from './nuxt'
|
||||||
|
import type { NuxtModule, ModuleHandler } from 'nuxt/config/config/_common'
|
||||||
|
|
||||||
interface Module {
|
interface TemplateInput {
|
||||||
|
filename?: string
|
||||||
|
fileName?: string
|
||||||
|
options?: Record<string, any>
|
||||||
src: string
|
src: string
|
||||||
options: Record<string, any>
|
ssr?: boolean
|
||||||
handler: () => any
|
mode?: 'all' | 'server' | 'client'
|
||||||
}
|
|
||||||
|
|
||||||
interface Template {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ModuleContainer {
|
export default class ModuleContainer {
|
||||||
nuxt: Nuxt
|
nuxt: Nuxt
|
||||||
options: Nuxt['options']
|
options: Nuxt['options']
|
||||||
requiredModules: Record<string, Module>
|
requiredModules: Record<string, {
|
||||||
|
src: string
|
||||||
|
options: Record<string, any>
|
||||||
|
handler: ModuleHandler
|
||||||
|
}>
|
||||||
|
|
||||||
constructor(nuxt: Nuxt) {
|
constructor(nuxt: Nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
@ -58,13 +63,13 @@ export default class ModuleContainer {
|
|||||||
consola.warn('addVendor has been deprecated due to webpack4 optimization')
|
consola.warn('addVendor has been deprecated due to webpack4 optimization')
|
||||||
}
|
}
|
||||||
|
|
||||||
addTemplate (template) {
|
addTemplate(template: TemplateInput | string) {
|
||||||
if (!template) {
|
if (!template) {
|
||||||
throw new Error('Invalid template: ' + JSON.stringify(template))
|
throw new Error('Invalid template: ' + JSON.stringify(template))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate & parse source
|
// Validate & parse source
|
||||||
const src = template.src || template
|
const src = typeof template === 'string' ? template : template.src
|
||||||
const srcPath = path.parse(src)
|
const srcPath = path.parse(src)
|
||||||
|
|
||||||
if (typeof src !== 'string' || !fs.existsSync(src)) {
|
if (typeof src !== 'string' || !fs.existsSync(src)) {
|
||||||
@ -72,14 +77,14 @@ export default class ModuleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mostly for DX, some people prefers `filename` vs `fileName`
|
// Mostly for DX, some people prefers `filename` vs `fileName`
|
||||||
const fileName = template.fileName || template.filename
|
const fileName = typeof template === 'string' ? '' : template.fileName || template.filename
|
||||||
// Generate unique and human readable dst filename if not provided
|
// Generate unique and human readable dst filename if not provided
|
||||||
const dst = fileName || `${path.basename(srcPath.dir)}.${srcPath.name}.${hash(src)}${srcPath.ext}`
|
const dst = fileName || `${path.basename(srcPath.dir)}.${srcPath.name}.${hash(src)}${srcPath.ext}`
|
||||||
// Add to templates list
|
// Add to templates list
|
||||||
const templateObj = {
|
const templateObj = {
|
||||||
src,
|
src,
|
||||||
dst,
|
dst,
|
||||||
options: template.options
|
options: typeof template === 'string' ? undefined : template.options
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options.build.templates.push(templateObj)
|
this.options.build.templates.push(templateObj)
|
||||||
@ -87,7 +92,7 @@ export default class ModuleContainer {
|
|||||||
return templateObj
|
return templateObj
|
||||||
}
|
}
|
||||||
|
|
||||||
addPlugin (template) {
|
addPlugin(template: TemplateInput) {
|
||||||
const { dst } = this.addTemplate(template)
|
const { dst } = this.addTemplate(template)
|
||||||
|
|
||||||
// Add to nuxt plugins
|
// Add to nuxt plugins
|
||||||
@ -99,7 +104,7 @@ export default class ModuleContainer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
addLayout (template, name: string) {
|
addLayout(template: TemplateInput, name: string) {
|
||||||
const { dst, src } = this.addTemplate(template)
|
const { dst, src } = this.addTemplate(template)
|
||||||
const layoutName = name || path.parse(src).name
|
const layoutName = name || path.parse(src).name
|
||||||
const layout = this.options.layouts[layoutName]
|
const layout = this.options.layouts[layoutName]
|
||||||
@ -122,29 +127,29 @@ export default class ModuleContainer {
|
|||||||
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
||||||
}
|
}
|
||||||
|
|
||||||
addServerMiddleware (middleware) {
|
addServerMiddleware(middleware: NormalizedConfiguration['serverMiddleware'][number]) {
|
||||||
this.options.serverMiddleware.push(middleware)
|
this.options.serverMiddleware.push(middleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
extendBuild (fn) {
|
extendBuild(fn: NormalizedConfiguration['build']['extend']) {
|
||||||
this.options.build.extend = chainFn(this.options.build.extend, fn)
|
this.options.build.extend = chainFn(this.options.build.extend, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
extendRoutes (fn) {
|
extendRoutes(fn: NormalizedConfiguration['router']['extendRoutes']) {
|
||||||
this.options.router.extendRoutes = chainFn(
|
this.options.router.extendRoutes = chainFn(
|
||||||
this.options.router.extendRoutes,
|
this.options.router.extendRoutes,
|
||||||
fn
|
fn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
requireModule (moduleOpts: Module) {
|
requireModule(moduleOpts: NuxtModule) {
|
||||||
return this.addModule(moduleOpts)
|
return this.addModule(moduleOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
async addModule (moduleOpts) {
|
async addModule(moduleOpts: NuxtModule) {
|
||||||
let src
|
let src: string | ModuleHandler
|
||||||
let options: Record<string, any>
|
let options: Record<string, any>
|
||||||
let handler
|
let handler: ModuleHandler | ModuleHandler & { meta: { name: string } }
|
||||||
|
|
||||||
// Type 1: String or Function
|
// Type 1: String or Function
|
||||||
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
|
if (typeof moduleOpts === 'string' || typeof moduleOpts === 'function') {
|
||||||
@ -168,7 +173,7 @@ export default class ModuleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resolve handler
|
// Resolve handler
|
||||||
if (!handler) {
|
if (!handler && typeof src === 'string') {
|
||||||
try {
|
try {
|
||||||
handler = this.nuxt.resolver.requireModule(src, { useESM: true })
|
handler = this.nuxt.resolver.requireModule(src, { useESM: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -207,6 +212,7 @@ export default class ModuleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure module is required once
|
// Ensure module is required once
|
||||||
|
if ('meta' in handler && typeof src === 'string') {
|
||||||
const metaKey = handler.meta && handler.meta.name
|
const metaKey = handler.meta && handler.meta.name
|
||||||
const key = metaKey || src
|
const key = metaKey || src
|
||||||
if (typeof key === 'string') {
|
if (typeof key === 'string') {
|
||||||
@ -218,7 +224,8 @@ export default class ModuleContainer {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.requiredModules[key] = { src, options, handler }
|
this.requiredModules[key] = { src, options, handler: handler as ModuleHandler }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default module options to empty object
|
// Default module options to empty object
|
||||||
|
@ -4,7 +4,7 @@ import consola from 'consola'
|
|||||||
import Hookable from 'hookable'
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
import { defineAlias } from 'nuxt/utils'
|
import { defineAlias } from 'nuxt/utils'
|
||||||
import { getNuxtConfig } from 'nuxt/config'
|
import { getNuxtConfig, Configuration, NormalizedConfiguration } from 'nuxt/config'
|
||||||
import { Server } from 'nuxt/server'
|
import { Server } from 'nuxt/server'
|
||||||
|
|
||||||
import { version } from '../../package.json'
|
import { version } from '../../package.json'
|
||||||
@ -12,11 +12,15 @@ import { version } from '../../package.json'
|
|||||||
import ModuleContainer from './module'
|
import ModuleContainer from './module'
|
||||||
import Resolver from './resolver'
|
import Resolver from './resolver'
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var __NUXT_DEV__: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export default class Nuxt extends Hookable {
|
export default class Nuxt extends Hookable {
|
||||||
_ready?: Promise<this>
|
_ready?: Promise<this>
|
||||||
_initCalled?: boolean
|
_initCalled?: boolean
|
||||||
|
|
||||||
options: any
|
options: NormalizedConfiguration
|
||||||
resolver: Resolver
|
resolver: Resolver
|
||||||
moduleContainer: ModuleContainer
|
moduleContainer: ModuleContainer
|
||||||
server?: Server
|
server?: Server
|
||||||
@ -24,7 +28,7 @@ export default class Nuxt extends Hookable {
|
|||||||
render?: Server['app']
|
render?: Server['app']
|
||||||
showReady?: () => void
|
showReady?: () => void
|
||||||
|
|
||||||
constructor (options = {}) {
|
constructor(options: Configuration = {}) {
|
||||||
super(consola)
|
super(consola)
|
||||||
|
|
||||||
// Assign options and apply defaults
|
// Assign options and apply defaults
|
||||||
@ -84,10 +88,10 @@ export default class Nuxt extends Hookable {
|
|||||||
this._initCalled = true
|
this._initCalled = true
|
||||||
|
|
||||||
// Add hooks
|
// Add hooks
|
||||||
if (isPlainObject(this.options.hooks)) {
|
if (this.options.hooks instanceof Function) {
|
||||||
this.addHooks(this.options.hooks)
|
|
||||||
} else if (typeof this.options.hooks === 'function') {
|
|
||||||
this.options.hooks(this.hook)
|
this.options.hooks(this.hook)
|
||||||
|
} else if (isPlainObject(this.options.hooks)) {
|
||||||
|
this.addHooks(this.options.hooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Await for modules
|
// Await for modules
|
||||||
@ -120,8 +124,5 @@ export default class Nuxt extends Hookable {
|
|||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
await callback()
|
await callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deleting as no longer exists on `hookable`
|
|
||||||
// this.clearHooks()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,8 @@ export default class Generator {
|
|||||||
try {
|
try {
|
||||||
const renderContext = {
|
const renderContext = {
|
||||||
payload,
|
payload,
|
||||||
staticAssetsBase: this.staticAssetsBase
|
staticAssetsBase: this.staticAssetsBase,
|
||||||
|
staticAssets: undefined
|
||||||
}
|
}
|
||||||
const res = await this.nuxt.server.renderRoute(route, renderContext)
|
const res = await this.nuxt.server.renderRoute(route, renderContext)
|
||||||
html = res.html
|
html = res.html
|
||||||
@ -377,7 +378,7 @@ export default class Generator {
|
|||||||
pageErrors.push({ type: 'unhandled', route, error: minifyErr })
|
pageErrors.push({ type: 'unhandled', route, error: minifyErr })
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileName
|
let fileName: string
|
||||||
|
|
||||||
if (this.options.generate.subFolders) {
|
if (this.options.generate.subFolders) {
|
||||||
fileName = path.join(route, path.sep, 'index.html') // /about -> /about/index.html
|
fileName = path.join(route, path.sep, 'index.html') // /about -> /about/index.html
|
||||||
@ -414,16 +415,8 @@ export default class Generator {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
minifyHtml (html) {
|
minifyHtml(html: string) {
|
||||||
let minificationOptions = this.options.build.html.minify
|
const minificationOptions = this.options.build.html.minify
|
||||||
|
|
||||||
// Legacy: Override minification options with generate.minify if present
|
|
||||||
// TODO: Remove in Nuxt version 3
|
|
||||||
if (typeof this.options.generate.minify !== 'undefined') {
|
|
||||||
minificationOptions = this.options.generate.minify
|
|
||||||
consola.warn('generate.minify has been deprecated and will be removed in the next major version.' +
|
|
||||||
' Use build.html.minify instead!')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!minificationOptions) {
|
if (!minificationOptions) {
|
||||||
return html
|
return html
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import { BaseOptions, DOMWindow, VirtualConsole } from 'jsdom'
|
||||||
import { DeterminedGlobals, timeout } from 'nuxt/utils'
|
import { DeterminedGlobals, timeout } from 'nuxt/utils'
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
@ -28,12 +29,12 @@ export default async function renderAndGetWindow (
|
|||||||
throw e
|
throw e
|
||||||
})
|
})
|
||||||
|
|
||||||
const options = Object.assign({
|
const options: BaseOptions = Object.assign({
|
||||||
// Load subresources (https://github.com/tmpvar/jsdom#loading-subresources)
|
// Load subresources (https://github.com/tmpvar/jsdom#loading-subresources)
|
||||||
resources: 'usable',
|
resources: 'usable' as const,
|
||||||
runScripts: 'dangerously',
|
runScripts: 'dangerously' as const,
|
||||||
virtualConsole: true,
|
virtualConsole: undefined,
|
||||||
beforeParse (window: Window) {
|
beforeParse (window: DOMWindow) {
|
||||||
// Mock window.scrollTo
|
// Mock window.scrollTo
|
||||||
window.scrollTo = () => {}
|
window.scrollTo = () => {}
|
||||||
}
|
}
|
||||||
@ -44,8 +45,8 @@ export default async function renderAndGetWindow (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.virtualConsole) {
|
if (options.virtualConsole) {
|
||||||
if (options.virtualConsole === true) {
|
if (options.virtualConsole === undefined) {
|
||||||
options.virtualConsole = new jsdom.VirtualConsole().sendTo(consola)
|
options.virtualConsole = new jsdom.VirtualConsole().sendTo(consola as unknown as Console)
|
||||||
}
|
}
|
||||||
// Throw error when window creation failed
|
// Throw error when window creation failed
|
||||||
options.virtualConsole.on('jsdomError', jsdomErrHandler)
|
options.virtualConsole.on('jsdomError', jsdomErrHandler)
|
||||||
@ -58,13 +59,13 @@ export default async function renderAndGetWindow (
|
|||||||
|
|
||||||
if (!nuxtExists) {
|
if (!nuxtExists) {
|
||||||
const error = new Error('Could not load the nuxt app')
|
const error = new Error('Could not load the nuxt app')
|
||||||
error.body = window.document.body.innerHTML
|
;(error as any).body = window.document.body.innerHTML
|
||||||
window.close()
|
window.close()
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by Nuxt.js to say when the components are loaded and the app ready
|
// Used by Nuxt.js to say when the components are loaded and the app ready
|
||||||
await timeout(new Promise((resolve) => {
|
await timeout(new Promise<DOMWindow>((resolve) => {
|
||||||
window[loadedCallback] = () => resolve(window)
|
window[loadedCallback] = () => resolve(window)
|
||||||
}), loadingTimeout, `Components loading in renderAndGetWindow was not completed in ${loadingTimeout / 1000}s`)
|
}), loadingTimeout, `Components loading in renderAndGetWindow was not completed in ${loadingTimeout / 1000}s`)
|
||||||
|
|
||||||
|
@ -8,6 +8,16 @@ import pify from 'pify'
|
|||||||
|
|
||||||
let RANDOM_PORT = '0'
|
let RANDOM_PORT = '0'
|
||||||
|
|
||||||
|
interface ListenerOptions {
|
||||||
|
port: number | string
|
||||||
|
host: string
|
||||||
|
socket: string
|
||||||
|
https: boolean
|
||||||
|
app: any
|
||||||
|
dev: boolean
|
||||||
|
baseURL: string
|
||||||
|
}
|
||||||
|
|
||||||
export default class Listener {
|
export default class Listener {
|
||||||
port: number | string
|
port: number | string
|
||||||
host: string
|
host: string
|
||||||
@ -22,7 +32,7 @@ export default class Listener {
|
|||||||
server: null | http.Server
|
server: null | http.Server
|
||||||
address: null
|
address: null
|
||||||
url: null | string
|
url: null | string
|
||||||
constructor ({ port, host, socket, https, app, dev, baseURL }) {
|
constructor ({ port, host, socket, https, app, dev, baseURL }: ListenerOptions) {
|
||||||
// Options
|
// Options
|
||||||
this.port = port
|
this.port = port
|
||||||
this.host = host
|
this.host = host
|
||||||
|
@ -33,7 +33,7 @@ export default class Server {
|
|||||||
nuxt: Nuxt
|
nuxt: Nuxt
|
||||||
globals: DeterminedGlobals
|
globals: DeterminedGlobals
|
||||||
options: Nuxt['options']
|
options: Nuxt['options']
|
||||||
publicPath: boolean
|
publicPath: string
|
||||||
renderer: VueRenderer
|
renderer: VueRenderer
|
||||||
resources: {
|
resources: {
|
||||||
clientManifest?: Manifest
|
clientManifest?: Manifest
|
||||||
@ -114,7 +114,7 @@ export default class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.server.timing) {
|
if (typeof this.options.server !== 'boolean' && this.options.server.timing) {
|
||||||
this.useMiddleware(createTimingMiddleware(this.options.server.timing))
|
this.useMiddleware(createTimingMiddleware(this.options.server.timing))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ interface AliasOptions {
|
|||||||
warn?: boolean
|
warn?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineAlias (
|
export function defineAlias <O extends Record<string, any>>(
|
||||||
src: string,
|
src: O,
|
||||||
target: Record<string, any>,
|
target: Record<string, any>,
|
||||||
prop: string | string[],
|
prop: string | string[],
|
||||||
opts: AliasOptions = {}
|
opts: AliasOptions = {}
|
||||||
|
@ -213,7 +213,7 @@ export const createRoutes = function createRoutes ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Guard dir1 from dir2 which can be indiscriminately removed
|
// Guard dir1 from dir2 which can be indiscriminately removed
|
||||||
export const guardDir = function guardDir (options: Record<string, unknown>, key1: string, key2: string) {
|
export const guardDir = function guardDir (options: Record<string, any>, key1: string, key2: string) {
|
||||||
const dir1 = get(options, key1, false) as string
|
const dir1 = get(options, key1, false) as string
|
||||||
const dir2 = get(options, key2, false) as string
|
const dir2 = get(options, key2, false) as string
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ async function promiseFinally<T> (
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const timeout = function timeout (
|
export const timeout = function timeout <T>(
|
||||||
fn: () => any,
|
fn: Promise<T>,
|
||||||
ms: number,
|
ms: number,
|
||||||
msg: string
|
msg: string
|
||||||
) {
|
) {
|
||||||
|
Loading…
Reference in New Issue
Block a user