mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
feat: typed nuxt (1)
This commit is contained in:
parent
f9005bb300
commit
38e72f86c2
@ -15,6 +15,7 @@ import template from 'lodash/template'
|
|||||||
import uniq from 'lodash/uniq'
|
import uniq from 'lodash/uniq'
|
||||||
import uniqBy from 'lodash/uniqBy'
|
import uniqBy from 'lodash/uniqBy'
|
||||||
|
|
||||||
|
import type { Nuxt } from 'nuxt/core'
|
||||||
import { BundleBuilder } from 'nuxt/webpack'
|
import { BundleBuilder } from 'nuxt/webpack'
|
||||||
import vueAppTemplate from 'nuxt/vue-app/template'
|
import vueAppTemplate from 'nuxt/vue-app/template'
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ import {
|
|||||||
determineGlobals,
|
determineGlobals,
|
||||||
stripWhitespace,
|
stripWhitespace,
|
||||||
isIndexFileAndFolder,
|
isIndexFileAndFolder,
|
||||||
|
DeterminedGlobals,
|
||||||
scanRequireTree,
|
scanRequireTree,
|
||||||
TARGETS,
|
TARGETS,
|
||||||
isFullStatic
|
isFullStatic
|
||||||
@ -34,10 +36,35 @@ import {
|
|||||||
import Ignore from './ignore'
|
import Ignore from './ignore'
|
||||||
import BuildContext from './context/build'
|
import BuildContext from './context/build'
|
||||||
import TemplateContext from './context/template'
|
import TemplateContext from './context/template'
|
||||||
|
import { RouteLocationRaw } from 'vue-router'
|
||||||
|
|
||||||
const glob = pify(Glob)
|
const glob = pify(Glob)
|
||||||
export default class Builder {
|
export default class Builder {
|
||||||
constructor (nuxt, bundleBuilder) {
|
__closed?: boolean
|
||||||
|
_buildStatus: typeof STATUS[keyof typeof STATUS]
|
||||||
|
_defaultPage?: boolean
|
||||||
|
_nuxtPages?: boolean
|
||||||
|
|
||||||
|
appFiles: string[]
|
||||||
|
bundleBuilder: BundleBuilder
|
||||||
|
globals: DeterminedGlobals
|
||||||
|
ignore: Ignore
|
||||||
|
nuxt: Nuxt
|
||||||
|
options: Nuxt['options']
|
||||||
|
plugins: Array<{
|
||||||
|
src: string
|
||||||
|
}>
|
||||||
|
relativeToBuild: (...args: string[]) => string
|
||||||
|
routes: RouteLocationRaw[]
|
||||||
|
supportedExtensions: string[]
|
||||||
|
template: typeof vueAppTemplate
|
||||||
|
watchers: {
|
||||||
|
files: null
|
||||||
|
custom: null
|
||||||
|
restart: null
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (nuxt: Nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.plugins = []
|
this.plugins = []
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
@ -51,7 +78,7 @@ export default class Builder {
|
|||||||
this.supportedExtensions = ['vue', 'js', ...(this.options.build.additionalExtensions || [])]
|
this.supportedExtensions = ['vue', 'js', ...(this.options.build.additionalExtensions || [])]
|
||||||
|
|
||||||
// Helper to resolve build paths
|
// Helper to resolve build paths
|
||||||
this.relativeToBuild = (...args) => relativeTo(this.options.buildDir, ...args)
|
this.relativeToBuild = (...args: string[]) => relativeTo(this.options.buildDir, ...args)
|
||||||
|
|
||||||
this._buildStatus = STATUS.INITIAL
|
this._buildStatus = STATUS.INITIAL
|
||||||
|
|
||||||
@ -81,7 +108,7 @@ export default class Builder {
|
|||||||
this.template = vueAppTemplate
|
this.template = vueAppTemplate
|
||||||
|
|
||||||
// Create a new bundle builder
|
// Create a new bundle builder
|
||||||
this.bundleBuilder = this.getBundleBuilder(bundleBuilder)
|
this.bundleBuilder = this.getBundleBuilder()
|
||||||
|
|
||||||
this.ignore = new Ignore({
|
this.ignore = new Ignore({
|
||||||
rootDir: this.options.srcDir,
|
rootDir: this.options.srcDir,
|
||||||
@ -846,4 +873,4 @@ const STATUS = {
|
|||||||
INITIAL: 1,
|
INITIAL: 1,
|
||||||
BUILD_DONE: 2,
|
BUILD_DONE: 2,
|
||||||
BUILDING: 3
|
BUILDING: 3
|
||||||
}
|
} as const
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
|
import type Builder from '../builder'
|
||||||
|
|
||||||
export default class BuildContext {
|
export default class BuildContext {
|
||||||
constructor (builder) {
|
_builder: Builder
|
||||||
|
nuxt: Builder['nuxt']
|
||||||
|
options: Builder['nuxt']['options']
|
||||||
|
target: Builder['nuxt']['options']['target']
|
||||||
|
|
||||||
|
constructor (builder: Builder) {
|
||||||
this._builder = builder
|
this._builder = builder
|
||||||
this.nuxt = builder.nuxt
|
this.nuxt = builder.nuxt
|
||||||
this.options = builder.nuxt.options
|
this.options = builder.nuxt.options
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import consola from 'consola'
|
|
||||||
import uniqBy from 'lodash/uniqBy'
|
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 { r, wp, wChunk, serializeFunction, isFullStatic } from 'nuxt/utils'
|
import { r, wp, wChunk, serializeFunction, isFullStatic } from 'nuxt/utils'
|
||||||
|
|
||||||
|
import type Builder from '../builder'
|
||||||
|
|
||||||
export default class TemplateContext {
|
export default class TemplateContext {
|
||||||
constructor(builder, options) {
|
templateFiles: string[]
|
||||||
|
templateVars: any
|
||||||
|
|
||||||
|
constructor (builder: Builder, options) {
|
||||||
this.templateFiles = Array.from(builder.template.files)
|
this.templateFiles = Array.from(builder.template.files)
|
||||||
this.templateVars = {
|
this.templateVars = {
|
||||||
nuxtOptions: options,
|
nuxtOptions: options,
|
||||||
@ -53,7 +57,7 @@ export default class TemplateContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get templateOptions () {
|
get templateOptions() {
|
||||||
return {
|
return {
|
||||||
imports: {
|
imports: {
|
||||||
serialize,
|
serialize,
|
||||||
@ -62,7 +66,7 @@ export default class TemplateContext {
|
|||||||
hash,
|
hash,
|
||||||
r,
|
r,
|
||||||
wp,
|
wp,
|
||||||
wChunk,
|
wChunk
|
||||||
},
|
},
|
||||||
interpolate: /<%=([\s\S]+?)%>/g
|
interpolate: /<%=([\s\S]+?)%>/g
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,16 @@ import path from 'path'
|
|||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import ignore from 'ignore'
|
import ignore from 'ignore'
|
||||||
|
|
||||||
|
type IgnoreInstance = ReturnType<typeof ignore>
|
||||||
|
type IgnoreOptions = Parameters<typeof ignore>[0]
|
||||||
|
|
||||||
export default class Ignore {
|
export default class Ignore {
|
||||||
|
rootDir: string
|
||||||
|
ignore?: IgnoreInstance
|
||||||
|
ignoreArray?: string | string
|
||||||
|
ignoreFile?: string
|
||||||
|
ignoreOptions?: IgnoreOptions
|
||||||
|
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
this.rootDir = options.rootDir
|
this.rootDir = options.rootDir
|
||||||
this.ignoreOptions = options.ignoreOptions
|
this.ignoreOptions = options.ignoreOptions
|
||||||
@ -44,7 +53,7 @@ export default class Ignore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filter (paths) {
|
filter (paths: string[]) {
|
||||||
if (this.ignore) {
|
if (this.ignore) {
|
||||||
return this.ignore.filter([].concat(paths || []))
|
return this.ignore.filter([].concat(paths || []))
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import type { Nuxt } from 'nuxt/core'
|
||||||
|
|
||||||
import Builder from './builder'
|
import Builder from './builder'
|
||||||
export { default as Builder } from './builder'
|
export { default as Builder } from './builder'
|
||||||
|
|
||||||
export function getBuilder (nuxt) {
|
export function getBuilder (nuxt: Nuxt) {
|
||||||
return new Builder(nuxt)
|
return new Builder(nuxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function build (nuxt) {
|
export function build (nuxt: Nuxt) {
|
||||||
return getBuilder(nuxt).build()
|
return getBuilder(nuxt).build()
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,74 @@
|
|||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import minimist from 'minimist'
|
import minimist, { ParsedArgs } from 'minimist'
|
||||||
import Hookable from 'hable'
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
|
import { Builder } from 'nuxt/builder'
|
||||||
|
import { Generator } from 'nuxt/generator'
|
||||||
|
import type { Target } from 'nuxt/utils'
|
||||||
|
|
||||||
import { name, version } from '../../package.json'
|
import { name, version } from '../../package.json'
|
||||||
|
|
||||||
import { forceExit } from './utils'
|
import { forceExit } from './utils'
|
||||||
import { loadNuxtConfig } from './utils/config'
|
import { loadNuxtConfig } from './utils/config'
|
||||||
import { indent, foldLines, colorize } from './utils/formatting'
|
import { indent, foldLines, colorize } from './utils/formatting'
|
||||||
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants'
|
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/constants'
|
||||||
import { Nuxt } from 'nuxt/core'
|
|
||||||
import { Builder } from 'nuxt/builder'
|
export interface Command {
|
||||||
import { Generator } from 'nuxt/generator'
|
name: string
|
||||||
|
usage: string
|
||||||
|
description: string
|
||||||
|
options?: Record<string, any>
|
||||||
|
run?: (nuxt: NuxtCommand) => any | Promise<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
constructor (cmd = { name: '', usage: '', description: '' }, argv = process.argv.slice(2), hooks = {}) {
|
_argv: string[]
|
||||||
|
_parsedArgv: null | ParsedArgs
|
||||||
|
_lockRelease?: () => Promise<any>
|
||||||
|
|
||||||
|
cmd: Command & { options: Command['options'] }
|
||||||
|
|
||||||
|
constructor(cmd: Command = { name: '', usage: '', description: '' }, argv = process.argv.slice(2), hooks: Hooks = {}) {
|
||||||
super(consola)
|
super(consola)
|
||||||
this.addHooks(hooks)
|
this.addHooks(hooks)
|
||||||
|
|
||||||
if (!cmd.options) {
|
if (!cmd.options) {
|
||||||
cmd.options = {}
|
cmd.options = {}
|
||||||
}
|
}
|
||||||
this.cmd = cmd
|
this.cmd = cmd as Command & { options: Command['options'] }
|
||||||
|
|
||||||
this._argv = Array.from(argv)
|
this._argv = Array.from(argv)
|
||||||
this._parsedArgv = null // Lazy evaluate
|
this._parsedArgv = null // Lazy evaluate
|
||||||
}
|
}
|
||||||
|
|
||||||
static run (cmd, argv, hooks) {
|
static run(cmd: Command, argv: NodeJS.Process['argv'], hooks: Hooks) {
|
||||||
return NuxtCommand.from(cmd, argv, hooks).run()
|
return NuxtCommand.from(cmd, argv, hooks).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
static from (cmd, argv, hooks) {
|
static from(cmd: Command, argv: NodeJS.Process['argv'], hooks: Hooks) {
|
||||||
if (cmd instanceof NuxtCommand) {
|
if (cmd instanceof NuxtCommand) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
return new NuxtCommand(cmd, argv, hooks)
|
return new NuxtCommand(cmd, argv, hooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
async run () {
|
async run() {
|
||||||
await this.callHook('run:before', {
|
await this.callHook('run:before', {
|
||||||
argv: this._argv,
|
argv: this._argv,
|
||||||
cmd: this.cmd,
|
cmd: this.cmd,
|
||||||
@ -54,11 +85,11 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof this.cmd.run !== 'function') {
|
if (!(this.cmd.run instanceof Function)) {
|
||||||
throw new TypeError('Invalid command! Commands should at least implement run() function.')
|
throw new TypeError('Invalid command! Commands should at least implement run() function.')
|
||||||
}
|
}
|
||||||
|
|
||||||
let cmdError
|
let cmdError: any
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.cmd.run(this)
|
await this.cmd.run(this)
|
||||||
@ -86,15 +117,15 @@ export default class NuxtCommand extends Hookable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showVersion () {
|
showVersion() {
|
||||||
process.stdout.write(`${name} v${version}\n`)
|
process.stdout.write(`${name} v${version}\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
showHelp () {
|
showHelp() {
|
||||||
process.stdout.write(this._getHelp())
|
process.stdout.write(this._getHelp())
|
||||||
}
|
}
|
||||||
|
|
||||||
get argv () {
|
get argv() {
|
||||||
if (!this._parsedArgv) {
|
if (!this._parsedArgv) {
|
||||||
const minimistOptions = this._getMinimistOptions()
|
const minimistOptions = this._getMinimistOptions()
|
||||||
this._parsedArgv = minimist(this._argv, minimistOptions)
|
this._parsedArgv = minimist(this._argv, minimistOptions)
|
||||||
@ -102,7 +133,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return this._parsedArgv
|
return this._parsedArgv
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNuxtConfig (extraOptions = {}) {
|
async getNuxtConfig(extraOptions: ExtraOptions = {}) {
|
||||||
// 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
|
||||||
|
|
||||||
@ -123,7 +154,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNuxt (options) {
|
async getNuxt(options) {
|
||||||
|
|
||||||
const nuxt = new Nuxt(options)
|
const nuxt = new Nuxt(options)
|
||||||
await nuxt.ready()
|
await nuxt.ready()
|
||||||
@ -131,16 +162,16 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return nuxt
|
return nuxt
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBuilder (nuxt) {
|
async getBuilder(nuxt: Nuxt) {
|
||||||
return new Builder(nuxt)
|
return new Builder(nuxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGenerator (nuxt) {
|
async getGenerator(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) {
|
||||||
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`)
|
||||||
@ -153,22 +184,22 @@ export default class NuxtCommand extends Hookable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async releaseLock () {
|
async releaseLock() {
|
||||||
if (this._lockRelease) {
|
if (this._lockRelease) {
|
||||||
await this._lockRelease()
|
await this._lockRelease()
|
||||||
this._lockRelease = undefined
|
this._lockRelease = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isUserSuppliedArg (option) {
|
isUserSuppliedArg(option: string) {
|
||||||
return this._argv.includes(`--${option}`) || this._argv.includes(`--no-${option}`)
|
return this._argv.includes(`--${option}`) || this._argv.includes(`--no-${option}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
_getDefaultOptionValue (option) {
|
_getDefaultOptionValue<T, Option extends { default: ((cmd: Command) => T) | T }>(option: Option) {
|
||||||
return typeof option.default === 'function' ? option.default(this.cmd) : option.default
|
return option.default instanceof Function ? option.default(this.cmd) : option.default
|
||||||
}
|
}
|
||||||
|
|
||||||
_getMinimistOptions () {
|
_getMinimistOptions() {
|
||||||
const minimistOptions = {
|
const minimistOptions = {
|
||||||
alias: {},
|
alias: {},
|
||||||
boolean: [],
|
boolean: [],
|
||||||
@ -193,7 +224,7 @@ export default class NuxtCommand extends Hookable {
|
|||||||
return minimistOptions
|
return minimistOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
_getHelp () {
|
_getHelp() {
|
||||||
const options = []
|
const options = []
|
||||||
let maxOptionLength = 0
|
let maxOptionLength = 0
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import type { ParsedArgs } from 'minimist'
|
||||||
|
|
||||||
import { MODES, TARGETS } from 'nuxt/utils'
|
import { MODES, TARGETS } from 'nuxt/utils'
|
||||||
|
import NuxtCommand from '../command'
|
||||||
import { common, locking } from '../options'
|
import { common, locking } from '../options'
|
||||||
import { createLock } from '../utils'
|
import { createLock } from '../utils'
|
||||||
|
|
||||||
@ -14,7 +17,7 @@ export default {
|
|||||||
alias: 'a',
|
alias: 'a',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Launch webpack-bundle-analyzer to optimize your bundles',
|
description: 'Launch webpack-bundle-analyzer to optimize your bundles',
|
||||||
prepare (cmd, options, argv) {
|
prepare (cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
// Analyze option
|
// Analyze option
|
||||||
options.build = options.build || {}
|
options.build = options.build || {}
|
||||||
if (argv.analyze && typeof options.build.analyze !== 'object') {
|
if (argv.analyze && typeof options.build.analyze !== 'object') {
|
||||||
@ -26,7 +29,7 @@ export default {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
description: 'Enable Vue devtools',
|
description: 'Enable Vue devtools',
|
||||||
prepare (cmd, options, argv) {
|
prepare (cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
options.vue = options.vue || {}
|
options.vue = options.vue || {}
|
||||||
options.vue.config = options.vue.config || {}
|
options.vue.config = options.vue.config || {}
|
||||||
if (argv.devtools) {
|
if (argv.devtools) {
|
||||||
@ -43,7 +46,7 @@ export default {
|
|||||||
alias: 'q',
|
alias: 'q',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Disable output except for errors',
|
description: 'Disable output except for errors',
|
||||||
prepare (cmd, options, argv) {
|
prepare (cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
// Silence output when using --quiet
|
// Silence output when using --quiet
|
||||||
options.build = options.build || {}
|
options.build = options.build || {}
|
||||||
if (argv.quiet) {
|
if (argv.quiet) {
|
||||||
@ -55,14 +58,14 @@ export default {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
description: 'Bundle all server dependencies (useful for nuxt-start)',
|
description: 'Bundle all server dependencies (useful for nuxt-start)',
|
||||||
prepare (cmd, options, argv) {
|
prepare (cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
if (argv.standalone) {
|
if (argv.standalone) {
|
||||||
options.build.standalone = true
|
options.build.standalone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const config = await cmd.getNuxtConfig({ dev: false, server: false, _build: true })
|
const config = await cmd.getNuxtConfig({ dev: false, server: false, _build: true })
|
||||||
config.server = (config.mode === MODES.spa || config.ssr === false) && cmd.argv.generate !== false
|
config.server = (config.mode === MODES.spa || config.ssr === false) && cmd.argv.generate !== false
|
||||||
const nuxt = await cmd.getNuxt(config)
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import opener from 'opener'
|
import opener from 'opener'
|
||||||
|
import type { ParsedArgs } from 'minimist'
|
||||||
|
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
|
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
import { common, server } from '../options'
|
import { common, server } from '../options'
|
||||||
import { eventsMapping, formatPath } from '../utils'
|
import { eventsMapping, formatPath } from '../utils'
|
||||||
import { showBanner } from '../utils/banner'
|
import { showBanner } from '../utils/banner'
|
||||||
@ -20,13 +25,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const { argv } = cmd
|
const { argv } = cmd
|
||||||
|
|
||||||
await this.startDev(cmd, argv, argv.open)
|
await this.startDev(cmd, argv, argv.open)
|
||||||
},
|
},
|
||||||
|
|
||||||
async startDev (cmd, argv) {
|
async startDev (cmd: NuxtCommand, argv) {
|
||||||
let nuxt
|
let nuxt
|
||||||
try {
|
try {
|
||||||
nuxt = await this._listenDev(cmd, argv)
|
nuxt = await this._listenDev(cmd, argv)
|
||||||
@ -45,7 +50,7 @@ export default {
|
|||||||
return nuxt
|
return nuxt
|
||||||
},
|
},
|
||||||
|
|
||||||
async _listenDev (cmd, argv) {
|
async _listenDev (cmd: NuxtCommand, argv) {
|
||||||
const config = await cmd.getNuxtConfig({ dev: true, _build: true })
|
const config = await cmd.getNuxtConfig({ dev: true, _build: true })
|
||||||
const nuxt = await cmd.getNuxt(config)
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
|
||||||
@ -73,7 +78,7 @@ export default {
|
|||||||
return nuxt
|
return nuxt
|
||||||
},
|
},
|
||||||
|
|
||||||
async _buildDev (cmd, argv, nuxt) {
|
async _buildDev (cmd: NuxtCommand, argv: ParsedArgs, nuxt: Nuxt) {
|
||||||
// Create builder instance
|
// Create builder instance
|
||||||
const builder = await cmd.getBuilder(nuxt)
|
const builder = await cmd.getBuilder(nuxt)
|
||||||
|
|
||||||
@ -110,7 +115,7 @@ export default {
|
|||||||
await this.startDev(cmd, argv)
|
await this.startDev(cmd, argv)
|
||||||
},
|
},
|
||||||
|
|
||||||
onBundlerChange (path) {
|
onBundlerChange (path: string) {
|
||||||
this.logChanged({ event: 'change', path })
|
this.logChanged({ event: 'change', path })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { TARGETS } from 'nuxt/utils'
|
import { TARGETS } from 'nuxt/utils'
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
import { common, locking } from '../options'
|
import { common, locking } from '../options'
|
||||||
import { createLock } from '../utils'
|
import { createLock } from '../utils'
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ export default {
|
|||||||
description: 'Exit with non-zero status code if there are errors when exporting pages'
|
description: 'Exit with non-zero status code if there are errors when exporting pages'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const config = await cmd.getNuxtConfig({
|
const config = await cmd.getNuxtConfig({
|
||||||
dev: false,
|
dev: false,
|
||||||
target: TARGETS.static,
|
target: TARGETS.static,
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import type { ParsedArgs } from 'minimist'
|
||||||
import { TARGETS } from 'nuxt/utils'
|
import { TARGETS } from 'nuxt/utils'
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
import { common, locking } from '../options'
|
import { common, locking } from '../options'
|
||||||
import { normalizeArg, createLock } from '../utils'
|
import { normalizeArg, createLock } from '../utils'
|
||||||
|
|
||||||
@ -18,7 +20,7 @@ export default {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
description: 'Enable Vue devtools',
|
description: 'Enable Vue devtools',
|
||||||
prepare (cmd, options, argv) {
|
prepare (_cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
options.vue = options.vue || {}
|
options.vue = options.vue || {}
|
||||||
options.vue.config = options.vue.config || {}
|
options.vue.config = options.vue.config || {}
|
||||||
if (argv.devtools) {
|
if (argv.devtools) {
|
||||||
@ -30,7 +32,7 @@ export default {
|
|||||||
alias: 'q',
|
alias: 'q',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Disable output except for errors',
|
description: 'Disable output except for errors',
|
||||||
prepare (cmd, options, argv) {
|
prepare (_cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
// Silence output when using --quiet
|
// Silence output when using --quiet
|
||||||
options.build = options.build || {}
|
options.build = options.build || {}
|
||||||
if (argv.quiet) {
|
if (argv.quiet) {
|
||||||
@ -41,7 +43,7 @@ export default {
|
|||||||
modern: {
|
modern: {
|
||||||
...common.modern,
|
...common.modern,
|
||||||
description: 'Generate app in modern build (modern mode can be only client)',
|
description: 'Generate app in modern build (modern mode can be only client)',
|
||||||
prepare (cmd, options, argv) {
|
prepare (_cmd: NuxtCommand, options, argv: ParsedArgs) {
|
||||||
if (normalizeArg(argv.modern)) {
|
if (normalizeArg(argv.modern)) {
|
||||||
options.modern = 'client'
|
options.modern = 'client'
|
||||||
}
|
}
|
||||||
@ -53,7 +55,7 @@ export default {
|
|||||||
description: 'Exit with non-zero status code if there are errors when generating pages'
|
description: 'Exit with non-zero status code if there are errors when generating pages'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const config = await cmd.getNuxtConfig({
|
const config = await cmd.getNuxtConfig({
|
||||||
dev: false,
|
dev: false,
|
||||||
_build: cmd.argv.build,
|
_build: cmd.argv.build,
|
||||||
|
@ -12,7 +12,7 @@ export default {
|
|||||||
help: common.help,
|
help: common.help,
|
||||||
version: common.version
|
version: common.version
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const [name] = cmd._argv
|
const [name] = cmd._argv
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return listCommands()
|
return listCommands()
|
||||||
|
@ -9,7 +9,7 @@ const _commands = {
|
|||||||
help: () => import('./help')
|
help: () => import('./help')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getCommand (name) {
|
export default function getCommand (name: keyof typeof _commands) {
|
||||||
if (!_commands[name]) {
|
if (!_commands[name]) {
|
||||||
return Promise.resolve(null)
|
return Promise.resolve(null)
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@ import serveStatic from 'serve-static'
|
|||||||
import compression from 'compression'
|
import compression from 'compression'
|
||||||
import { getNuxtConfig } from 'nuxt/config'
|
import { getNuxtConfig } from 'nuxt/config'
|
||||||
import { TARGETS } from 'nuxt/utils'
|
import { TARGETS } from 'nuxt/utils'
|
||||||
import { common, server } from '../options'
|
|
||||||
import { showBanner } from '../utils/banner'
|
|
||||||
import { Listener } from 'nuxt/server'
|
import { Listener } from 'nuxt/server'
|
||||||
import { Nuxt } from 'nuxt/core'
|
import { Nuxt } from 'nuxt/core'
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
|
import { common, server } from '../options'
|
||||||
|
import { showBanner } from '../utils/banner'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'serve',
|
name: 'serve',
|
||||||
@ -20,7 +21,7 @@ export default {
|
|||||||
help: common.help,
|
help: common.help,
|
||||||
...server
|
...server
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
let options = await cmd.getNuxtConfig({ dev: false })
|
let options = await cmd.getNuxtConfig({ dev: false })
|
||||||
// add default options
|
// add default options
|
||||||
options = getNuxtConfig(options)
|
options = getNuxtConfig(options)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { TARGETS } from 'nuxt/utils'
|
import { TARGETS } from 'nuxt/utils'
|
||||||
|
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
import { common, server } from '../options'
|
import { common, server } from '../options'
|
||||||
import { showBanner } from '../utils/banner'
|
import { showBanner } from '../utils/banner'
|
||||||
|
|
||||||
@ -10,7 +12,7 @@ export default {
|
|||||||
...common,
|
...common,
|
||||||
...server
|
...server
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const config = await cmd.getNuxtConfig({ dev: false, _start: true })
|
const config = await cmd.getNuxtConfig({ dev: false, _start: true })
|
||||||
if (config.target === TARGETS.static) {
|
if (config.target === TARGETS.static) {
|
||||||
throw new Error('You cannot use `nuxt start` with ' + TARGETS.static + ' target, please use `nuxt export` and `nuxt serve`')
|
throw new Error('You cannot use `nuxt start` with ' + TARGETS.static + ' target, please use `nuxt export` and `nuxt serve`')
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import util from 'util'
|
import util from 'util'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import get from 'lodash/get'
|
import get from 'lodash/get'
|
||||||
|
|
||||||
|
import type NuxtCommand from '../command'
|
||||||
import { common } from '../options'
|
import { common } from '../options'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -32,7 +34,7 @@ export default {
|
|||||||
description: 'Inspect development mode webpack config'
|
description: 'Inspect development mode webpack config'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run (cmd) {
|
async run (cmd: NuxtCommand) {
|
||||||
const { name } = cmd.argv
|
const { name } = cmd.argv
|
||||||
const queries = [...cmd.argv._]
|
const queries = [...cmd.argv._]
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { startSpaces, optionSpaces } from './utils/constants'
|
|||||||
import getCommand from './commands'
|
import getCommand from './commands'
|
||||||
|
|
||||||
export default async function listCommands () {
|
export default async function listCommands () {
|
||||||
const commandsOrder = ['dev', 'build', 'generate', 'start', 'help']
|
const commandsOrder = ['dev', 'build', 'generate', 'start', 'help'] as const
|
||||||
|
|
||||||
// Load all commands
|
// Load all commands
|
||||||
const _commands = await Promise.all(
|
const _commands = await Promise.all(
|
||||||
|
@ -5,7 +5,7 @@ import NuxtCommand from './command'
|
|||||||
import setup from './setup'
|
import setup from './setup'
|
||||||
import getCommand from './commands'
|
import getCommand from './commands'
|
||||||
|
|
||||||
function packageExists (name) {
|
function packageExists (name: string) {
|
||||||
try {
|
try {
|
||||||
require.resolve(name)
|
require.resolve(name)
|
||||||
return true
|
return true
|
||||||
@ -14,7 +14,7 @@ function packageExists (name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function run(_argv, hooks = {}) {
|
export default async function run (_argv: NodeJS.Process['argv'], hooks = {}) {
|
||||||
// Check for not installing both nuxt and nuxt-edge
|
// Check for not installing both nuxt and nuxt-edge
|
||||||
const dupPkg = '@nuxt/' + (pkgName === '@nuxt/cli-edge' ? 'cli' : 'cli-edge')
|
const dupPkg = '@nuxt/' + (pkgName === '@nuxt/cli-edge' ? 'cli' : 'cli-edge')
|
||||||
if (packageExists(dupPkg)) {
|
if (packageExists(dupPkg)) {
|
||||||
@ -25,7 +25,7 @@ export default async function run(_argv, hooks = {}) {
|
|||||||
const argv = _argv ? Array.from(_argv) : process.argv.slice(2)
|
const argv = _argv ? Array.from(_argv) : process.argv.slice(2)
|
||||||
|
|
||||||
// Check for internal command
|
// Check for internal command
|
||||||
let cmd = await getCommand(argv[0])
|
let cmd = await getCommand(argv[0] as any)
|
||||||
|
|
||||||
// Matching `nuxt` or `nuxt [dir]` or `nuxt -*` for `nuxt dev` shortcut
|
// Matching `nuxt` or `nuxt [dir]` or `nuxt -*` for `nuxt dev` shortcut
|
||||||
if (!cmd && (!argv[0] || argv[0][0] === '-' || (argv[0] !== 'static' && fs.existsSync(argv[0])))) {
|
if (!cmd && (!argv[0] || argv[0][0] === '-' || (argv[0] !== 'static' && fs.existsSync(argv[0])))) {
|
||||||
|
@ -4,7 +4,7 @@ import { fatalBox } from './utils/formatting'
|
|||||||
|
|
||||||
let _setup = false
|
let _setup = false
|
||||||
|
|
||||||
export default function setup ({ dev }) {
|
export default function setup ({ dev }: { dev: boolean }) {
|
||||||
// Apply default NODE_ENV if not provided
|
// Apply default NODE_ENV if not provided
|
||||||
if (!process.env.NODE_ENV) {
|
if (!process.env.NODE_ENV) {
|
||||||
process.env.NODE_ENV = dev ? 'development' : 'production'
|
process.env.NODE_ENV = dev ? 'development' : 'production'
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import env from 'std-env'
|
import env from 'std-env'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
|
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
import { successBox } from './formatting'
|
import { successBox } from './formatting'
|
||||||
import { getFormattedMemoryUsage } from './memory'
|
import { getFormattedMemoryUsage } from './memory'
|
||||||
|
|
||||||
export function showBanner (nuxt, showMemoryUsage = true) {
|
export function showBanner (nuxt: Nuxt, showMemoryUsage = true) {
|
||||||
if (env.test) {
|
if (env.test) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -23,7 +25,7 @@ export function showBanner (nuxt, showMemoryUsage = true) {
|
|||||||
const { bannerColor, badgeMessages } = nuxt.options.cli
|
const { bannerColor, badgeMessages } = nuxt.options.cli
|
||||||
titleLines.push(`${chalk[bannerColor].bold('Nuxt.js')} @ ${nuxt.constructor.version || 'exotic'}\n`)
|
titleLines.push(`${chalk[bannerColor].bold('Nuxt.js')} @ ${nuxt.constructor.version || 'exotic'}\n`)
|
||||||
|
|
||||||
const label = name => chalk.bold.cyan(`▸ ${name}:`)
|
const label = (name: string) => chalk.bold.cyan(`▸ ${name}:`)
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
const isDev = nuxt.options.dev
|
const isDev = nuxt.options.dev
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import defaultsDeep from 'lodash/defaultsDeep'
|
import defaultsDeep from 'lodash/defaultsDeep'
|
||||||
|
import type { ParsedArgs } from 'minimist'
|
||||||
|
|
||||||
import { loadNuxtConfig as _loadNuxtConfig, getDefaultNuxtConfig } from 'nuxt/config'
|
import { loadNuxtConfig as _loadNuxtConfig, getDefaultNuxtConfig } from 'nuxt/config'
|
||||||
import { MODES } from 'nuxt/utils'
|
import { MODES } from 'nuxt/utils'
|
||||||
|
|
||||||
export async function loadNuxtConfig (argv, configContext) {
|
export async function loadNuxtConfig (argv: ParsedArgs, configContext) {
|
||||||
const rootDir = path.resolve(argv._[0] || '.')
|
const rootDir = path.resolve(argv._[0] || '.')
|
||||||
const configFile = argv['config-file']
|
const configFile = argv['config-file']
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ import chalk from 'chalk'
|
|||||||
import boxen from 'boxen'
|
import boxen from 'boxen'
|
||||||
import { maxCharsPerLine } from './constants'
|
import { maxCharsPerLine } from './constants'
|
||||||
|
|
||||||
export function indent (count, chr = ' ') {
|
export function indent (count: number, chr = ' ') {
|
||||||
return chr.repeat(count)
|
return chr.repeat(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function indentLines (string, spaces, firstLineSpaces) {
|
export function indentLines (string: string | string[], spaces: number, firstLineSpaces?: number) {
|
||||||
const lines = Array.isArray(string) ? string : string.split('\n')
|
const lines = Array.isArray(string) ? string : string.split('\n')
|
||||||
let s = ''
|
let s = ''
|
||||||
if (lines.length) {
|
if (lines.length) {
|
||||||
@ -21,11 +21,11 @@ export function indentLines (string, spaces, firstLineSpaces) {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
export function foldLines (string, spaces, firstLineSpaces, charsPerLine = maxCharsPerLine()) {
|
export function foldLines (string: string, spaces: number, firstLineSpaces?: number, charsPerLine = maxCharsPerLine()) {
|
||||||
return indentLines(wrapAnsi(string, charsPerLine), spaces, firstLineSpaces)
|
return indentLines(wrapAnsi(string, charsPerLine), spaces, firstLineSpaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function colorize (text) {
|
export function colorize (text: string) {
|
||||||
return text
|
return text
|
||||||
.replace(/\[[^ ]+]/g, m => chalk.grey(m))
|
.replace(/\[[^ ]+]/g, m => chalk.grey(m))
|
||||||
.replace(/<[^ ]+>/g, m => chalk.green(m))
|
.replace(/<[^ ]+>/g, m => chalk.green(m))
|
||||||
@ -33,7 +33,7 @@ export function colorize (text) {
|
|||||||
.replace(/`([^`]+)`/g, (_, m) => chalk.bold.cyan(m))
|
.replace(/`([^`]+)`/g, (_, m) => chalk.bold.cyan(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function box (message, title, options) {
|
export function box (message: string, title: string, options?: boxen.Options) {
|
||||||
return boxen([
|
return boxen([
|
||||||
title || chalk.white('Nuxt Message'),
|
title || chalk.white('Nuxt Message'),
|
||||||
'',
|
'',
|
||||||
@ -46,24 +46,24 @@ export function box (message, title, options) {
|
|||||||
}, options)) + '\n'
|
}, options)) + '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function successBox (message, title) {
|
export function successBox (message: string, title?: string) {
|
||||||
return box(message, title || chalk.green('✔ Nuxt Success'), {
|
return box(message, title || chalk.green('✔ Nuxt Success'), {
|
||||||
borderColor: 'green'
|
borderColor: 'green'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function warningBox (message, title) {
|
export function warningBox (message: string, title?: string) {
|
||||||
return box(message, title || chalk.yellow('⚠ Nuxt Warning'), {
|
return box(message, title || chalk.yellow('⚠ Nuxt Warning'), {
|
||||||
borderColor: 'yellow'
|
borderColor: 'yellow'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function errorBox (message, title) {
|
export function errorBox (message: string, title?: string) {
|
||||||
return box(message, title || chalk.red('✖ Nuxt Error'), {
|
return box(message, title || chalk.red('✖ Nuxt Error'), {
|
||||||
borderColor: 'red'
|
borderColor: 'red'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fatalBox (message, title) {
|
export function fatalBox (message: string, title?: string) {
|
||||||
return errorBox(message, title || chalk.red('✖ Nuxt Fatal Error'))
|
return errorBox(message, title || chalk.red('✖ Nuxt Fatal Error'))
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ export const eventsMapping = {
|
|||||||
unlink: { icon: '-', color: 'red', action: 'Removed' }
|
unlink: { icon: '-', color: 'red', action: 'Removed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatPath (filePath) {
|
export function formatPath (filePath: string) {
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ export function formatPath (filePath) {
|
|||||||
* @param {*} defaultValue
|
* @param {*} defaultValue
|
||||||
* @returns formatted argument
|
* @returns formatted argument
|
||||||
*/
|
*/
|
||||||
export function normalizeArg (arg, defaultValue) {
|
export function normalizeArg (arg: boolean | 'true' | '' | 'false', defaultValue?: boolean) {
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
case 'true': arg = true; break
|
case 'true': arg = true; break
|
||||||
case '': arg = true; break
|
case '': arg = true; break
|
||||||
@ -37,7 +37,7 @@ export function normalizeArg (arg, defaultValue) {
|
|||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forceExit (cmdName, timeout) {
|
export function forceExit (cmdName: string, timeout: number | false) {
|
||||||
if (timeout !== false) {
|
if (timeout !== false) {
|
||||||
const exitTimeout = setTimeout(() => {
|
const exitTimeout = setTimeout(() => {
|
||||||
const msg = `The command 'nuxt ${cmdName}' finished but did not exit after ${timeout}s
|
const msg = `The command 'nuxt ${cmdName}' finished but did not exit after ${timeout}s
|
||||||
@ -59,6 +59,6 @@ ${chalk.bold('DeprecationWarning: Starting with Nuxt version 3 this will be a fa
|
|||||||
|
|
||||||
// An immediate export throws an error when mocking with jest
|
// An immediate export throws an error when mocking with jest
|
||||||
// TypeError: Cannot set property createLock of #<Object> which has only a getter
|
// TypeError: Cannot set property createLock of #<Object> which has only a getter
|
||||||
export function createLock (...args) {
|
export function createLock (...args: Parameters<typeof lock>) {
|
||||||
return lock(...args)
|
return lock(...args)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { loadNuxt } from 'nuxt/core'
|
import { loadNuxt } from 'nuxt/core'
|
||||||
import { getBuilder } from 'nuxt/builder'
|
import { getBuilder } from 'nuxt/builder'
|
||||||
|
|
||||||
export async function getWebpackConfig(name = 'client', loadOptions = {}) {
|
export async function getWebpackConfig (name = 'client', loadOptions = {}) {
|
||||||
const nuxt = await loadNuxt(loadOptions)
|
const nuxt = await loadNuxt(loadOptions)
|
||||||
const builder = await getBuilder(nuxt)
|
const builder = await getBuilder(nuxt)
|
||||||
const { bundleBuilder } = builder
|
const { bundleBuilder } = builder
|
||||||
|
@ -8,18 +8,27 @@ import jiti from 'jiti'
|
|||||||
import _createRequire from 'create-require'
|
import _createRequire from 'create-require'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
import * as rc from 'rc9'
|
import * as rc from 'rc9'
|
||||||
|
|
||||||
|
import { LoadOptions } from 'nuxt/core/load'
|
||||||
import { defaultNuxtConfigFile } from './config'
|
import { defaultNuxtConfigFile } from './config'
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const isJest = typeof jest !== 'undefined'
|
const isJest = typeof jest !== 'undefined'
|
||||||
|
|
||||||
|
export interface EnvConfig {
|
||||||
|
dotenv?: string
|
||||||
|
env?: NodeJS.ProcessEnv & { _applied?: boolean }
|
||||||
|
expand?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export async function loadNuxtConfig ({
|
export async function loadNuxtConfig ({
|
||||||
rootDir = '.',
|
rootDir = '.',
|
||||||
envConfig = {},
|
envConfig = {},
|
||||||
configFile = defaultNuxtConfigFile,
|
configFile = defaultNuxtConfigFile,
|
||||||
configContext = {},
|
configContext = {},
|
||||||
configOverrides = {},
|
configOverrides = {},
|
||||||
createRequire = module => isJest ? _createRequire(module.filename) : jiti(module.filename)
|
createRequire = (module: NodeJS.Module) => isJest ? _createRequire(module.filename) : jiti(module.filename)
|
||||||
} = {}) {
|
}: LoadOptions = {}) {
|
||||||
rootDir = path.resolve(rootDir)
|
rootDir = path.resolve(rootDir)
|
||||||
|
|
||||||
let options = {}
|
let options = {}
|
||||||
@ -120,7 +129,7 @@ export async function loadNuxtConfig ({
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadEnv (envConfig, rootDir = process.cwd()) {
|
function loadEnv (envConfig: EnvConfig, rootDir = process.cwd()) {
|
||||||
const env = Object.create(null)
|
const env = Object.create(null)
|
||||||
|
|
||||||
// Read dotenv
|
// Read dotenv
|
||||||
@ -147,13 +156,13 @@ function loadEnv (envConfig, rootDir = process.cwd()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://github.com/motdotla/dotenv-expand
|
// Based on https://github.com/motdotla/dotenv-expand
|
||||||
function expand (target, source = {}, parse = v => v) {
|
function expand (target: Record<string, string>, source: Record<string, string> = {}, parse = (v: string) => v) {
|
||||||
function getValue (key) {
|
function getValue (key: string) {
|
||||||
// Source value 'wins' over target value
|
// Source value 'wins' over target value
|
||||||
return source[key] !== undefined ? source[key] : target[key]
|
return source[key] !== undefined ? source[key] : target[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
function interpolate (value) {
|
function interpolate (value: string): string {
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -162,7 +171,8 @@ function expand (target, source = {}, parse = v => v) {
|
|||||||
const parts = /(.?)\${?([a-zA-Z0-9_:]+)?}?/g.exec(match)
|
const parts = /(.?)\${?([a-zA-Z0-9_:]+)?}?/g.exec(match)
|
||||||
const prefix = parts[1]
|
const prefix = parts[1]
|
||||||
|
|
||||||
let value, replacePart
|
let value: string
|
||||||
|
let replacePart: string
|
||||||
|
|
||||||
if (prefix === '\\') {
|
if (prefix === '\\') {
|
||||||
replacePart = parts[0]
|
replacePart = parts[0]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { EnvConfig } from 'nuxt/config/load'
|
||||||
import { loadNuxtConfig } from '../config'
|
import { loadNuxtConfig } from '../config'
|
||||||
import Nuxt from './nuxt'
|
import Nuxt from './nuxt'
|
||||||
|
|
||||||
@ -8,7 +9,19 @@ const OVERRIDES = {
|
|||||||
start: { dev: false, _start: true }
|
start: { dev: false, _start: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadNuxt (loadOptions) {
|
export interface LoadOptions {
|
||||||
|
for?: keyof typeof OVERRIDES
|
||||||
|
ready?: boolean
|
||||||
|
|
||||||
|
rootDir?: string
|
||||||
|
envConfig?: EnvConfig
|
||||||
|
configFile?: string
|
||||||
|
configContext?: {}
|
||||||
|
configOverrides?: {},
|
||||||
|
createRequire?: (module: NodeJS.Module) => NodeJS.Require
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadNuxt (loadOptions: LoadOptions | LoadOptions['for']) {
|
||||||
// Normalize loadOptions
|
// Normalize loadOptions
|
||||||
if (typeof loadOptions === 'string') {
|
if (typeof loadOptions === 'string') {
|
||||||
loadOptions = { for: loadOptions }
|
loadOptions = { for: loadOptions }
|
||||||
|
@ -5,8 +5,24 @@ import consola from 'consola'
|
|||||||
|
|
||||||
import { chainFn, sequence } from 'nuxt/utils'
|
import { chainFn, sequence } from 'nuxt/utils'
|
||||||
|
|
||||||
|
import Nuxt from './nuxt'
|
||||||
|
|
||||||
|
interface Module {
|
||||||
|
src: string
|
||||||
|
options: Record<string, any>
|
||||||
|
handler: () => any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Template {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export default class ModuleContainer {
|
export default class ModuleContainer {
|
||||||
constructor (nuxt) {
|
nuxt: Nuxt
|
||||||
|
options: Nuxt['options']
|
||||||
|
requiredModules: Record<string, Module>
|
||||||
|
|
||||||
|
constructor (nuxt: Nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
this.requiredModules = {}
|
this.requiredModules = {}
|
||||||
@ -83,7 +99,7 @@ export default class ModuleContainer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
addLayout (template, name) {
|
addLayout (template, 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]
|
||||||
@ -101,7 +117,7 @@ export default class ModuleContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addErrorLayout (dst) {
|
addErrorLayout (dst: string) {
|
||||||
const relativeBuildDir = path.relative(this.options.rootDir, this.options.buildDir)
|
const relativeBuildDir = path.relative(this.options.rootDir, this.options.buildDir)
|
||||||
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
this.options.ErrorPage = `~/${relativeBuildDir}/${dst}`
|
||||||
}
|
}
|
||||||
@ -121,13 +137,13 @@ export default class ModuleContainer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
requireModule (moduleOpts) {
|
requireModule (moduleOpts: Module) {
|
||||||
return this.addModule(moduleOpts)
|
return this.addModule(moduleOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
async addModule (moduleOpts) {
|
async addModule (moduleOpts) {
|
||||||
let src
|
let src
|
||||||
let options
|
let options: Record<string, any>
|
||||||
let handler
|
let handler
|
||||||
|
|
||||||
// Type 1: String or Function
|
// Type 1: String or Function
|
||||||
@ -142,7 +158,7 @@ export default class ModuleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Define handler if src is a function
|
// Define handler if src is a function
|
||||||
if (typeof src === 'function') {
|
if (src instanceof Function) {
|
||||||
handler = src
|
handler = src
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import isPlainObject from 'lodash/isPlainObject'
|
import isPlainObject from 'lodash/isPlainObject'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import Hookable from 'hable'
|
import Hookable from 'hookable'
|
||||||
|
|
||||||
import { defineAlias } from 'nuxt/utils'
|
import { defineAlias } from 'nuxt/utils'
|
||||||
import { getNuxtConfig } from 'nuxt/config'
|
import { getNuxtConfig } from 'nuxt/config'
|
||||||
@ -13,6 +13,17 @@ import ModuleContainer from './module'
|
|||||||
import Resolver from './resolver'
|
import Resolver from './resolver'
|
||||||
|
|
||||||
export default class Nuxt extends Hookable {
|
export default class Nuxt extends Hookable {
|
||||||
|
_ready?: Promise<this>
|
||||||
|
_initCalled?: boolean
|
||||||
|
|
||||||
|
options: any
|
||||||
|
resolver: Resolver
|
||||||
|
moduleContainer: ModuleContainer
|
||||||
|
server?: Server
|
||||||
|
renderer?: Server
|
||||||
|
render?: Server['app']
|
||||||
|
showReady?: () => void
|
||||||
|
|
||||||
constructor (options = {}) {
|
constructor (options = {}) {
|
||||||
super(consola)
|
super(consola)
|
||||||
|
|
||||||
@ -103,13 +114,14 @@ export default class Nuxt extends Hookable {
|
|||||||
defineAlias(this, this.server, ['renderRoute', 'renderAndGetWindow', 'listen'])
|
defineAlias(this, this.server, ['renderRoute', 'renderAndGetWindow', 'listen'])
|
||||||
}
|
}
|
||||||
|
|
||||||
async close (callback) {
|
async close (callback?: () => any | Promise<any>) {
|
||||||
await this.callHook('close', this)
|
await this.callHook('close', this)
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
await callback()
|
await callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearHooks()
|
// Deleting as no longer exists on `hookable`
|
||||||
|
// this.clearHooks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { resolve, join } from 'path'
|
import { resolve, join } from 'path'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import consola from 'consola'
|
|
||||||
|
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
import {
|
import {
|
||||||
startsWithRootAlias,
|
startsWithRootAlias,
|
||||||
startsWithSrcAlias,
|
startsWithSrcAlias,
|
||||||
@ -9,8 +9,25 @@ import {
|
|||||||
clearRequireCache
|
clearRequireCache
|
||||||
} from 'nuxt/utils'
|
} from 'nuxt/utils'
|
||||||
|
|
||||||
|
interface ResolvePathOptions {
|
||||||
|
isAlias?: boolean
|
||||||
|
isModule?: boolean
|
||||||
|
isStyle?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequireModuleOptions {
|
||||||
|
useESM?: boolean
|
||||||
|
isAlias?: boolean
|
||||||
|
interopDefault?: any
|
||||||
|
}
|
||||||
|
|
||||||
export default class Resolver {
|
export default class Resolver {
|
||||||
constructor (nuxt) {
|
_require: NodeJS.Require
|
||||||
|
_resolve: RequireResolve
|
||||||
|
nuxt: Nuxt
|
||||||
|
options: Nuxt['options']
|
||||||
|
|
||||||
|
constructor (nuxt: Nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = this.nuxt.options
|
this.options = this.nuxt.options
|
||||||
|
|
||||||
@ -26,7 +43,7 @@ export default class Resolver {
|
|||||||
this._resolve = require.resolve
|
this._resolve = require.resolve
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveModule (path) {
|
resolveModule (path: string) {
|
||||||
try {
|
try {
|
||||||
return this._resolve(path, {
|
return this._resolve(path, {
|
||||||
paths: this.options.modulesDir
|
paths: this.options.modulesDir
|
||||||
@ -42,7 +59,7 @@ export default class Resolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveAlias (path) {
|
resolveAlias (path: string) {
|
||||||
if (startsWithRootAlias(path)) {
|
if (startsWithRootAlias(path)) {
|
||||||
return join(this.options.rootDir, path.substr(2))
|
return join(this.options.rootDir, path.substr(2))
|
||||||
}
|
}
|
||||||
@ -54,21 +71,13 @@ export default class Resolver {
|
|||||||
return resolve(this.options.srcDir, path)
|
return resolve(this.options.srcDir, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvePath (path, { alias, isAlias = alias, module, isModule = module, isStyle } = {}) {
|
resolvePath (path: string, { isAlias, isModule, isStyle }: ResolvePathOptions = {}) {
|
||||||
// TODO: Remove in Nuxt 3
|
|
||||||
if (alias) {
|
|
||||||
consola.warn('Using alias is deprecated and will be removed in Nuxt 3. Use `isAlias` instead.')
|
|
||||||
}
|
|
||||||
if (module) {
|
|
||||||
consola.warn('Using module is deprecated and will be removed in Nuxt 3. Use `isModule` instead.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast return in case of path exists
|
// Fast return in case of path exists
|
||||||
if (fs.existsSync(path)) {
|
if (fs.existsSync(path)) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolvedPath
|
let resolvedPath: string
|
||||||
|
|
||||||
// Try to resolve it as a regular module
|
// Try to resolve it as a regular module
|
||||||
if (isModule !== false) {
|
if (isModule !== false) {
|
||||||
@ -85,7 +94,7 @@ export default class Resolver {
|
|||||||
resolvedPath = path
|
resolvedPath = path
|
||||||
}
|
}
|
||||||
|
|
||||||
let isDirectory
|
let isDirectory: boolean
|
||||||
|
|
||||||
// Check if resolvedPath exits and is not a directory
|
// Check if resolvedPath exits and is not a directory
|
||||||
if (fs.existsSync(resolvedPath)) {
|
if (fs.existsSync(resolvedPath)) {
|
||||||
@ -119,22 +128,11 @@ export default class Resolver {
|
|||||||
throw new Error(`Cannot resolve "${path}" from "${resolvedPath}"`)
|
throw new Error(`Cannot resolve "${path}" from "${resolvedPath}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
requireModule (path, { esm, useESM = esm, alias, isAlias = alias, intropDefault, interopDefault = intropDefault } = {}) {
|
requireModule <T>(path: string, { useESM, isAlias, interopDefault }: RequireModuleOptions = {}): T {
|
||||||
let resolvedPath = path
|
let resolvedPath = path
|
||||||
let requiredModule
|
let requiredModule: any
|
||||||
|
|
||||||
// TODO: Remove in Nuxt 3
|
let lastError: any
|
||||||
if (intropDefault) {
|
|
||||||
consola.warn('Using intropDefault is deprecated and will be removed in Nuxt 3. Use `interopDefault` instead.')
|
|
||||||
}
|
|
||||||
if (alias) {
|
|
||||||
consola.warn('Using alias is deprecated and will be removed in Nuxt 3. Use `isAlias` instead.')
|
|
||||||
}
|
|
||||||
if (esm) {
|
|
||||||
consola.warn('Using esm is deprecated and will be removed in Nuxt 3. Use `useESM` instead.')
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastError
|
|
||||||
|
|
||||||
// Try to resolve path
|
// Try to resolve path
|
||||||
try {
|
try {
|
||||||
|
@ -6,10 +6,32 @@ import defu from 'defu'
|
|||||||
import htmlMinifier from 'html-minifier'
|
import htmlMinifier from 'html-minifier'
|
||||||
import { parse } from 'node-html-parser'
|
import { parse } from 'node-html-parser'
|
||||||
|
|
||||||
|
import type { Builder } from 'nuxt/builder'
|
||||||
|
import type { Nuxt } from 'nuxt/core'
|
||||||
import { isFullStatic, flatRoutes, isString, isUrl, promisifyRoute, waitFor, TARGETS } from 'nuxt/utils'
|
import { isFullStatic, flatRoutes, isString, isUrl, promisifyRoute, waitFor, TARGETS } from 'nuxt/utils'
|
||||||
|
|
||||||
export default class Generator {
|
export default class Generator {
|
||||||
constructor (nuxt, builder) {
|
_payload: null
|
||||||
|
setPayload: (payload: any) => void
|
||||||
|
|
||||||
|
builder?: Builder
|
||||||
|
isFullStatic: boolean
|
||||||
|
nuxt: Nuxt
|
||||||
|
options: Nuxt['options']
|
||||||
|
staticRoutes: string
|
||||||
|
srcBuiltPath: string
|
||||||
|
distPath: string
|
||||||
|
distNuxtPath: string
|
||||||
|
|
||||||
|
staticAssetsDir?: string
|
||||||
|
staticAssetsBase?: string
|
||||||
|
|
||||||
|
payloadDir?: string
|
||||||
|
|
||||||
|
routes: Array<{ route: string } & Record<string, any>>
|
||||||
|
generatedRoutes: Set<string>
|
||||||
|
|
||||||
|
constructor (nuxt: Nuxt, builder?: Builder) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
this.builder = builder
|
this.builder = builder
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import type { Nuxt } from 'nuxt/core'
|
||||||
|
|
||||||
import Generator from './generator'
|
import Generator from './generator'
|
||||||
export { default as Generator } from './generator'
|
export { default as Generator } from './generator'
|
||||||
|
|
||||||
export function getGenerator (nuxt) {
|
export function getGenerator (nuxt: Nuxt) {
|
||||||
return new Generator(nuxt)
|
return new Generator(nuxt)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
|
import { Server } from 'nuxt/server'
|
||||||
|
|
||||||
export default class ServerContext {
|
export default class ServerContext {
|
||||||
constructor (server) {
|
nuxt: Server['nuxt']
|
||||||
|
globals: Server['globals']
|
||||||
|
options: Server['options']
|
||||||
|
resources: Server['resources']
|
||||||
|
|
||||||
|
constructor (server: Server) {
|
||||||
this.nuxt = server.nuxt
|
this.nuxt = server.nuxt
|
||||||
this.globals = server.globals
|
this.globals = server.globals
|
||||||
this.options = server.options
|
this.options = server.options
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { timeout } from 'nuxt/utils'
|
import { DeterminedGlobals, timeout } from 'nuxt/utils'
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
globals: DeterminedGlobals
|
||||||
|
loadedCallback: string
|
||||||
|
loadingTimeout?: number
|
||||||
|
}
|
||||||
|
|
||||||
export default async function renderAndGetWindow (
|
export default async function renderAndGetWindow (
|
||||||
url = 'http://localhost:3000',
|
url = 'http://localhost:3000',
|
||||||
@ -8,7 +14,7 @@ export default async function renderAndGetWindow (
|
|||||||
loadedCallback,
|
loadedCallback,
|
||||||
loadingTimeout = 2000,
|
loadingTimeout = 2000,
|
||||||
globals
|
globals
|
||||||
} = {}
|
}: Options
|
||||||
) {
|
) {
|
||||||
const jsdom = await import('jsdom')
|
const jsdom = await import('jsdom')
|
||||||
.then(m => m.default || m)
|
.then(m => m.default || m)
|
||||||
@ -27,13 +33,13 @@ export default async function renderAndGetWindow (
|
|||||||
resources: 'usable',
|
resources: 'usable',
|
||||||
runScripts: 'dangerously',
|
runScripts: 'dangerously',
|
||||||
virtualConsole: true,
|
virtualConsole: true,
|
||||||
beforeParse (window) {
|
beforeParse (window: Window) {
|
||||||
// Mock window.scrollTo
|
// Mock window.scrollTo
|
||||||
window.scrollTo = () => {}
|
window.scrollTo = () => {}
|
||||||
}
|
}
|
||||||
}, jsdomOpts)
|
}, jsdomOpts)
|
||||||
|
|
||||||
const jsdomErrHandler = (err) => {
|
const jsdomErrHandler = (err: any) => {
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import http from 'http'
|
import http from 'http'
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
|
import type { ListenOptions } from 'net'
|
||||||
import enableDestroy from 'server-destroy'
|
import enableDestroy from 'server-destroy'
|
||||||
import ip from 'ip'
|
import ip from 'ip'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
@ -8,6 +9,19 @@ import pify from 'pify'
|
|||||||
let RANDOM_PORT = '0'
|
let RANDOM_PORT = '0'
|
||||||
|
|
||||||
export default class Listener {
|
export default class Listener {
|
||||||
|
port: number | string
|
||||||
|
host: string
|
||||||
|
socket: string
|
||||||
|
https: boolean
|
||||||
|
app: any
|
||||||
|
dev: boolean
|
||||||
|
baseURL: string
|
||||||
|
|
||||||
|
listening: boolean
|
||||||
|
_server: null | http.Server
|
||||||
|
server: null | http.Server
|
||||||
|
address: null
|
||||||
|
url: null | string
|
||||||
constructor ({ port, host, socket, https, app, dev, baseURL }) {
|
constructor ({ port, host, socket, https, app, dev, baseURL }) {
|
||||||
// Options
|
// Options
|
||||||
this.port = port
|
this.port = port
|
||||||
@ -43,6 +57,9 @@ export default class Listener {
|
|||||||
|
|
||||||
computeURL () {
|
computeURL () {
|
||||||
const address = this.server.address()
|
const address = this.server.address()
|
||||||
|
if (typeof address === 'string') {
|
||||||
|
return address
|
||||||
|
}
|
||||||
if (!this.socket) {
|
if (!this.socket) {
|
||||||
switch (address.address) {
|
switch (address.address) {
|
||||||
case '127.0.0.1': this.host = 'localhost'; break
|
case '127.0.0.1': this.host = 'localhost'; break
|
||||||
@ -68,7 +85,7 @@ export default class Listener {
|
|||||||
|
|
||||||
// Call server.listen
|
// Call server.listen
|
||||||
// Prepare listenArgs
|
// Prepare listenArgs
|
||||||
const listenArgs = this.socket ? { path: this.socket } : { host: this.host, port: this.port }
|
const listenArgs: ListenOptions = this.socket ? { path: this.socket } : { host: this.host, port: Number(this.port) }
|
||||||
listenArgs.exclusive = false
|
listenArgs.exclusive = false
|
||||||
|
|
||||||
// Call server.listen
|
// Call server.listen
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
import type { ServerResponse } from 'http'
|
||||||
|
import type { IncomingMessage } from 'connect'
|
||||||
|
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import onHeaders from 'on-headers'
|
import onHeaders from 'on-headers'
|
||||||
import { Timer } from 'nuxt/utils'
|
import { Timer } from 'nuxt/utils'
|
||||||
|
|
||||||
export default options => (req, res, next) => {
|
export default options => (_req: IncomingMessage, res: ServerResponse & { timing?: ServerTiming }, next: (err?: any) => void) => {
|
||||||
if (res.timing) {
|
if (res.timing) {
|
||||||
consola.warn('server-timing is already registered.')
|
consola.warn('server-timing is already registered.')
|
||||||
}
|
}
|
||||||
@ -31,13 +34,15 @@ export default options => (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ServerTiming extends Timer {
|
class ServerTiming extends Timer {
|
||||||
constructor (...args) {
|
headers: string[]
|
||||||
super(...args)
|
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
this.headers = []
|
this.headers = []
|
||||||
}
|
}
|
||||||
|
|
||||||
end (...args) {
|
end (name?: string) {
|
||||||
const time = super.end(...args)
|
const time = super.end(name)
|
||||||
if (time) {
|
if (time) {
|
||||||
this.headers.push(this.formatHeader(time))
|
this.headers.push(this.formatHeader(time))
|
||||||
}
|
}
|
||||||
@ -49,7 +54,7 @@ class ServerTiming extends Timer {
|
|||||||
this.headers.length = 0
|
this.headers.length = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
formatHeader (time) {
|
formatHeader (time: ReturnType<Timer['end']>) {
|
||||||
const desc = time.description ? `;desc="${time.description}"` : ''
|
const desc = time.description ? `;desc="${time.description}"` : ''
|
||||||
return `${time.name};dur=${time.duration}${desc}`
|
return `${time.name};dur=${time.duration}${desc}`
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { ServerResponse } from 'http'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import launchMiddleware from 'launch-editor-middleware'
|
import launchMiddleware from 'launch-editor-middleware'
|
||||||
import serveStatic from 'serve-static'
|
import serveStatic from 'serve-static'
|
||||||
import servePlaceholder from 'serve-placeholder'
|
import servePlaceholder from 'serve-placeholder'
|
||||||
import connect from 'connect'
|
import connect, { IncomingMessage } from 'connect'
|
||||||
import { determineGlobals, isUrl } from 'nuxt/utils'
|
import type { TemplateExecutor } from 'lodash'
|
||||||
|
|
||||||
|
import { Nuxt } from 'nuxt/core'
|
||||||
|
import { DeterminedGlobals, determineGlobals, isUrl } from 'nuxt/utils'
|
||||||
import { VueRenderer } from 'nuxt/vue-renderer'
|
import { VueRenderer } from 'nuxt/vue-renderer'
|
||||||
|
|
||||||
import ServerContext from './context'
|
import ServerContext from './context'
|
||||||
@ -14,8 +18,34 @@ import errorMiddleware from './middleware/error'
|
|||||||
import Listener from './listener'
|
import Listener from './listener'
|
||||||
import createTimingMiddleware from './middleware/timing'
|
import createTimingMiddleware from './middleware/timing'
|
||||||
|
|
||||||
|
interface Manifest {
|
||||||
|
assetsMapping: Record<string, string[]>
|
||||||
|
publicPath: string
|
||||||
|
}
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
constructor (nuxt) {
|
__closed?: boolean
|
||||||
|
_readyCalled?: boolean
|
||||||
|
|
||||||
|
app: connect.Server
|
||||||
|
devMiddleware: (req: IncomingMessage, res: ServerResponse, next: (err?: any) => void) => any
|
||||||
|
listeners: Listener[]
|
||||||
|
nuxt: Nuxt
|
||||||
|
globals: DeterminedGlobals
|
||||||
|
options: Nuxt['options']
|
||||||
|
publicPath: boolean
|
||||||
|
renderer: VueRenderer
|
||||||
|
resources: {
|
||||||
|
clientManifest?: Manifest
|
||||||
|
modernManifest?: Manifest
|
||||||
|
serverManifest?: Manifest
|
||||||
|
ssrTemplate?: TemplateExecutor
|
||||||
|
spaTemplate?: TemplateExecutor
|
||||||
|
errorTemplate?: TemplateExecutor
|
||||||
|
}
|
||||||
|
serverContext: ServerContext
|
||||||
|
|
||||||
|
constructor (nuxt: Nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
|
|
||||||
@ -76,7 +106,7 @@ export default class Server {
|
|||||||
const { compressor } = this.options.render
|
const { compressor } = this.options.render
|
||||||
if (typeof compressor === 'object') {
|
if (typeof compressor === 'object') {
|
||||||
// If only setting for `compression` are provided, require the module and insert
|
// If only setting for `compression` are provided, require the module and insert
|
||||||
const compression = this.nuxt.resolver.requireModule('compression')
|
const compression = this.nuxt.resolver.requireModule<typeof import('compression')>('compression')
|
||||||
this.useMiddleware(compression(compressor))
|
this.useMiddleware(compression(compressor))
|
||||||
} else if (compressor) {
|
} else if (compressor) {
|
||||||
// Else, require own compression middleware if compressor is actually truthy
|
// Else, require own compression middleware if compressor is actually truthy
|
||||||
@ -317,12 +347,12 @@ export default class Server {
|
|||||||
return this.app.stack.map(({ handle }) => handle._middleware && handle._middleware.entry).filter(Boolean)
|
return this.app.stack.map(({ handle }) => handle._middleware && handle._middleware.entry).filter(Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRoute () {
|
renderRoute (...args: Parameters<VueRenderer['renderRoute']>) {
|
||||||
return this.renderer.renderRoute.apply(this.renderer, arguments)
|
return this.renderer.renderRoute.apply(this.renderer, ...args.slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
loadResources () {
|
loadResources (...args: Parameters<VueRenderer['loadResources']>) {
|
||||||
return this.renderer.loadResources.apply(this.renderer, arguments)
|
return this.renderer.loadResources.apply(this.renderer, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAndGetWindow (url, opts = {}, {
|
renderAndGetWindow (url, opts = {}, {
|
||||||
@ -337,13 +367,13 @@ export default class Server {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async listen (port, host, socket) {
|
async listen (port?: string | number, host?: string, socket?: string) {
|
||||||
// Ensure nuxt is ready
|
// Ensure nuxt is ready
|
||||||
await this.nuxt.ready()
|
await this.nuxt.ready()
|
||||||
|
|
||||||
// Create a new listener
|
// Create a new listener
|
||||||
const listener = new Listener({
|
const listener = new Listener({
|
||||||
port: isNaN(parseInt(port)) ? this.options.server.port : port,
|
port: typeof port !== 'number' && isNaN(parseInt(port)) ? this.options.server.port : port,
|
||||||
host: host || this.options.server.host,
|
host: host || this.options.server.host,
|
||||||
socket: socket || this.options.server.socket,
|
socket: socket || this.options.server.socket,
|
||||||
https: this.options.server.https,
|
https: this.options.server.https,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
|
|
||||||
export function isExternalDependency (id) {
|
export function isExternalDependency (id: string) {
|
||||||
return /[/\\]node_modules[/\\]/.test(id)
|
return /[/\\]node_modules[/\\]/.test(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearRequireCache (id) {
|
export function clearRequireCache (id: string) {
|
||||||
if (isExternalDependency(id)) {
|
if (isExternalDependency(id)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ export function clearRequireCache (id) {
|
|||||||
delete require.cache[id]
|
delete require.cache[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scanRequireTree (id, files = new Set()) {
|
export function scanRequireTree (id: string, files = new Set<string>()) {
|
||||||
if (isExternalDependency(id) || files.has(id)) {
|
if (isExternalDependency(id) || files.has(id)) {
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
@ -48,20 +48,20 @@ export function scanRequireTree (id, files = new Set()) {
|
|||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRequireCacheItem (id) {
|
export function getRequireCacheItem (id: string) {
|
||||||
try {
|
try {
|
||||||
return require.cache[id]
|
return require.cache[id]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tryRequire (id) {
|
export function tryRequire (id: string) {
|
||||||
try {
|
try {
|
||||||
return require(id)
|
return require(id)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPKG (id) {
|
export function getPKG (id: string) {
|
||||||
return tryRequire(join(id, 'package.json'))
|
return tryRequire(join(id, 'package.json'))
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
export const TARGETS = {
|
export const TARGETS = {
|
||||||
server: 'server',
|
server: 'server',
|
||||||
static: 'static'
|
static: 'static'
|
||||||
}
|
} as const
|
||||||
|
|
||||||
|
export type Target = keyof typeof TARGETS
|
||||||
|
|
||||||
export const MODES = {
|
export const MODES = {
|
||||||
universal: 'universal',
|
universal: 'universal',
|
||||||
spa: 'spa'
|
spa: 'spa'
|
||||||
}
|
} as const
|
||||||
|
|
||||||
|
export type Mode = keyof typeof MODES
|
@ -1,19 +1,35 @@
|
|||||||
|
import type { ServerResponse } from 'http'
|
||||||
|
import type { IncomingMessage } from 'connect'
|
||||||
|
|
||||||
import { TARGETS } from './constants'
|
import { TARGETS } from './constants'
|
||||||
|
|
||||||
export const getContext = function getContext (req, res) {
|
export const getContext = function getContext (req: IncomingMessage, res: ServerResponse) {
|
||||||
return { req, res }
|
return { req, res }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const determineGlobals = function determineGlobals (globalName, globals) {
|
type NuxtGlobal = string | ((globalName: string) => string)
|
||||||
const _globals = {}
|
|
||||||
|
type Globals = 'id' | 'nuxt' | 'context' | 'pluginPrefix' | 'readyCallback' | 'loadedCallback'
|
||||||
|
|
||||||
|
type NuxtGlobals = {
|
||||||
|
[key in Globals]: NuxtGlobal
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeterminedGlobals = {
|
||||||
|
[key in keyof NuxtGlobals]: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const determineGlobals = function determineGlobals (globalName: string, globals: NuxtGlobals) {
|
||||||
|
const _globals: Partial<DeterminedGlobals> = {}
|
||||||
for (const global in globals) {
|
for (const global in globals) {
|
||||||
if (typeof globals[global] === 'function') {
|
const currentGlobal = globals[global]
|
||||||
_globals[global] = globals[global](globalName)
|
if (currentGlobal instanceof Function) {
|
||||||
|
_globals[global] = currentGlobal(globalName)
|
||||||
} else {
|
} else {
|
||||||
_globals[global] = globals[global]
|
_globals[global] = currentGlobal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _globals
|
return _globals as DeterminedGlobals
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isFullStatic = function (options) {
|
export const isFullStatic = function (options) {
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
export const encodeHtml = function encodeHtml (str) {
|
export const encodeHtml = function encodeHtml (str: string) {
|
||||||
return str.replace(/</g, '<').replace(/>/g, '>')
|
return str.replace(/</g, '<').replace(/>/g, '>')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isString = obj => typeof obj === 'string' || obj instanceof String
|
export const isString = (obj: unknown): obj is string =>
|
||||||
|
typeof obj === 'string' || obj instanceof String
|
||||||
|
|
||||||
export const isNonEmptyString = obj => Boolean(obj && isString(obj))
|
export const isNonEmptyString = (obj: unknown): obj is string =>
|
||||||
|
Boolean(obj && isString(obj))
|
||||||
|
|
||||||
export const isPureObject = obj => !Array.isArray(obj) && typeof obj === 'object'
|
export const isPureObject = (
|
||||||
|
obj: unknown
|
||||||
|
): obj is Exclude<object, Array<any>> =>
|
||||||
|
!Array.isArray(obj) && typeof obj === 'object'
|
||||||
|
|
||||||
export const isUrl = function isUrl (url) {
|
export const isUrl = function isUrl (url: string) {
|
||||||
return ['http', '//'].some(str => url.startsWith(str))
|
return ['http', '//'].some(str => url.startsWith(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const urlJoin = function urlJoin () {
|
export const urlJoin = function urlJoin (...args: string[]) {
|
||||||
return [].slice
|
return [].slice
|
||||||
.call(arguments)
|
.call(args)
|
||||||
.join('/')
|
.join('/')
|
||||||
.replace(/\/+/g, '/')
|
.replace(/\/+/g, '/')
|
||||||
.replace(':/', '://')
|
.replace(':/', '://')
|
||||||
@ -22,13 +27,11 @@ export const urlJoin = function urlJoin () {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps value in array if it is not already an array
|
* Wraps value in array if it is not already an array
|
||||||
*
|
|
||||||
* @param {any} value
|
|
||||||
* @return {array}
|
|
||||||
*/
|
*/
|
||||||
export const wrapArray = value => Array.isArray(value) ? value : [value]
|
export const wrapArray = <T>(value: T | T[]): T[] =>
|
||||||
|
Array.isArray(value) ? value : [value]
|
||||||
|
|
||||||
const WHITESPACE_REPLACEMENTS = [
|
const WHITESPACE_REPLACEMENTS: [RegExp, string][] = [
|
||||||
[/[ \t\f\r]+\n/g, '\n'], // strip empty indents
|
[/[ \t\f\r]+\n/g, '\n'], // strip empty indents
|
||||||
[/{\n{2,}/g, '{\n'], // strip start padding from blocks
|
[/{\n{2,}/g, '{\n'], // strip start padding from blocks
|
||||||
[/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks
|
[/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks
|
||||||
@ -36,7 +39,7 @@ const WHITESPACE_REPLACEMENTS = [
|
|||||||
[/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed)
|
[/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed)
|
||||||
]
|
]
|
||||||
|
|
||||||
export const stripWhitespace = function stripWhitespace (string) {
|
export const stripWhitespace = function stripWhitespace (string: string) {
|
||||||
WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => {
|
WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => {
|
||||||
string = string.replace(regex, newSubstr)
|
string = string.replace(regex, newSubstr)
|
||||||
})
|
})
|
||||||
|
@ -2,27 +2,42 @@ import path from 'path'
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import properlock from 'proper-lockfile'
|
import properlock, { LockOptions } from 'proper-lockfile'
|
||||||
import onExit from 'signal-exit'
|
import onExit from 'signal-exit'
|
||||||
|
|
||||||
export const lockPaths = new Set()
|
export const lockPaths = new Set<string>()
|
||||||
|
|
||||||
export const defaultLockOptions = {
|
export const defaultLockOptions: Required<
|
||||||
|
Pick<LockOptions, 'stale' | 'onCompromised'>
|
||||||
|
> = {
|
||||||
stale: 30000,
|
stale: 30000,
|
||||||
onCompromised: err => consola.warn(err)
|
onCompromised: err => consola.warn(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLockOptions (options) {
|
export function getLockOptions (options: Partial<LockOptions>) {
|
||||||
return Object.assign({}, defaultLockOptions, options)
|
return Object.assign({}, defaultLockOptions, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createLockPath ({ id = 'nuxt', dir, root }) {
|
interface NuxtLockOptions {
|
||||||
|
id?: string
|
||||||
|
dir: string
|
||||||
|
root: string
|
||||||
|
options?: LockOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createLockPath ({
|
||||||
|
id = 'nuxt',
|
||||||
|
dir,
|
||||||
|
root
|
||||||
|
}: Pick<NuxtLockOptions, 'id' | 'dir' | 'root'>) {
|
||||||
const sum = hash(`${root}-${dir}`)
|
const sum = hash(`${root}-${dir}`)
|
||||||
|
|
||||||
return path.resolve(root, 'node_modules/.cache/nuxt', `${id}-lock-${sum}`)
|
return path.resolve(root, 'node_modules/.cache/nuxt', `${id}-lock-${sum}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLockPath (config) {
|
export async function getLockPath (
|
||||||
|
config: Pick<NuxtLockOptions, 'id' | 'dir' | 'root'>
|
||||||
|
) {
|
||||||
const lockPath = createLockPath(config)
|
const lockPath = createLockPath(config)
|
||||||
|
|
||||||
// the lock is created for the lockPath as ${lockPath}.lock
|
// the lock is created for the lockPath as ${lockPath}.lock
|
||||||
@ -32,8 +47,12 @@ export async function getLockPath (config) {
|
|||||||
return lockPath
|
return lockPath
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function lock ({ id, dir, root, options }) {
|
export async function lock ({ id, dir, root, options }: NuxtLockOptions) {
|
||||||
const lockPath = await getLockPath({ id, dir, root })
|
const lockPath = await getLockPath({
|
||||||
|
id,
|
||||||
|
dir,
|
||||||
|
root
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const locked = await properlock.check(lockPath)
|
const locked = await properlock.check(lockPath)
|
||||||
@ -45,7 +64,7 @@ export async function lock ({ id, dir, root, options }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lockWasCompromised = false
|
let lockWasCompromised = false
|
||||||
let release
|
let release: (() => Promise<void>) | undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
options = getLockOptions(options)
|
options = getLockOptions(options)
|
||||||
@ -94,7 +113,7 @@ export async function lock ({ id, dir, root, options }) {
|
|||||||
// as well, but in our case its much more likely the lock was
|
// as well, but in our case its much more likely the lock was
|
||||||
// compromised due to mtime update timeouts
|
// compromised due to mtime update timeouts
|
||||||
const lockDir = `${lockPath}.lock`
|
const lockDir = `${lockPath}.lock`
|
||||||
if (await fs.exists(lockDir)) {
|
if (await fs.pathExists(lockDir)) {
|
||||||
await fs.remove(lockDir)
|
await fs.remove(lockDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import UAParser from 'ua-parser-js'
|
import { UAParser } from 'ua-parser-js'
|
||||||
|
|
||||||
|
import type { SemVer } from 'semver'
|
||||||
|
import type { IncomingMessage } from 'connect'
|
||||||
|
|
||||||
export const ModernBrowsers = {
|
export const ModernBrowsers = {
|
||||||
Edge: '16',
|
Edge: '16',
|
||||||
@ -12,49 +15,65 @@ export const ModernBrowsers = {
|
|||||||
Yandex: '18',
|
Yandex: '18',
|
||||||
Vivaldi: '1.14',
|
Vivaldi: '1.14',
|
||||||
'Mobile Safari': '10.3'
|
'Mobile Safari': '10.3'
|
||||||
}
|
} as const
|
||||||
|
|
||||||
let semver
|
type ModernBrowsers = { -readonly [key in keyof typeof ModernBrowsers]: SemVer }
|
||||||
let __modernBrowsers
|
|
||||||
|
let semver: typeof import('semver')
|
||||||
|
let __modernBrowsers: ModernBrowsers
|
||||||
|
|
||||||
const getModernBrowsers = () => {
|
const getModernBrowsers = () => {
|
||||||
if (__modernBrowsers) {
|
if (__modernBrowsers) {
|
||||||
return __modernBrowsers
|
return __modernBrowsers
|
||||||
}
|
}
|
||||||
|
|
||||||
__modernBrowsers = Object.keys(ModernBrowsers)
|
__modernBrowsers = (Object.keys(ModernBrowsers) as Array<
|
||||||
.reduce((allBrowsers, browser) => {
|
keyof typeof ModernBrowsers
|
||||||
allBrowsers[browser] = semver.coerce(ModernBrowsers[browser])
|
>).reduce(
|
||||||
|
(allBrowsers, browser) => {
|
||||||
|
const version = semver.coerce(ModernBrowsers[browser])
|
||||||
|
if (version) { allBrowsers[browser] = version }
|
||||||
return allBrowsers
|
return allBrowsers
|
||||||
}, {})
|
},
|
||||||
|
{} as ModernBrowsers
|
||||||
|
)
|
||||||
return __modernBrowsers
|
return __modernBrowsers
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isModernBrowser = (ua) => {
|
interface NuxtRequest extends IncomingMessage {
|
||||||
|
socket: IncomingMessage['socket'] & {
|
||||||
|
_modern?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isModernBrowser = (ua: string) => {
|
||||||
if (!ua) {
|
if (!ua) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!semver) {
|
if (!semver) {
|
||||||
semver = require('semver')
|
semver = require('semver')
|
||||||
}
|
}
|
||||||
const { browser } = UAParser(ua)
|
const browser = new UAParser(ua).getBrowser()
|
||||||
const browserVersion = semver.coerce(browser.version)
|
const browserVersion = semver.coerce(browser.version)
|
||||||
if (!browserVersion) {
|
if (!browserVersion) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const modernBrowsers = getModernBrowsers()
|
const modernBrowsers = getModernBrowsers()
|
||||||
return Boolean(modernBrowsers[browser.name] && semver.gte(browserVersion, modernBrowsers[browser.name]))
|
const name = browser.name as keyof typeof modernBrowsers
|
||||||
|
return Boolean(
|
||||||
|
name && name in modernBrowsers && semver.gte(browserVersion, modernBrowsers[name])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isModernRequest = (req, modernMode = false) => {
|
export const isModernRequest = (req: NuxtRequest, modernMode = false) => {
|
||||||
if (modernMode === false) {
|
if (modernMode === false) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const { socket = {}, headers } = req
|
const { socket = {} as NuxtRequest['socket'], headers } = req
|
||||||
if (socket._modern === undefined) {
|
if (socket._modern === undefined) {
|
||||||
const ua = headers && headers['user-agent']
|
const ua = headers && headers['user-agent']
|
||||||
socket._modern = isModernBrowser(ua)
|
socket._modern = ua && isModernBrowser(ua)
|
||||||
}
|
}
|
||||||
|
|
||||||
return socket._modern
|
return socket._modern
|
||||||
|
@ -2,7 +2,8 @@ import path from 'path'
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import escapeRegExp from 'lodash/escapeRegExp'
|
import escapeRegExp from 'lodash/escapeRegExp'
|
||||||
|
|
||||||
export const startsWithAlias = aliasArray => str => aliasArray.some(c => str.startsWith(c))
|
export const startsWithAlias = (aliasArray: string[]) => (str: string) =>
|
||||||
|
aliasArray.some(c => str.startsWith(c))
|
||||||
|
|
||||||
export const startsWithSrcAlias = startsWithAlias(['@', '~'])
|
export const startsWithSrcAlias = startsWithAlias(['@', '~'])
|
||||||
|
|
||||||
@ -24,9 +25,9 @@ export const wChunk = function wChunk (p = '') {
|
|||||||
|
|
||||||
const reqSep = /\//g
|
const reqSep = /\//g
|
||||||
const sysSep = escapeRegExp(path.sep)
|
const sysSep = escapeRegExp(path.sep)
|
||||||
const normalize = string => string.replace(reqSep, sysSep)
|
const normalize = (string: string) => string.replace(reqSep, sysSep)
|
||||||
|
|
||||||
export const r = function r (...args) {
|
export const r = function r (...args: string[]) {
|
||||||
const lastArg = args[args.length - 1]
|
const lastArg = args[args.length - 1]
|
||||||
|
|
||||||
if (startsWithSrcAlias(lastArg)) {
|
if (startsWithSrcAlias(lastArg)) {
|
||||||
@ -36,14 +37,12 @@ export const r = function r (...args) {
|
|||||||
return wp(path.resolve(...args.map(normalize)))
|
return wp(path.resolve(...args.map(normalize)))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const relativeTo = function relativeTo (...args) {
|
export const relativeTo = function relativeTo (dir: string, ...args: string[]): string {
|
||||||
const dir = args.shift()
|
|
||||||
|
|
||||||
// Keep webpack inline loader intact
|
// Keep webpack inline loader intact
|
||||||
if (args[0].includes('!')) {
|
if (args[0].includes('!')) {
|
||||||
const loaders = args.shift().split('!')
|
const loaders = args.shift()!.split('!')
|
||||||
|
|
||||||
return loaders.concat(relativeTo(dir, loaders.pop(), ...args)).join('!')
|
return loaders.concat(relativeTo(dir, loaders.pop()!, ...args)).join('!')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve path
|
// Resolve path
|
||||||
@ -63,7 +62,17 @@ export const relativeTo = function relativeTo (...args) {
|
|||||||
return wp(rp)
|
return wp(rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineAlias (src, target, prop, opts = {}) {
|
interface AliasOptions {
|
||||||
|
bind?: boolean
|
||||||
|
warn?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineAlias (
|
||||||
|
src: string,
|
||||||
|
target: Record<string, any>,
|
||||||
|
prop: string | string[],
|
||||||
|
opts: AliasOptions = {}
|
||||||
|
) {
|
||||||
const { bind = true, warn = false } = opts
|
const { bind = true, warn = false } = opts
|
||||||
|
|
||||||
if (Array.isArray(prop)) {
|
if (Array.isArray(prop)) {
|
||||||
@ -94,9 +103,9 @@ export function defineAlias (src, target, prop, opts = {}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const isIndex = s => /(.*)\/index\.[^/]+$/.test(s)
|
const isIndex = (s: string) => /(.*)\/index\.[^/]+$/.test(s)
|
||||||
|
|
||||||
export function isIndexFileAndFolder (pluginFiles) {
|
export function isIndexFileAndFolder (pluginFiles: string[]) {
|
||||||
// Return early in case the matching file count exceeds 2 (index.js + folder)
|
// Return early in case the matching file count exceeds 2 (index.js + folder)
|
||||||
if (pluginFiles.length !== 2) {
|
if (pluginFiles.length !== 2) {
|
||||||
return false
|
return false
|
||||||
@ -105,5 +114,9 @@ export function isIndexFileAndFolder (pluginFiles) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getMainModule = () => {
|
export const getMainModule = () => {
|
||||||
return require.main || (module && module.main) || module
|
return (
|
||||||
|
require.main ||
|
||||||
|
(module && ((module as any).main as NodeJS.Module)) ||
|
||||||
|
module
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ import path from 'path'
|
|||||||
import get from 'lodash/get'
|
import get from 'lodash/get'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
|
||||||
|
import type { Component } from 'vue'
|
||||||
|
import type { _RouteRecordBase } from 'vue-router'
|
||||||
|
|
||||||
import { r } from './resolve'
|
import { r } from './resolve'
|
||||||
|
|
||||||
export const flatRoutes = function flatRoutes (router, fileName = '', routes = []) {
|
export const flatRoutes = function flatRoutes (router, fileName = '', routes: string[] = []) {
|
||||||
router.forEach((r) => {
|
router.forEach((r) => {
|
||||||
if ([':', '*'].some(c => r.path.includes(c))) {
|
if ([':', '*'].some(c => r.path.includes(c))) {
|
||||||
return
|
return
|
||||||
@ -30,12 +33,12 @@ export const flatRoutes = function flatRoutes (router, fileName = '', routes = [
|
|||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanChildrenRoutes (routes, isChild = false, routeNameSplitter = '-') {
|
function cleanChildrenRoutes (routes: NuxtRouteConfig[], isChild = false, routeNameSplitter = '-') {
|
||||||
let start = -1
|
let start = -1
|
||||||
const regExpIndex = new RegExp(`${routeNameSplitter}index$`)
|
const regExpIndex = new RegExp(`${routeNameSplitter}index$`)
|
||||||
const routesIndex = []
|
const routesIndex: string[][] = []
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
if (regExpIndex.test(route.name) || route.name === 'index') {
|
if (route.name && typeof route.name === 'string' && (regExpIndex.test(route.name) || route.name === 'index')) {
|
||||||
// Save indexOf 'index' key in name
|
// Save indexOf 'index' key in name
|
||||||
const res = route.name.split(routeNameSplitter)
|
const res = route.name.split(routeNameSplitter)
|
||||||
const s = res.indexOf('index')
|
const s = res.indexOf('index')
|
||||||
@ -46,7 +49,7 @@ function cleanChildrenRoutes (routes, isChild = false, routeNameSplitter = '-')
|
|||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
route.path = isChild ? route.path.replace('/', '') : route.path
|
route.path = isChild ? route.path.replace('/', '') : route.path
|
||||||
if (route.path.includes('?')) {
|
if (route.path.includes('?')) {
|
||||||
const names = route.name.split(routeNameSplitter)
|
const names = typeof route.name === 'string' && route.name.split(routeNameSplitter) || []
|
||||||
const paths = route.path.split('/')
|
const paths = route.path.split('/')
|
||||||
if (!isChild) {
|
if (!isChild) {
|
||||||
paths.shift()
|
paths.shift()
|
||||||
@ -66,7 +69,9 @@ function cleanChildrenRoutes (routes, isChild = false, routeNameSplitter = '-')
|
|||||||
})
|
})
|
||||||
route.path = (isChild ? '' : '/') + paths.join('/')
|
route.path = (isChild ? '' : '/') + paths.join('/')
|
||||||
}
|
}
|
||||||
route.name = route.name.replace(regExpIndex, '')
|
if (route.name) {
|
||||||
|
route.name = typeof route.name === 'string' && route.name.replace(regExpIndex, '')
|
||||||
|
}
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
if (route.children.find(child => child.path === '')) {
|
if (route.children.find(child => child.path === '')) {
|
||||||
delete route.name
|
delete route.name
|
||||||
@ -79,7 +84,7 @@ function cleanChildrenRoutes (routes, isChild = false, routeNameSplitter = '-')
|
|||||||
|
|
||||||
const DYNAMIC_ROUTE_REGEX = /^\/([:*])/
|
const DYNAMIC_ROUTE_REGEX = /^\/([:*])/
|
||||||
|
|
||||||
export const sortRoutes = function sortRoutes (routes) {
|
export const sortRoutes = function sortRoutes (routes: NuxtRouteConfig[]) {
|
||||||
routes.sort((a, b) => {
|
routes.sort((a, b) => {
|
||||||
if (!a.path.length) {
|
if (!a.path.length) {
|
||||||
return -1
|
return -1
|
||||||
@ -136,6 +141,22 @@ export const sortRoutes = function sortRoutes (routes) {
|
|||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateRouteOptions {
|
||||||
|
files: string[]
|
||||||
|
srcDir: string
|
||||||
|
pagesDir?: string
|
||||||
|
routeNameSplitter?: string
|
||||||
|
supportedExtensions?: string[]
|
||||||
|
trailingSlash: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NuxtRouteConfig extends Omit<_RouteRecordBase, 'children'> {
|
||||||
|
component?: Component | string
|
||||||
|
chunkName?: string
|
||||||
|
pathToRegexpOptions?: any
|
||||||
|
children?: NuxtRouteConfig[]
|
||||||
|
}
|
||||||
|
|
||||||
export const createRoutes = function createRoutes ({
|
export const createRoutes = function createRoutes ({
|
||||||
files,
|
files,
|
||||||
srcDir,
|
srcDir,
|
||||||
@ -143,8 +164,8 @@ export const createRoutes = function createRoutes ({
|
|||||||
routeNameSplitter = '-',
|
routeNameSplitter = '-',
|
||||||
supportedExtensions = ['vue', 'js'],
|
supportedExtensions = ['vue', 'js'],
|
||||||
trailingSlash
|
trailingSlash
|
||||||
}) {
|
}: CreateRouteOptions) {
|
||||||
const routes = []
|
const routes: NuxtRouteConfig[] = []
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
const keys = file
|
const keys = file
|
||||||
.replace(new RegExp(`^${pagesDir}`), '')
|
.replace(new RegExp(`^${pagesDir}`), '')
|
||||||
@ -152,13 +173,13 @@ export const createRoutes = function createRoutes ({
|
|||||||
.replace(/\/{2,}/g, '/')
|
.replace(/\/{2,}/g, '/')
|
||||||
.split('/')
|
.split('/')
|
||||||
.slice(1)
|
.slice(1)
|
||||||
const route = { name: '', path: '', component: r(srcDir, file) }
|
const route: NuxtRouteConfig = { name: '', path: '', component: r(srcDir, file) }
|
||||||
let parent = routes
|
let parent = routes
|
||||||
keys.forEach((key, i) => {
|
keys.forEach((key, i) => {
|
||||||
// remove underscore only, if its the prefix
|
// remove underscore only, if its the prefix
|
||||||
const sanitizedKey = key.startsWith('_') ? key.substr(1) : key
|
const sanitizedKey = key.startsWith('_') ? key.substr(1) : key
|
||||||
|
|
||||||
route.name = route.name
|
route.name = route.name && typeof route.name === 'string'
|
||||||
? route.name + routeNameSplitter + sanitizedKey
|
? route.name + routeNameSplitter + sanitizedKey
|
||||||
: sanitizedKey
|
: sanitizedKey
|
||||||
route.name += key === '_' ? 'all' : ''
|
route.name += key === '_' ? 'all' : ''
|
||||||
@ -192,9 +213,9 @@ 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, key1, key2) {
|
export const guardDir = function guardDir (options: Record<string, unknown>, key1: string, key2: string) {
|
||||||
const dir1 = get(options, key1, false)
|
const dir1 = get(options, key1, false) as string
|
||||||
const dir2 = get(options, key2, false)
|
const dir2 = get(options, key2, false) as string
|
||||||
|
|
||||||
if (
|
if (
|
||||||
dir1 &&
|
dir1 &&
|
||||||
@ -213,7 +234,7 @@ export const guardDir = function guardDir (options, key1, key2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRoutePathExtension = (key) => {
|
const getRoutePathExtension = (key: string) => {
|
||||||
if (key === '_') {
|
if (key === '_') {
|
||||||
return '*'
|
return '*'
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import serialize from 'serialize-javascript'
|
import serialize from 'serialize-javascript'
|
||||||
|
|
||||||
export function normalizeFunctions (obj) {
|
export function normalizeFunctions (obj: Array<any>): Array<any>
|
||||||
|
export function normalizeFunctions (obj: null): null
|
||||||
|
export function normalizeFunctions (obj: Function): Function
|
||||||
|
export function normalizeFunctions (obj: Record<string, any>): Record<string, any>
|
||||||
|
export function normalizeFunctions (obj: Array<unknown> | null | Function | Record<string, any>) {
|
||||||
if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) {
|
if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@ -22,14 +26,14 @@ export function normalizeFunctions (obj) {
|
|||||||
functionBody = `return ${functionBody}`
|
functionBody = `return ${functionBody}`
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-new-func
|
// eslint-disable-next-line no-new-func
|
||||||
obj[key] = new Function(...match[1].split(',').map(arg => arg.trim()), functionBody)
|
obj[key] = new Function(...match[1].split(',').map((arg: string) => arg.trim()), functionBody)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializeFunction (func) {
|
export function serializeFunction (func: Function) {
|
||||||
let open = false
|
let open = false
|
||||||
func = normalizeFunctions(func)
|
func = normalizeFunctions(func)
|
||||||
return serialize(func)
|
return serialize(func)
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
export const sequence = function sequence (tasks, fn) {
|
export const sequence = function sequence<T, R> (
|
||||||
|
tasks: T[],
|
||||||
|
fn: (task: T) => R
|
||||||
|
) {
|
||||||
return tasks.reduce(
|
return tasks.reduce(
|
||||||
(promise, task) => promise.then(() => fn(task)),
|
(promise, task): any => promise.then(() => fn(task)),
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parallel = function parallel (tasks, fn) {
|
export const parallel = function parallel<T, R> (
|
||||||
|
tasks: T[],
|
||||||
|
fn: (task: T) => R
|
||||||
|
) {
|
||||||
return Promise.all(tasks.map(fn))
|
return Promise.all(tasks.map(fn))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
async function promiseFinally (fn, finalFn) {
|
async function promiseFinally<T> (
|
||||||
let result
|
fn: (() => Promise<T>) | Promise<T>,
|
||||||
|
finalFn: () => any
|
||||||
|
) {
|
||||||
|
let result: T
|
||||||
try {
|
try {
|
||||||
if (typeof fn === 'function') {
|
if (typeof fn === 'function') {
|
||||||
result = await fn()
|
result = await fn()
|
||||||
@ -12,8 +15,12 @@ async function promiseFinally (fn, finalFn) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const timeout = function timeout (fn, ms, msg) {
|
export const timeout = function timeout (
|
||||||
let timerId
|
fn: () => any,
|
||||||
|
ms: number,
|
||||||
|
msg: string
|
||||||
|
) {
|
||||||
|
let timerId: NodeJS.Timeout
|
||||||
const warpPromise = promiseFinally(fn, () => clearTimeout(timerId))
|
const warpPromise = promiseFinally(fn, () => clearTimeout(timerId))
|
||||||
const timerPromise = new Promise((resolve, reject) => {
|
const timerPromise = new Promise((resolve, reject) => {
|
||||||
timerId = setTimeout(() => reject(new Error(msg)), ms)
|
timerId = setTimeout(() => reject(new Error(msg)), ms)
|
||||||
@ -21,16 +28,25 @@ export const timeout = function timeout (fn, ms, msg) {
|
|||||||
return Promise.race([warpPromise, timerPromise])
|
return Promise.race([warpPromise, timerPromise])
|
||||||
}
|
}
|
||||||
|
|
||||||
export const waitFor = function waitFor (ms) {
|
export const waitFor = function waitFor (ms: number) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms || 0))
|
return new Promise(resolve => setTimeout(resolve, ms || 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Time {
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
start: [number, number] | bigint
|
||||||
|
duration?: bigint | [number, number]
|
||||||
|
}
|
||||||
export class Timer {
|
export class Timer {
|
||||||
|
_times: Map<string, Time>
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
this._times = new Map()
|
this._times = new Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
start (name, description) {
|
start (name: string, description: string) {
|
||||||
const time = {
|
const time: Time = {
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
start: this.hrtime()
|
start: this.hrtime()
|
||||||
@ -39,22 +55,33 @@ export class Timer {
|
|||||||
return time
|
return time
|
||||||
}
|
}
|
||||||
|
|
||||||
end (name) {
|
end (name: string) {
|
||||||
if (this._times.has(name)) {
|
if (this._times.has(name)) {
|
||||||
const time = this._times.get(name)
|
const time = this._times.get(name)!
|
||||||
time.duration = this.hrtime(time.start)
|
if (typeof time.start === 'bigint') {
|
||||||
|
time.duration = this.hrtime(time.start)
|
||||||
|
} else {
|
||||||
|
time.duration = this.hrtime(time.start)
|
||||||
|
}
|
||||||
this._times.delete(name)
|
this._times.delete(name)
|
||||||
return time
|
return time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hrtime (start) {
|
hrtime (start?: bigint): bigint
|
||||||
|
hrtime (start?: [number, number]): [number, number]
|
||||||
|
hrtime (start?: [number, number] | bigint) {
|
||||||
const useBigInt = typeof process.hrtime.bigint === 'function'
|
const useBigInt = typeof process.hrtime.bigint === 'function'
|
||||||
if (start) {
|
if (start) {
|
||||||
const end = useBigInt ? process.hrtime.bigint() : process.hrtime(start)
|
if (typeof start === 'bigint') {
|
||||||
return useBigInt
|
if (!useBigInt) { throw new Error('bigint is not supported.') }
|
||||||
? (end - start) / BigInt(1000000)
|
|
||||||
: (end[0] * 1e3) + (end[1] * 1e-6)
|
const end = process.hrtime.bigint()
|
||||||
|
return (end - start) / BigInt(1000000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = process.hrtime(start)
|
||||||
|
return end[0] * 1e3 + end[1] * 1e-6
|
||||||
}
|
}
|
||||||
return useBigInt ? process.hrtime.bigint() : process.hrtime()
|
return useBigInt ? process.hrtime.bigint() : process.hrtime()
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,22 @@ import { TARGETS, isModernRequest, waitFor } from 'nuxt/utils'
|
|||||||
import SPARenderer from './renderers/spa'
|
import SPARenderer from './renderers/spa'
|
||||||
import SSRRenderer from './renderers/ssr'
|
import SSRRenderer from './renderers/ssr'
|
||||||
import ModernRenderer from './renderers/modern'
|
import ModernRenderer from './renderers/modern'
|
||||||
|
import ServerContext from 'nuxt/server/context'
|
||||||
|
|
||||||
export default class VueRenderer {
|
export default class VueRenderer {
|
||||||
constructor (context) {
|
__closed?: boolean
|
||||||
|
_state?: 'created' | 'loading' | 'ready' | 'error'
|
||||||
|
_error?: null
|
||||||
|
_readyPromise?: Promise<any>
|
||||||
|
distPath: string
|
||||||
|
serverContext: ServerContext
|
||||||
|
renderer: {
|
||||||
|
ssr: any
|
||||||
|
modern: any
|
||||||
|
spa: any
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (context: ServerContext) {
|
||||||
this.serverContext = context
|
this.serverContext = context
|
||||||
this.options = this.serverContext.options
|
this.options = this.serverContext.options
|
||||||
|
|
||||||
@ -86,10 +99,10 @@ export default class VueRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadResources (_fs) {
|
async loadResources (_fs: typeof import('fs-extra')) {
|
||||||
const updated = []
|
const updated = []
|
||||||
|
|
||||||
const readResource = async (fileName, encoding) => {
|
const readResource = async (fileName: string, encoding: string) => {
|
||||||
try {
|
try {
|
||||||
const fullPath = path.resolve(this.distPath, fileName)
|
const fullPath = path.resolve(this.distPath, fileName)
|
||||||
|
|
||||||
@ -311,16 +324,16 @@ export default class VueRenderer {
|
|||||||
return {
|
return {
|
||||||
clientManifest: {
|
clientManifest: {
|
||||||
fileName: 'client.manifest.json',
|
fileName: 'client.manifest.json',
|
||||||
transform: src => JSON.parse(src)
|
transform: (src: string) => JSON.parse(src)
|
||||||
},
|
},
|
||||||
modernManifest: {
|
modernManifest: {
|
||||||
fileName: 'modern.manifest.json',
|
fileName: 'modern.manifest.json',
|
||||||
transform: src => JSON.parse(src)
|
transform: (src: string) => JSON.parse(src)
|
||||||
},
|
},
|
||||||
serverManifest: {
|
serverManifest: {
|
||||||
fileName: 'server.manifest.json',
|
fileName: 'server.manifest.json',
|
||||||
// BundleRenderer needs resolved contents
|
// BundleRenderer needs resolved contents
|
||||||
transform: async (src, { readResource }) => {
|
transform: async (src: string, { readResource }) => {
|
||||||
const serverManifest = JSON.parse(src)
|
const serverManifest = JSON.parse(src)
|
||||||
|
|
||||||
const readResources = async (obj) => {
|
const readResources = async (obj) => {
|
||||||
@ -357,16 +370,16 @@ export default class VueRenderer {
|
|||||||
},
|
},
|
||||||
ssrTemplate: {
|
ssrTemplate: {
|
||||||
fileName: 'index.ssr.html',
|
fileName: 'index.ssr.html',
|
||||||
transform: src => this.parseTemplate(src)
|
transform: (src: string) => this.parseTemplate(src)
|
||||||
},
|
},
|
||||||
spaTemplate: {
|
spaTemplate: {
|
||||||
fileName: 'index.spa.html',
|
fileName: 'index.spa.html',
|
||||||
transform: src => this.parseTemplate(src)
|
transform: (src: string) => this.parseTemplate(src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseTemplate (templateStr) {
|
parseTemplate (templateStr: string) {
|
||||||
return template(templateStr, {
|
return template(templateStr, {
|
||||||
interpolate: /{{([\s\S]+?)}}/g,
|
interpolate: /{{([\s\S]+?)}}/g,
|
||||||
evaluate: /{%([\s\S]+?)%}/g
|
evaluate: /{%([\s\S]+?)%}/g
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
|
import ServerContext from "nuxt/server/context"
|
||||||
|
|
||||||
export default class BaseRenderer {
|
export default class BaseRenderer {
|
||||||
constructor (serverContext) {
|
serverContext: ServerContext
|
||||||
|
options: ServerContext['options']
|
||||||
|
|
||||||
|
constructor (serverContext: ServerContext) {
|
||||||
this.serverContext = serverContext
|
this.serverContext = serverContext
|
||||||
this.options = serverContext.options
|
this.options = serverContext.options
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTemplate (templateFn, opts) {
|
renderTemplate (templateFn: (options: Record<string, any>) => void, opts: Record<string, any>) {
|
||||||
// Fix problem with HTMLPlugin's minify option (#3392)
|
// Fix problem with HTMLPlugin's minify option (#3392)
|
||||||
opts.html_attrs = opts.HTML_ATTRS
|
opts.html_attrs = opts.HTML_ATTRS
|
||||||
opts.head_attrs = opts.HEAD_ATTRS
|
opts.head_attrs = opts.HEAD_ATTRS
|
||||||
@ -13,7 +18,7 @@ export default class BaseRenderer {
|
|||||||
return templateFn(opts)
|
return templateFn(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render (renderContext) {
|
||||||
throw new Error('`render()` needs to be implemented')
|
throw new Error('`render()` needs to be implemented')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
import ServerContext from 'nuxt/server/context'
|
||||||
import { isUrl, urlJoin, safariNoModuleFix } from 'nuxt/utils'
|
import { isUrl, urlJoin, safariNoModuleFix } from 'nuxt/utils'
|
||||||
|
|
||||||
import SSRRenderer from './ssr'
|
import SSRRenderer from './ssr'
|
||||||
|
|
||||||
export default class ModernRenderer extends SSRRenderer {
|
export default class ModernRenderer extends SSRRenderer {
|
||||||
constructor (serverContext) {
|
_assetsMapping?: Record<string, string>
|
||||||
|
publicPath: string
|
||||||
|
|
||||||
|
constructor (serverContext: ServerContext) {
|
||||||
super(serverContext)
|
super(serverContext)
|
||||||
|
|
||||||
const { build: { publicPath }, router: { base } } = this.options
|
const { build: { publicPath }, router: { base } } = this.options
|
||||||
@ -17,7 +22,7 @@ export default class ModernRenderer extends SSRRenderer {
|
|||||||
const { clientManifest, modernManifest } = this.serverContext.resources
|
const { clientManifest, modernManifest } = this.serverContext.resources
|
||||||
const legacyAssets = clientManifest.assetsMapping
|
const legacyAssets = clientManifest.assetsMapping
|
||||||
const modernAssets = modernManifest.assetsMapping
|
const modernAssets = modernManifest.assetsMapping
|
||||||
const mapping = {}
|
const mapping: Record<string, string> = {}
|
||||||
|
|
||||||
Object.keys(legacyAssets).forEach((componentHash) => {
|
Object.keys(legacyAssets).forEach((componentHash) => {
|
||||||
const modernComponentAssets = modernAssets[componentHash] || []
|
const modernComponentAssets = modernAssets[componentHash] || []
|
||||||
|
@ -3,11 +3,22 @@ import cloneDeep from 'lodash/cloneDeep'
|
|||||||
import VueMeta from 'vue-meta'
|
import VueMeta from 'vue-meta'
|
||||||
import LRU from 'lru-cache'
|
import LRU from 'lru-cache'
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
|
|
||||||
import { TARGETS, isModernRequest } from 'nuxt/utils'
|
import { TARGETS, isModernRequest } from 'nuxt/utils'
|
||||||
|
import ServerContext from 'nuxt/server/context'
|
||||||
import BaseRenderer from './base'
|
import BaseRenderer from './base'
|
||||||
|
|
||||||
export default class SPARenderer extends BaseRenderer {
|
export default class SPARenderer extends BaseRenderer {
|
||||||
constructor (serverContext) {
|
cache: LRU<unknown, unknown>
|
||||||
|
vueMetaConfig: {
|
||||||
|
ssrAppId: string
|
||||||
|
keyName: string
|
||||||
|
attribute: string
|
||||||
|
ssrAttribute: string
|
||||||
|
tagIDKeyName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (serverContext: ServerContext) {
|
||||||
super(serverContext)
|
super(serverContext)
|
||||||
|
|
||||||
this.cache = new LRU()
|
this.cache = new LRU()
|
||||||
@ -188,7 +199,7 @@ export default class SPARenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getPreloadType (ext) {
|
static getPreloadType (ext: string) {
|
||||||
if (ext === 'js') {
|
if (ext === 'js') {
|
||||||
return 'script'
|
return 'script'
|
||||||
} else if (ext === 'css') {
|
} else if (ext === 'css') {
|
||||||
|
@ -3,13 +3,15 @@ import crypto from 'crypto'
|
|||||||
import { format } from 'util'
|
import { format } from 'util'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { TARGETS, urlJoin } from 'nuxt/utils'
|
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
import { createBundleRenderer } from 'vue-bundle-renderer'
|
import { createBundleRenderer } from 'vue-bundle-renderer'
|
||||||
|
|
||||||
|
import { TARGETS, urlJoin } from 'nuxt/utils'
|
||||||
|
import ServerContext from 'nuxt/server/context'
|
||||||
import BaseRenderer from './base'
|
import BaseRenderer from './base'
|
||||||
|
|
||||||
export default class SSRRenderer extends BaseRenderer {
|
export default class SSRRenderer extends BaseRenderer {
|
||||||
constructor (serverContext) {
|
constructor (serverContext: ServerContext) {
|
||||||
super(serverContext)
|
super(serverContext)
|
||||||
this.createRenderer()
|
this.createRenderer()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user