mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 06:05:11 +00:00
refactor(cli): cleanups and improvements (#4222)
This commit is contained in:
parent
2e2b32b547
commit
4503d42d54
@ -1,19 +1,26 @@
|
||||
import parseArgs from 'minimist'
|
||||
import wrapAnsi from 'wrap-ansi'
|
||||
import { name, version } from '../package.json'
|
||||
import { loadNuxtConfig, indent, indentLines, foldLines } from './utils'
|
||||
import { options as Options, defaultOptions as DefaultOptions } from './options'
|
||||
import { loadNuxtConfig, indent, foldLines } from './utils'
|
||||
import * as imports from './imports'
|
||||
|
||||
const startSpaces = 6
|
||||
const startSpaces = 2
|
||||
const optionSpaces = 2
|
||||
const maxCharsPerLine = 80
|
||||
|
||||
export default class NuxtCommand {
|
||||
constructor({ description, usage, options } = {}) {
|
||||
constructor({ name, description, usage, options, run } = {}) {
|
||||
this.name = name || ''
|
||||
this.description = description || ''
|
||||
this.usage = usage || ''
|
||||
this.options = Array.from(new Set((options || []).concat(DefaultOptions)))
|
||||
this.options = Object.assign({}, options)
|
||||
this._run = run
|
||||
}
|
||||
|
||||
static from(options) {
|
||||
if (options instanceof NuxtCommand) {
|
||||
return options
|
||||
}
|
||||
return new NuxtCommand(options)
|
||||
}
|
||||
|
||||
_getMinimistOptions() {
|
||||
@ -24,8 +31,8 @@ export default class NuxtCommand {
|
||||
default: {}
|
||||
}
|
||||
|
||||
for (const name of this.options) {
|
||||
const option = Options[name]
|
||||
for (const name of Object.keys(this.options)) {
|
||||
const option = this.options[name]
|
||||
|
||||
if (option.alias) {
|
||||
minimistOptions.alias[option.alias] = name
|
||||
@ -54,13 +61,17 @@ export default class NuxtCommand {
|
||||
return argv
|
||||
}
|
||||
|
||||
run() {
|
||||
return this._run(this)
|
||||
}
|
||||
|
||||
async getNuxtConfig(argv, extraOptions) {
|
||||
const config = await loadNuxtConfig(argv)
|
||||
const options = Object.assign(config, extraOptions || {})
|
||||
|
||||
for (const name of this.options) {
|
||||
if (Options[name].handle) {
|
||||
Options[name].handle(options, argv)
|
||||
for (const name of Object.keys(this.options)) {
|
||||
if (this.options[name].prepare) {
|
||||
this.options[name].prepare(this, options, argv)
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,38 +97,37 @@ export default class NuxtCommand {
|
||||
|
||||
_getHelp() {
|
||||
const options = []
|
||||
|
||||
let maxOptionLength = 0
|
||||
// For consistency Options determines order
|
||||
for (const name in Options) {
|
||||
const option = Options[name]
|
||||
if (this.options.includes(name)) {
|
||||
let optionHelp = '--'
|
||||
optionHelp += option.type === 'boolean' && option.default ? 'no-' : ''
|
||||
optionHelp += name
|
||||
if (option.alias) {
|
||||
optionHelp += `, -${option.alias}`
|
||||
}
|
||||
|
||||
maxOptionLength = Math.max(maxOptionLength, optionHelp.length)
|
||||
options.push([ optionHelp, option.description ])
|
||||
for (const name in this.options) {
|
||||
const option = this.options[name]
|
||||
|
||||
let optionHelp = '--'
|
||||
optionHelp += option.type === 'boolean' && option.default ? 'no-' : ''
|
||||
optionHelp += name
|
||||
if (option.alias) {
|
||||
optionHelp += `, -${option.alias}`
|
||||
}
|
||||
|
||||
maxOptionLength = Math.max(maxOptionLength, optionHelp.length)
|
||||
options.push([ optionHelp, option.description ])
|
||||
}
|
||||
|
||||
const optionStr = options.map(([option, description]) => {
|
||||
const line = option +
|
||||
indent(maxOptionLength + optionSpaces - option.length) +
|
||||
wrapAnsi(description, maxCharsPerLine - startSpaces - maxOptionLength - optionSpaces)
|
||||
return indentLines(line, startSpaces + maxOptionLength + optionSpaces, startSpaces)
|
||||
const _opts = options.map(([option, description]) => {
|
||||
const i = indent(maxOptionLength + optionSpaces - option.length)
|
||||
return foldLines(
|
||||
option + i + description,
|
||||
maxCharsPerLine,
|
||||
startSpaces + maxOptionLength + optionSpaces * 2,
|
||||
startSpaces + optionSpaces
|
||||
)
|
||||
}).join('\n')
|
||||
|
||||
const usage = foldLines(`Usage: nuxt ${this.usage} [options]`, maxCharsPerLine, startSpaces)
|
||||
const description = foldLines(this.description, maxCharsPerLine, startSpaces)
|
||||
const opts = foldLines(`Options:`, maxCharsPerLine, startSpaces) + '\n\n' + _opts
|
||||
|
||||
return `
|
||||
Description\n${description}
|
||||
Usage
|
||||
$ nuxt ${this.usage}
|
||||
Options\n${optionStr}\n\n`
|
||||
return `${usage}\n\n${description}\n\n${opts}\n\n`
|
||||
}
|
||||
|
||||
showVersion() {
|
||||
|
@ -1,46 +1,77 @@
|
||||
import consola from 'consola'
|
||||
import NuxtCommand from '../command'
|
||||
import { common } from '../options'
|
||||
|
||||
export default async function build() {
|
||||
const nuxtCmd = new NuxtCommand({
|
||||
description: 'Compiles the application for production deployment',
|
||||
usage: 'build <dir>',
|
||||
options: [ 'analyze', 'quiet' ]
|
||||
})
|
||||
|
||||
const argv = nuxtCmd.getArgv()
|
||||
|
||||
// Create production build when calling `nuxt build` (dev: false)
|
||||
const nuxt = await nuxtCmd.getNuxt(
|
||||
await nuxtCmd.getNuxtConfig(argv, { dev: false })
|
||||
)
|
||||
|
||||
// Setup hooks
|
||||
nuxt.hook('error', err => consola.fatal(err))
|
||||
|
||||
let builderOrGenerator
|
||||
if (nuxt.options.mode !== 'spa' || argv.generate === false) {
|
||||
// Build only
|
||||
builderOrGenerator = (await nuxtCmd.getBuilder(nuxt)).build()
|
||||
} else {
|
||||
// Build + Generate for static deployment
|
||||
builderOrGenerator = (await nuxtCmd.getGenerator(nuxt)).generate({
|
||||
build: true
|
||||
})
|
||||
}
|
||||
|
||||
return builderOrGenerator
|
||||
.then(() => {
|
||||
// In analyze mode wait for plugin
|
||||
// emitting assets and opening browser
|
||||
if (
|
||||
nuxt.options.build.analyze === true ||
|
||||
typeof nuxt.options.build.analyze === 'object'
|
||||
) {
|
||||
return
|
||||
export default {
|
||||
name: 'build',
|
||||
description: 'Compiles the application for production deployment',
|
||||
usage: 'build <dir>',
|
||||
options: {
|
||||
...common,
|
||||
analyze: {
|
||||
alias: 'a',
|
||||
type: 'boolean',
|
||||
description: 'Launch webpack-bundle-analyzer to optimize your bundles',
|
||||
prepare(cmd, options, argv) {
|
||||
// Analyze option
|
||||
options.build = options.build || {}
|
||||
if (argv.analyze && typeof options.build.analyze !== 'object') {
|
||||
options.build.analyze = true
|
||||
}
|
||||
}
|
||||
},
|
||||
generate: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Don\'t generate static version for SPA mode (useful for nuxt start)'
|
||||
},
|
||||
quiet: {
|
||||
alias: 'q',
|
||||
type: 'boolean',
|
||||
description: 'Disable output except for errors',
|
||||
handle(options, argv) {
|
||||
// Silence output when using --quiet
|
||||
options.build = options.build || {}
|
||||
if (argv.quiet) {
|
||||
options.build.quiet = !!argv.quiet
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async run(nuxtCmd) {
|
||||
const argv = nuxtCmd.getArgv()
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(err => consola.fatal(err))
|
||||
// Create production build when calling `nuxt build` (dev: false)
|
||||
const nuxt = await nuxtCmd.getNuxt(
|
||||
await nuxtCmd.getNuxtConfig(argv, { dev: false })
|
||||
)
|
||||
|
||||
// Setup hooks
|
||||
nuxt.hook('error', err => consola.fatal(err))
|
||||
|
||||
let builderOrGenerator
|
||||
if (nuxt.options.mode !== 'spa' || argv.generate === false) {
|
||||
// Build only
|
||||
builderOrGenerator = (await nuxtCmd.getBuilder(nuxt)).build()
|
||||
} else {
|
||||
// Build + Generate for static deployment
|
||||
builderOrGenerator = (await nuxtCmd.getGenerator(nuxt)).generate({
|
||||
build: true
|
||||
})
|
||||
}
|
||||
|
||||
return builderOrGenerator
|
||||
.then(() => {
|
||||
// In analyze mode wait for plugin
|
||||
// emitting assets and opening browser
|
||||
if (
|
||||
nuxt.options.build.analyze === true ||
|
||||
typeof nuxt.options.build.analyze === 'object'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(err => consola.fatal(err))
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +1,62 @@
|
||||
import consola from 'consola'
|
||||
import NuxtCommand from '../command'
|
||||
import { common, server } from '../options'
|
||||
|
||||
export default async function dev() {
|
||||
const nuxtCmd = new NuxtCommand({
|
||||
description: 'Start the application in development mode (e.g. hot-code reloading, error reporting)',
|
||||
usage: 'dev <dir> -p <port number> -H <hostname>',
|
||||
options: [ 'hostname', 'port' ]
|
||||
})
|
||||
export default {
|
||||
name: 'dev',
|
||||
description: 'Start the application in development mode (e.g. hot-code reloading, error reporting)',
|
||||
usage: 'dev <dir>',
|
||||
options: {
|
||||
...common,
|
||||
...server
|
||||
},
|
||||
async run(cmd) {
|
||||
const argv = cmd.getArgv()
|
||||
|
||||
const argv = nuxtCmd.getArgv()
|
||||
|
||||
const errorHandler = (err, instance) => {
|
||||
instance && instance.builder.watchServer()
|
||||
consola.error(err)
|
||||
}
|
||||
|
||||
// Start dev
|
||||
async function startDev(oldInstance) {
|
||||
let nuxt, builder
|
||||
|
||||
try {
|
||||
nuxt = await nuxtCmd.getNuxt(
|
||||
await nuxtCmd.getNuxtConfig(argv, { dev: true })
|
||||
)
|
||||
builder = await nuxtCmd.getBuilder(nuxt)
|
||||
nuxt.hook('watch:fileChanged', async (builder, fname) => {
|
||||
consola.debug(`[${fname}] changed, Rebuilding the app...`)
|
||||
await startDev({ nuxt: builder.nuxt, builder })
|
||||
})
|
||||
} catch (err) {
|
||||
return errorHandler(err, oldInstance)
|
||||
const errorHandler = (err, instance) => {
|
||||
instance && instance.builder.watchServer()
|
||||
consola.error(err)
|
||||
}
|
||||
|
||||
return (
|
||||
Promise.resolve()
|
||||
.then(() => oldInstance && oldInstance.nuxt.clearHook('watch:fileChanged'))
|
||||
.then(() => oldInstance && oldInstance.builder.unwatch())
|
||||
// Start build
|
||||
.then(() => builder.build())
|
||||
// Close old nuxt no matter if build successfully
|
||||
.catch((err) => {
|
||||
oldInstance && oldInstance.nuxt.close()
|
||||
// Jump to errorHandler
|
||||
throw err
|
||||
})
|
||||
.then(() => oldInstance && oldInstance.nuxt.close())
|
||||
// Start listening
|
||||
.then(() => nuxt.listen())
|
||||
// Show ready message first time, others will be shown through WebpackBar
|
||||
.then(() => !oldInstance && nuxt.showReady(false))
|
||||
.then(() => builder.watchServer())
|
||||
// Handle errors
|
||||
.catch(err => errorHandler(err, { builder, nuxt }))
|
||||
)
|
||||
}
|
||||
// Start dev
|
||||
async function startDev(oldInstance) {
|
||||
let nuxt, builder
|
||||
|
||||
await startDev()
|
||||
try {
|
||||
nuxt = await cmd.getNuxt(
|
||||
await cmd.getNuxtConfig(argv, { dev: true })
|
||||
)
|
||||
builder = await cmd.getBuilder(nuxt)
|
||||
nuxt.hook('watch:fileChanged', async (builder, fname) => {
|
||||
consola.debug(`[${fname}] changed, Rebuilding the app...`)
|
||||
await startDev({ nuxt: builder.nuxt, builder })
|
||||
})
|
||||
} catch (err) {
|
||||
return errorHandler(err, oldInstance)
|
||||
}
|
||||
|
||||
return (
|
||||
Promise.resolve()
|
||||
.then(() => oldInstance && oldInstance.nuxt.clearHook('watch:fileChanged'))
|
||||
.then(() => oldInstance && oldInstance.builder.unwatch())
|
||||
// Start build
|
||||
.then(() => builder.build())
|
||||
// Close old nuxt no matter if build successfully
|
||||
.catch((err) => {
|
||||
oldInstance && oldInstance.nuxt.close()
|
||||
// Jump to errorHandler
|
||||
throw err
|
||||
})
|
||||
.then(() => oldInstance && oldInstance.nuxt.close())
|
||||
// Start listening
|
||||
.then(() => nuxt.listen())
|
||||
// Show ready message first time, others will be shown through WebpackBar
|
||||
.then(() => !oldInstance && nuxt.showReady(false))
|
||||
.then(() => builder.watchServer())
|
||||
// Handle errors
|
||||
.catch(err => errorHandler(err, { builder, nuxt }))
|
||||
)
|
||||
}
|
||||
|
||||
await startDev()
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,32 @@
|
||||
import consola from 'consola'
|
||||
import NuxtCommand from '../command'
|
||||
import { common } from '../options'
|
||||
|
||||
export default async function generate() {
|
||||
const nuxtCmd = new NuxtCommand({
|
||||
description: 'Generate a static web application (server-rendered)',
|
||||
usage: 'generate <dir>',
|
||||
options: [ 'build' ]
|
||||
})
|
||||
export default {
|
||||
name: 'generate',
|
||||
description: 'Generate a static web application (server-rendered)',
|
||||
usage: 'generate <dir>',
|
||||
options: {
|
||||
...common,
|
||||
build: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Only generate pages for dynamic routes. Nuxt has to be built once before using this option'
|
||||
}
|
||||
},
|
||||
async run(cmd) {
|
||||
const argv = cmd.getArgv()
|
||||
|
||||
const argv = nuxtCmd.getArgv()
|
||||
|
||||
const generator = await nuxtCmd.getGenerator(
|
||||
await nuxtCmd.getNuxt(
|
||||
await nuxtCmd.getNuxtConfig(argv, { dev: false })
|
||||
const generator = await cmd.getGenerator(
|
||||
await cmd.getNuxt(
|
||||
await cmd.getNuxtConfig(argv, { dev: false })
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return generator.generate({
|
||||
init: true,
|
||||
build: argv.build
|
||||
}).then(() => {
|
||||
process.exit(0)
|
||||
}).catch(err => consola.fatal(err))
|
||||
return generator.generate({
|
||||
init: true,
|
||||
build: argv.build
|
||||
}).then(() => {
|
||||
process.exit(0)
|
||||
}).catch(err => consola.fatal(err))
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,52 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import consola from 'consola'
|
||||
import NuxtCommand from '../command'
|
||||
import { common, server } from '../options'
|
||||
|
||||
export default async function start() {
|
||||
const nuxtCmd = new NuxtCommand({
|
||||
description: 'Start the application in production mode (the application should be compiled with `nuxt build` first)',
|
||||
usage: 'start <dir> -p <port number> -H <hostname>',
|
||||
options: [ 'hostname', 'port', 'unix-socket' ]
|
||||
})
|
||||
export default {
|
||||
name: 'start',
|
||||
description: 'Start the application in production mode (the application should be compiled with `nuxt build` first)',
|
||||
usage: 'start <dir>',
|
||||
options: {
|
||||
...common,
|
||||
...server
|
||||
},
|
||||
async run(cmd) {
|
||||
const argv = cmd.getArgv()
|
||||
|
||||
const argv = nuxtCmd.getArgv()
|
||||
|
||||
// Create production build when calling `nuxt build`
|
||||
const nuxt = await nuxtCmd.getNuxt(
|
||||
await nuxtCmd.getNuxtConfig(argv, { dev: false })
|
||||
)
|
||||
|
||||
// Setup hooks
|
||||
nuxt.hook('error', err => consola.fatal(err))
|
||||
|
||||
// Check if project is built for production
|
||||
const distDir = path.resolve(
|
||||
nuxt.options.rootDir,
|
||||
nuxt.options.buildDir || '.nuxt',
|
||||
'dist',
|
||||
'server'
|
||||
)
|
||||
if (!fs.existsSync(distDir)) {
|
||||
consola.fatal(
|
||||
'No build files found, please run `nuxt build` before launching `nuxt start`'
|
||||
// Create production build when calling `nuxt build`
|
||||
const nuxt = await cmd.getNuxt(
|
||||
await cmd.getNuxtConfig(argv, { dev: false })
|
||||
)
|
||||
}
|
||||
|
||||
// Check if SSR Bundle is required
|
||||
if (nuxt.options.render.ssr === true) {
|
||||
const ssrBundlePath = path.resolve(distDir, 'server-bundle.json')
|
||||
if (!fs.existsSync(ssrBundlePath)) {
|
||||
// Setup hooks
|
||||
nuxt.hook('error', err => consola.fatal(err))
|
||||
|
||||
// Check if project is built for production
|
||||
const distDir = path.resolve(
|
||||
nuxt.options.rootDir,
|
||||
nuxt.options.buildDir || '.nuxt',
|
||||
'dist',
|
||||
'server'
|
||||
)
|
||||
if (!fs.existsSync(distDir)) {
|
||||
consola.fatal(
|
||||
'No SSR build! Please start with `nuxt start --spa` or build using `nuxt build --universal`'
|
||||
'No build files found, please run `nuxt build` before launching `nuxt start`'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nuxt.listen().then(() => {
|
||||
nuxt.showReady(false)
|
||||
})
|
||||
// Check if SSR Bundle is required
|
||||
if (nuxt.options.render.ssr === true) {
|
||||
const ssrBundlePath = path.resolve(distDir, 'server-bundle.json')
|
||||
if (!fs.existsSync(ssrBundlePath)) {
|
||||
consola.fatal(
|
||||
'No SSR build! Please start with `nuxt start --spa` or build using `nuxt build --universal`'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nuxt.listen().then(() => {
|
||||
nuxt.showReady(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import * as _imports from './imports'
|
||||
export const commands = _commands
|
||||
export const imports = _imports
|
||||
|
||||
export { default as NuxtCommand } from './command'
|
||||
export { default as setup } from './setup'
|
||||
export { default as run } from './run'
|
||||
|
||||
export { loadNuxtConfig } from './utils'
|
||||
|
@ -1,101 +0,0 @@
|
||||
import consola from 'consola'
|
||||
|
||||
export const defaultOptions = [
|
||||
'spa',
|
||||
'universal',
|
||||
'config-file',
|
||||
'version',
|
||||
'help'
|
||||
]
|
||||
|
||||
export const options = {
|
||||
port: {
|
||||
alias: 'p',
|
||||
type: 'string',
|
||||
description: 'Port number on which to start the application',
|
||||
handle(options, argv) {
|
||||
if (argv.port) {
|
||||
options.server.port = +argv.port
|
||||
}
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
alias: 'H',
|
||||
type: 'string',
|
||||
description: 'Hostname on which to start the application',
|
||||
handle(options, argv) {
|
||||
if (argv.hostname === '') {
|
||||
consola.fatal('Provided hostname argument has no value')
|
||||
}
|
||||
}
|
||||
},
|
||||
'unix-socket': {
|
||||
alias: 'n',
|
||||
type: 'string',
|
||||
description: 'Path to a UNIX socket'
|
||||
},
|
||||
analyze: {
|
||||
alias: 'a',
|
||||
type: 'boolean',
|
||||
description: 'Launch webpack-bundle-analyzer to optimize your bundles',
|
||||
handle(options, argv) {
|
||||
// Analyze option
|
||||
options.build = options.build || {}
|
||||
if (argv.analyze && typeof options.build.analyze !== 'object') {
|
||||
options.build.analyze = true
|
||||
}
|
||||
}
|
||||
},
|
||||
build: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Only generate pages for dynamic routes. Nuxt has to be built once before using this option'
|
||||
},
|
||||
generate: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Don\'t generate static version for SPA mode (useful for nuxt start)'
|
||||
},
|
||||
spa: {
|
||||
alias: 's',
|
||||
type: 'boolean',
|
||||
description: 'Launch in SPA mode'
|
||||
},
|
||||
universal: {
|
||||
alias: 'u',
|
||||
type: 'boolean',
|
||||
description: 'Launch in Universal mode (default)'
|
||||
},
|
||||
'config-file': {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
default: 'nuxt.config.js',
|
||||
description: 'Path to Nuxt.js config file (default: nuxt.config.js)'
|
||||
},
|
||||
quiet: {
|
||||
alias: 'q',
|
||||
type: 'boolean',
|
||||
description: 'Disable output except for errors',
|
||||
handle(options, argv) {
|
||||
// Silence output when using --quiet
|
||||
options.build = options.build || {}
|
||||
if (argv.quiet) {
|
||||
options.build.quiet = !!argv.quiet
|
||||
}
|
||||
}
|
||||
},
|
||||
verbose: {
|
||||
alias: 'v',
|
||||
type: 'boolean',
|
||||
description: 'Show debug information'
|
||||
},
|
||||
version: {
|
||||
type: 'boolean',
|
||||
description: 'Display the Nuxt version'
|
||||
},
|
||||
help: {
|
||||
alias: 'h',
|
||||
type: 'boolean',
|
||||
description: 'Display this message'
|
||||
}
|
||||
}
|
27
packages/cli/src/options/common.js
Normal file
27
packages/cli/src/options/common.js
Normal file
@ -0,0 +1,27 @@
|
||||
export default {
|
||||
spa: {
|
||||
alias: 's',
|
||||
type: 'boolean',
|
||||
description: 'Launch in SPA mode'
|
||||
},
|
||||
universal: {
|
||||
alias: 'u',
|
||||
type: 'boolean',
|
||||
description: 'Launch in Universal mode (default)'
|
||||
},
|
||||
'config-file': {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
default: 'nuxt.config.js',
|
||||
description: 'Path to Nuxt.js config file (default: nuxt.config.js)'
|
||||
},
|
||||
version: {
|
||||
type: 'boolean',
|
||||
description: 'Display the Nuxt version'
|
||||
},
|
||||
help: {
|
||||
alias: 'h',
|
||||
type: 'boolean',
|
||||
description: 'Display this message'
|
||||
}
|
||||
}
|
2
packages/cli/src/options/index.js
Normal file
2
packages/cli/src/options/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as common } from './common'
|
||||
export { default as server } from './server'
|
29
packages/cli/src/options/server.js
Normal file
29
packages/cli/src/options/server.js
Normal file
@ -0,0 +1,29 @@
|
||||
import consola from 'consola'
|
||||
|
||||
export default {
|
||||
port: {
|
||||
alias: 'p',
|
||||
type: 'string',
|
||||
description: 'Port number on which to start the application',
|
||||
prepare(cmd, options, argv) {
|
||||
if (argv.port) {
|
||||
options.server.port = +argv.port
|
||||
}
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
alias: 'H',
|
||||
type: 'string',
|
||||
description: 'Hostname on which to start the application',
|
||||
prepare(cmd, options, argv) {
|
||||
if (argv.hostname === '') {
|
||||
consola.fatal('Provided hostname argument has no value')
|
||||
}
|
||||
}
|
||||
},
|
||||
'unix-socket': {
|
||||
alias: 'n',
|
||||
type: 'string',
|
||||
description: 'Path to a UNIX socket'
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import consola from 'consola'
|
||||
import NuxtCommand from './command'
|
||||
import * as commands from './commands'
|
||||
import setup from './setup'
|
||||
|
||||
@ -26,7 +27,9 @@ export default function run() {
|
||||
})
|
||||
|
||||
return commands[cmd]() // eslint-disable-line import/namespace
|
||||
.then(m => m.default())
|
||||
.then(m => m.default)
|
||||
.then(options => NuxtCommand.from(options))
|
||||
.then(command => command.run())
|
||||
.catch((error) => {
|
||||
consola.fatal(error)
|
||||
})
|
||||
|
@ -76,11 +76,11 @@ export function indentLines(string, spaces, firstLineSpaces) {
|
||||
}
|
||||
if (lines.length) {
|
||||
const i = indent(spaces)
|
||||
s += '\n' + lines.map(l => i + l.trim()).join('\n')
|
||||
s += '\n' + lines.map(l => i + l).join('\n')
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
export function foldLines(string, maxCharsPerLine, spaces, firstLineSpaces) {
|
||||
return indentLines(wrapAnsi(string, maxCharsPerLine), spaces, firstLineSpaces)
|
||||
return indentLines(wrapAnsi(string, maxCharsPerLine, { trim: false }), spaces, firstLineSpaces)
|
||||
}
|
||||
|
23
packages/cli/test/unit/__snapshots__/command.test.js.snap
Normal file
23
packages/cli/test/unit/__snapshots__/command.test.js.snap
Normal file
@ -0,0 +1,23 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`cli/command builds help text 1`] = `
|
||||
" Usage: nuxt this is how you do it [options]
|
||||
|
||||
a very long description that is longer than 80 chars and should wrap to the next
|
||||
line while keeping indentation
|
||||
|
||||
Options:
|
||||
|
||||
--spa, -s Launch in SPA mode
|
||||
--universal, -u Launch in Universal mode (default)
|
||||
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
|
||||
--version Display the Nuxt version
|
||||
--help, -h Display this message
|
||||
--port, -p Port number on which to start the application
|
||||
--hostname, -H Hostname on which to start the application
|
||||
--unix-socket, -n Path to a UNIX socket
|
||||
--foo very long option that is longer than 80 chars and should wrap
|
||||
to the next line while keeping indentation
|
||||
|
||||
"
|
||||
`;
|
@ -1,25 +1,18 @@
|
||||
import { consola, mockGetNuxt, mockGetBuilder, mockGetGenerator } from '../utils'
|
||||
import { consola, mockGetNuxt, mockGetBuilder, mockGetGenerator, NuxtCommand } from '../utils'
|
||||
|
||||
describe('build', () => {
|
||||
let build
|
||||
|
||||
beforeAll(async () => {
|
||||
build = await import('../../src/commands/build')
|
||||
build = build.default
|
||||
|
||||
build = await import('../../src/commands/build').then(m => m.default)
|
||||
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
process.exit.mockRestore()
|
||||
})
|
||||
afterAll(() => process.exit.mockRestore())
|
||||
afterEach(() => jest.resetAllMocks())
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
test('is function', () => {
|
||||
expect(typeof build).toBe('function')
|
||||
test('has run function', () => {
|
||||
expect(typeof build.run).toBe('function')
|
||||
})
|
||||
|
||||
test('builds on universal mode', async () => {
|
||||
@ -31,7 +24,7 @@ describe('build', () => {
|
||||
})
|
||||
const builder = mockGetBuilder(Promise.resolve())
|
||||
|
||||
await build()
|
||||
await NuxtCommand.from(build).run()
|
||||
|
||||
expect(builder).toHaveBeenCalled()
|
||||
})
|
||||
@ -45,7 +38,7 @@ describe('build', () => {
|
||||
})
|
||||
const generate = mockGetGenerator(Promise.resolve())
|
||||
|
||||
await build()
|
||||
await NuxtCommand.from(build).run()
|
||||
|
||||
expect(generate).toHaveBeenCalled()
|
||||
expect(process.exit).toHaveBeenCalled()
|
||||
@ -55,7 +48,7 @@ describe('build', () => {
|
||||
mockGetNuxt({ mode: 'universal' })
|
||||
mockGetBuilder(Promise.reject(new Error('Builder Error')))
|
||||
|
||||
await build()
|
||||
await NuxtCommand.from(build).run()
|
||||
|
||||
expect(consola.fatal).toHaveBeenCalledWith(new Error('Builder Error'))
|
||||
})
|
||||
|
@ -10,9 +10,7 @@ const readDir = promisify(readdir)
|
||||
jest.mock('../../src/commands')
|
||||
|
||||
describe('cli', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
afterEach(() => jest.resetAllMocks())
|
||||
|
||||
test('exports for all commands defined', async () => {
|
||||
const cmds = await readDir(resolve(__dirname, '..', '..', 'src', 'commands'))
|
||||
@ -32,12 +30,14 @@ describe('cli', () => {
|
||||
test('calls expected method', async () => {
|
||||
const argv = process.argv
|
||||
process.argv = ['', '', 'dev']
|
||||
const defaultExport = jest.fn().mockImplementation(() => Promise.resolve())
|
||||
const defaultExport = {
|
||||
run: jest.fn().mockImplementation(() => Promise.resolve())
|
||||
}
|
||||
commands.dev.mockImplementationOnce(() => Promise.resolve({ default: defaultExport }))
|
||||
|
||||
await run()
|
||||
|
||||
expect(defaultExport).toHaveBeenCalled()
|
||||
expect(defaultExport.run).toHaveBeenCalled()
|
||||
process.argv = argv
|
||||
})
|
||||
|
||||
|
@ -1,39 +1,31 @@
|
||||
import Command from '../../src/command'
|
||||
import { options as Options } from '../../src/options'
|
||||
import { common, server } from '../../src/options'
|
||||
import { consola } from '../utils'
|
||||
|
||||
jest.mock('@nuxt/core')
|
||||
jest.mock('@nuxt/builder')
|
||||
jest.mock('@nuxt/generator')
|
||||
|
||||
const allOptions = {
|
||||
...common,
|
||||
...server
|
||||
}
|
||||
|
||||
describe('cli/command', () => {
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
test('adds default options', () => {
|
||||
const cmd = new Command()
|
||||
|
||||
expect(cmd.options.length).not.toBe(0)
|
||||
})
|
||||
beforeEach(() => jest.restoreAllMocks())
|
||||
|
||||
test('builds minimist options', () => {
|
||||
const cmd = new Command({
|
||||
options: Object.keys(Options)
|
||||
})
|
||||
|
||||
const cmd = new Command({ options: allOptions })
|
||||
const minimistOptions = cmd._getMinimistOptions()
|
||||
|
||||
expect(minimistOptions.string.length).toBe(4)
|
||||
expect(minimistOptions.boolean.length).toBe(9)
|
||||
expect(minimistOptions.boolean.length).toBe(4)
|
||||
expect(minimistOptions.alias.c).toBe('config-file')
|
||||
expect(minimistOptions.default.c).toBe(Options['config-file'].default)
|
||||
expect(minimistOptions.default.c).toBe(common['config-file'].default)
|
||||
})
|
||||
|
||||
test('parses args', () => {
|
||||
const cmd = new Command({
|
||||
options: Object.keys(Options)
|
||||
})
|
||||
const cmd = new Command({ options: { ...common, ...server } })
|
||||
|
||||
let args = ['-c', 'test-file', '-s', '-p', '3001']
|
||||
let argv = cmd.getArgv(args)
|
||||
@ -41,7 +33,6 @@ describe('cli/command', () => {
|
||||
expect(argv['config-file']).toBe(args[1])
|
||||
expect(argv.spa).toBe(true)
|
||||
expect(argv.universal).toBe(false)
|
||||
expect(argv.build).toBe(true)
|
||||
expect(argv.port).toBe('3001')
|
||||
|
||||
args = ['--no-build']
|
||||
@ -61,7 +52,7 @@ describe('cli/command', () => {
|
||||
})
|
||||
|
||||
test('prints help automatically', () => {
|
||||
const cmd = new Command()
|
||||
const cmd = new Command({ options: allOptions })
|
||||
cmd.showHelp = jest.fn()
|
||||
|
||||
const args = ['-h']
|
||||
@ -71,9 +62,7 @@ describe('cli/command', () => {
|
||||
})
|
||||
|
||||
test('returns nuxt config', async () => {
|
||||
const cmd = new Command({
|
||||
options: Object.keys(Options)
|
||||
})
|
||||
const cmd = new Command({ options: allOptions })
|
||||
|
||||
const args = ['-c', 'test-file', '-a', '-p', '3001', '-q', '-H']
|
||||
const argv = cmd.getArgv(args)
|
||||
@ -83,8 +72,6 @@ describe('cli/command', () => {
|
||||
|
||||
expect(options.testOption).toBe(true)
|
||||
expect(options.server.port).toBe(3001)
|
||||
expect(options.build.quiet).toBe(true)
|
||||
expect(options.build.analyze).toBe(true)
|
||||
expect(consola.fatal).toHaveBeenCalledWith('Provided hostname argument has no value') // hostname check
|
||||
})
|
||||
|
||||
@ -117,26 +104,17 @@ describe('cli/command', () => {
|
||||
description: 'a very long description that is longer than 80 chars and ' +
|
||||
'should wrap to the next line while keeping indentation',
|
||||
usage: 'this is how you do it',
|
||||
options: ['build']
|
||||
options: {
|
||||
...allOptions,
|
||||
foo: {
|
||||
type: 'boolean',
|
||||
description: 'very long option that is longer than 80 chars and ' +
|
||||
'should wrap to the next line while keeping indentation'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const expectedText = `
|
||||
Description
|
||||
a very long description that is longer than 80 chars and should wrap to the next
|
||||
line while keeping indentation
|
||||
Usage
|
||||
$ nuxt this is how you do it
|
||||
Options
|
||||
--no-build Only generate pages for dynamic routes. Nuxt has to be
|
||||
built once before using this option
|
||||
--spa, -s Launch in SPA mode
|
||||
--universal, -u Launch in Universal mode (default)
|
||||
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
|
||||
--version Display the Nuxt version
|
||||
--help, -h Display this message
|
||||
|
||||
`
|
||||
expect(cmd._getHelp()).toBe(expectedText)
|
||||
expect(cmd._getHelp()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('show version prints to stdout and exits', () => {
|
||||
|
@ -1,26 +1,23 @@
|
||||
import { consola, mockNuxt, mockBuilder, mockGetNuxtConfig } from '../utils'
|
||||
import { consola, mockNuxt, mockBuilder, mockGetNuxtConfig, NuxtCommand } from '../utils'
|
||||
|
||||
describe('dev', () => {
|
||||
let dev
|
||||
|
||||
beforeAll(async () => {
|
||||
dev = await import('../../src/commands/dev')
|
||||
dev = dev.default
|
||||
dev = await import('../../src/commands/dev').then(m => m.default)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
afterEach(() => jest.clearAllMocks())
|
||||
|
||||
test('is function', () => {
|
||||
expect(typeof dev).toBe('function')
|
||||
test('has run function', () => {
|
||||
expect(typeof dev.run).toBe('function')
|
||||
})
|
||||
|
||||
test('reloads on fileChanged hook', async () => {
|
||||
const Nuxt = mockNuxt()
|
||||
const Builder = mockBuilder()
|
||||
|
||||
await dev()
|
||||
await NuxtCommand.from(dev).run()
|
||||
|
||||
expect(consola.error).not.toHaveBeenCalled()
|
||||
|
||||
@ -51,7 +48,7 @@ describe('dev', () => {
|
||||
const Nuxt = mockNuxt()
|
||||
const Builder = mockBuilder()
|
||||
|
||||
await dev()
|
||||
await NuxtCommand.from(dev).run()
|
||||
jest.clearAllMocks()
|
||||
|
||||
// Test error on second build so we cover oldInstance stuff
|
||||
@ -68,7 +65,7 @@ describe('dev', () => {
|
||||
const Nuxt = mockNuxt()
|
||||
const Builder = mockBuilder()
|
||||
|
||||
await dev()
|
||||
await NuxtCommand.from(dev).run()
|
||||
jest.clearAllMocks()
|
||||
|
||||
const builder = new Builder()
|
||||
@ -84,7 +81,7 @@ describe('dev', () => {
|
||||
const Nuxt = mockNuxt()
|
||||
const Builder = mockBuilder()
|
||||
|
||||
await dev()
|
||||
await NuxtCommand.from(dev).run()
|
||||
jest.clearAllMocks()
|
||||
|
||||
mockGetNuxtConfig().mockImplementationOnce(() => {
|
||||
@ -106,7 +103,7 @@ describe('dev', () => {
|
||||
})
|
||||
mockBuilder()
|
||||
|
||||
await dev()
|
||||
await NuxtCommand.from(dev).run()
|
||||
|
||||
expect(consola.error).toHaveBeenCalledWith(new Error('Listen Error'))
|
||||
})
|
||||
|
@ -1,33 +1,26 @@
|
||||
import { consola, mockGetNuxt, mockGetGenerator } from '../utils'
|
||||
import { consola, mockGetNuxt, mockGetGenerator, NuxtCommand } from '../utils'
|
||||
import Command from '../../src/command'
|
||||
|
||||
describe('generate', () => {
|
||||
let generate
|
||||
|
||||
beforeAll(async () => {
|
||||
generate = await import('../../src/commands/generate')
|
||||
generate = generate.default
|
||||
|
||||
generate = await import('../../src/commands/generate').then(m => m.default)
|
||||
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
process.exit.mockRestore()
|
||||
})
|
||||
afterAll(() => process.exit.mockRestore())
|
||||
afterEach(() => jest.resetAllMocks())
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
test('is function', () => {
|
||||
expect(typeof generate).toBe('function')
|
||||
test('has run function', () => {
|
||||
expect(typeof generate.run).toBe('function')
|
||||
})
|
||||
|
||||
test('builds by default', async () => {
|
||||
mockGetNuxt()
|
||||
const generator = mockGetGenerator(Promise.resolve())
|
||||
|
||||
await generate()
|
||||
await NuxtCommand.from(generate).run()
|
||||
|
||||
expect(generator).toHaveBeenCalled()
|
||||
expect(generator.mock.calls[0][0].build).toBe(true)
|
||||
@ -46,7 +39,7 @@ describe('generate', () => {
|
||||
})
|
||||
const generator = mockGetGenerator(Promise.resolve())
|
||||
|
||||
await generate()
|
||||
await NuxtCommand.from(generate).run()
|
||||
|
||||
expect(generator).toHaveBeenCalled()
|
||||
expect(generator.mock.calls[0][0].build).toBe(false)
|
||||
@ -57,7 +50,7 @@ describe('generate', () => {
|
||||
mockGetNuxt()
|
||||
mockGetGenerator(Promise.reject(new Error('Generator Error')))
|
||||
|
||||
await generate()
|
||||
await NuxtCommand.from(generate).run()
|
||||
|
||||
expect(consola.fatal).toHaveBeenCalledWith(new Error('Generator Error'))
|
||||
})
|
||||
|
@ -1,29 +1,27 @@
|
||||
import fs from 'fs'
|
||||
import { consola, mockGetNuxtStart, mockGetNuxtConfig } from '../utils'
|
||||
import { consola, mockGetNuxtStart, mockGetNuxtConfig, NuxtCommand } from '../utils'
|
||||
|
||||
describe('start', () => {
|
||||
let start
|
||||
|
||||
beforeAll(async () => {
|
||||
start = await import('../../src/commands/start')
|
||||
start = start.default
|
||||
start = await import('../../src/commands/start').then(m => m.default)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (fs.existsSync.mockRestore) {
|
||||
fs.existsSync.mockRestore()
|
||||
}
|
||||
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
test('is function', () => {
|
||||
expect(typeof start).toBe('function')
|
||||
test('has run function', () => {
|
||||
expect(typeof start.run).toBe('function')
|
||||
})
|
||||
|
||||
test('starts listening and calls showReady', async () => {
|
||||
const { listen, showReady } = mockGetNuxtStart()
|
||||
await start()
|
||||
await NuxtCommand.from(start).run()
|
||||
|
||||
expect(listen).toHaveBeenCalled()
|
||||
expect(showReady).toHaveBeenCalled()
|
||||
@ -34,7 +32,7 @@ describe('start', () => {
|
||||
mockGetNuxtConfig()
|
||||
jest.spyOn(fs, 'existsSync').mockImplementationOnce(() => true)
|
||||
|
||||
await start()
|
||||
await NuxtCommand.from(start).run()
|
||||
|
||||
expect(consola.fatal).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -43,7 +41,7 @@ describe('start', () => {
|
||||
mockGetNuxtStart()
|
||||
jest.spyOn(fs, 'existsSync').mockImplementationOnce(() => false)
|
||||
|
||||
await start()
|
||||
await NuxtCommand.from(start).run()
|
||||
|
||||
expect(consola.fatal).toHaveBeenCalledWith('No build files found, please run `nuxt build` before launching `nuxt start`')
|
||||
})
|
||||
@ -53,7 +51,7 @@ describe('start', () => {
|
||||
mockGetNuxtConfig()
|
||||
jest.spyOn(fs, 'existsSync').mockImplementation(() => true)
|
||||
|
||||
await start()
|
||||
await NuxtCommand.from(start).run()
|
||||
|
||||
expect(consola.fatal).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -62,7 +60,7 @@ describe('start', () => {
|
||||
mockGetNuxtStart(true)
|
||||
jest.spyOn(fs, 'existsSync').mockImplementation(() => false)
|
||||
|
||||
await start()
|
||||
await NuxtCommand.from(start).run()
|
||||
|
||||
expect(consola.fatal).toHaveBeenCalledWith('No SSR build! Please start with `nuxt start --spa` or build using `nuxt build --universal`')
|
||||
})
|
||||
|
@ -3,9 +3,7 @@ import { consola } from '../utils'
|
||||
import * as utils from '../../src/utils'
|
||||
|
||||
describe('cli/utils', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
afterEach(() => jest.resetAllMocks())
|
||||
|
||||
test('loadNuxtConfig: defaults', async () => {
|
||||
const argv = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import consola from 'consola'
|
||||
export * from './mocking'
|
||||
export { NuxtCommand } from '../../src'
|
||||
|
||||
jest.mock('consola')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user