mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 22:25:12 +00:00
feat(cli): improvements and external commands (#4314)
This commit is contained in:
parent
8b366fd216
commit
0145551c3a
@ -1,3 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
require('../dist/cli.js').run()
|
require('../dist/cli.js').run()
|
||||||
|
.catch((error) => {
|
||||||
|
require('consola').fatal(error)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"chalk": "^2.4.1",
|
"chalk": "^2.4.1",
|
||||||
"consola": "^2.3.0",
|
"consola": "^2.3.0",
|
||||||
"esm": "^3.0.84",
|
"esm": "^3.0.84",
|
||||||
|
"execa": "^1.0.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"pretty-bytes": "^5.1.0",
|
"pretty-bytes": "^5.1.0",
|
||||||
"std-env": "^2.2.1",
|
"std-env": "^2.2.1",
|
||||||
|
@ -1,66 +1,72 @@
|
|||||||
import parseArgs from 'minimist'
|
|
||||||
|
import minimist from 'minimist'
|
||||||
import { name, version } from '../package.json'
|
import { name, version } from '../package.json'
|
||||||
import { loadNuxtConfig } from './utils'
|
import { loadNuxtConfig } from './utils'
|
||||||
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
|
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
|
||||||
import * as commands from './commands'
|
|
||||||
import * as imports from './imports'
|
import * as imports from './imports'
|
||||||
|
|
||||||
export default class NuxtCommand {
|
export default class NuxtCommand {
|
||||||
constructor(cmd = { name: '', usage: '', description: '', options: {} }) {
|
constructor(cmd = { name: '', usage: '', description: '' }, argv = process.argv.slice(2)) {
|
||||||
|
if (!cmd.options) {
|
||||||
|
cmd.options = {}
|
||||||
|
}
|
||||||
this.cmd = cmd
|
this.cmd = cmd
|
||||||
|
|
||||||
|
this._argv = Array.from(argv)
|
||||||
|
this._parsedArgv = null // Lazy evaluate
|
||||||
}
|
}
|
||||||
|
|
||||||
static async load(name) {
|
static run(cmd, argv) {
|
||||||
if (name in commands) {
|
return NuxtCommand.from(cmd, argv).run()
|
||||||
const cmd = await commands[name]() // eslint-disable-line import/namespace
|
|
||||||
.then(m => m.default)
|
|
||||||
return NuxtCommand.from(cmd)
|
|
||||||
} else {
|
|
||||||
// TODO dynamic module loading
|
|
||||||
throw new Error('Command ' + name + ' could not be loaded!')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static from(options) {
|
static from(cmd, argv) {
|
||||||
if (options instanceof NuxtCommand) {
|
if (cmd instanceof NuxtCommand) {
|
||||||
return options
|
return cmd
|
||||||
}
|
}
|
||||||
return new NuxtCommand(options)
|
return new NuxtCommand(cmd, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
run() {
|
run() {
|
||||||
return this.cmd.run(this)
|
if (this.argv.help) {
|
||||||
|
this.showHelp()
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.argv.version) {
|
||||||
|
this.showVersion()
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.cmd.run !== 'function') {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(this.cmd.run(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
showVersion() {
|
showVersion() {
|
||||||
process.stdout.write(`${name} v${version}\n`)
|
process.stdout.write(`${name} v${version}\n`)
|
||||||
process.exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showHelp() {
|
showHelp() {
|
||||||
process.stdout.write(this._getHelp())
|
process.stdout.write(this._getHelp())
|
||||||
process.exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getArgv(args) {
|
get argv() {
|
||||||
|
if (!this._parsedArgv) {
|
||||||
const minimistOptions = this._getMinimistOptions()
|
const minimistOptions = this._getMinimistOptions()
|
||||||
const argv = parseArgs(args || process.argv.slice(2), minimistOptions)
|
this._parsedArgv = minimist(this._argv, minimistOptions)
|
||||||
|
}
|
||||||
if (argv.version) {
|
return this._parsedArgv
|
||||||
this.showVersion()
|
|
||||||
} else if (argv.help) {
|
|
||||||
this.showHelp()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return argv
|
async getNuxtConfig(extraOptions) {
|
||||||
}
|
const config = await loadNuxtConfig(this.argv)
|
||||||
|
|
||||||
async getNuxtConfig(argv, extraOptions) {
|
|
||||||
const config = await loadNuxtConfig(argv)
|
|
||||||
const options = Object.assign(config, extraOptions || {})
|
const options = Object.assign(config, extraOptions || {})
|
||||||
|
|
||||||
for (const name of Object.keys(this.cmd.options)) {
|
for (const name of Object.keys(this.cmd.options)) {
|
||||||
this.cmd.options[name].prepare && this.cmd.options[name].prepare(this, options, argv)
|
this.cmd.options[name].prepare && this.cmd.options[name].prepare(this, options, this.argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import consola from 'consola'
|
|
||||||
import { common } from '../options'
|
import { common } from '../options'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -50,37 +49,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run(cmd) {
|
async run(cmd) {
|
||||||
const argv = cmd.getArgv()
|
const config = await cmd.getNuxtConfig({ dev: false })
|
||||||
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
|
||||||
// Create production build when calling `nuxt build` (dev: false)
|
if (nuxt.options.mode !== 'spa' || cmd.argv.generate === false) {
|
||||||
const nuxt = await cmd.getNuxt(
|
|
||||||
await cmd.getNuxtConfig(argv, { dev: false })
|
|
||||||
)
|
|
||||||
|
|
||||||
let builderOrGenerator
|
|
||||||
if (nuxt.options.mode !== 'spa' || argv.generate === false) {
|
|
||||||
// Build only
|
// Build only
|
||||||
builderOrGenerator = (await cmd.getBuilder(nuxt)).build()
|
const builder = await cmd.getBuilder(nuxt)
|
||||||
|
await builder.build()
|
||||||
} else {
|
} else {
|
||||||
// Build + Generate for static deployment
|
// Build + Generate for static deployment
|
||||||
builderOrGenerator = (await cmd.getGenerator(nuxt)).generate({
|
const generator = await cmd.getGenerator(nuxt)
|
||||||
build: true
|
await generator.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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async run(cmd) {
|
async run(cmd) {
|
||||||
const argv = cmd.getArgv()
|
const argv = cmd.argv
|
||||||
await this.startDev(cmd, argv)
|
await this.startDev(cmd, argv)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -26,10 +26,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async _startDev(cmd, argv) {
|
async _startDev(cmd, argv) {
|
||||||
// Load config
|
const config = await cmd.getNuxtConfig({ dev: true })
|
||||||
const config = await cmd.getNuxtConfig(argv, { dev: true })
|
|
||||||
|
|
||||||
// Initialize nuxt instance
|
|
||||||
const nuxt = await cmd.getNuxt(config)
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
|
||||||
// Setup hooks
|
// Setup hooks
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import consola from 'consola'
|
|
||||||
import { common } from '../options'
|
import { common } from '../options'
|
||||||
import { normalizeArg } from '../utils'
|
import { normalizeArg } from '../utils'
|
||||||
|
|
||||||
@ -36,19 +35,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async run(cmd) {
|
async run(cmd) {
|
||||||
const argv = cmd.getArgv()
|
const config = await cmd.getNuxtConfig({ dev: false })
|
||||||
|
const nuxt = await cmd.getNuxt(config)
|
||||||
|
const generator = await cmd.getGenerator(nuxt)
|
||||||
|
|
||||||
const generator = await cmd.getGenerator(
|
await generator.generate({
|
||||||
await cmd.getNuxt(
|
|
||||||
await cmd.getNuxtConfig(argv, { dev: false })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return generator.generate({
|
|
||||||
init: true,
|
init: true,
|
||||||
build: argv.build
|
build: cmd.argv.build
|
||||||
}).then(() => {
|
})
|
||||||
process.exit(0)
|
|
||||||
}).catch(err => consola.fatal(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import NuxtCommand from '../command'
|
import getCommand from '../commands'
|
||||||
import listCommands from '../list'
|
import listCommands from '../list'
|
||||||
|
import { common } from '../options'
|
||||||
|
import NuxtCommand from '../command'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'help',
|
name: 'help',
|
||||||
description: 'Shows help for <command>',
|
description: 'Shows help for <command>',
|
||||||
usage: 'help <command>',
|
usage: 'help <command>',
|
||||||
|
options: {
|
||||||
|
help: common.help,
|
||||||
|
version: common.version
|
||||||
|
},
|
||||||
async run(cmd) {
|
async run(cmd) {
|
||||||
const argv = cmd.getArgv()._
|
const name = cmd._argv[0]
|
||||||
const name = argv[0] || null
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return listCommands().then(() => process.exit(0))
|
return listCommands()
|
||||||
}
|
}
|
||||||
const command = await NuxtCommand.load(name)
|
const command = await getCommand(name)
|
||||||
if (command) {
|
if (command) {
|
||||||
command.showHelp()
|
NuxtCommand.from(command).showHelp()
|
||||||
} else {
|
} else {
|
||||||
consola.info(`Unknown command: ${name}`)
|
consola.info(`Unknown command: ${name}`)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
export const start = () => import('./start')
|
const commands = {
|
||||||
export const dev = () => import('./dev')
|
start: () => import('./start'),
|
||||||
export const build = () => import('./build')
|
dev: () => import('./dev'),
|
||||||
export const generate = () => import('./generate')
|
build: () => import('./build'),
|
||||||
export const help = () => import('./help')
|
generate: () => import('./generate'),
|
||||||
|
help: () => import('./help')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getCommand(name) {
|
||||||
|
if (!commands[name]) {
|
||||||
|
return Promise.resolve(null)
|
||||||
|
}
|
||||||
|
return commands[name]().then(m => m.default)
|
||||||
|
}
|
||||||
|
@ -10,16 +10,11 @@ export default {
|
|||||||
...server
|
...server
|
||||||
},
|
},
|
||||||
async run(cmd) {
|
async run(cmd) {
|
||||||
const argv = cmd.getArgv()
|
const config = await cmd.getNuxtConfig({ dev: false, _start: true })
|
||||||
|
const nuxt = await cmd.getNuxt(config)
|
||||||
// Create production build when calling `nuxt build`
|
|
||||||
const nuxt = await cmd.getNuxt(
|
|
||||||
await cmd.getNuxtConfig(argv, { dev: false, _start: true })
|
|
||||||
)
|
|
||||||
|
|
||||||
// Listen and show ready banner
|
// Listen and show ready banner
|
||||||
return nuxt.server.listen().then(() => {
|
await nuxt.server.listen()
|
||||||
showBanner(nuxt)
|
showBanner(nuxt)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import NuxtCommand from './command'
|
|
||||||
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
|
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
|
||||||
|
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']
|
||||||
|
|
||||||
// Load all commands
|
// Load all commands
|
||||||
const _commands = await Promise.all(
|
const _commands = await Promise.all(
|
||||||
commandsOrder.map(cmd => NuxtCommand.load(cmd))
|
commandsOrder.map(cmd => getCommand(cmd))
|
||||||
)
|
)
|
||||||
|
|
||||||
let maxLength = 0
|
let maxLength = 0
|
||||||
|
@ -28,6 +28,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
version: {
|
version: {
|
||||||
|
alias: 'v',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Display the Nuxt version'
|
description: 'Display the Nuxt version'
|
||||||
},
|
},
|
||||||
|
@ -1,31 +1,42 @@
|
|||||||
import consola from 'consola'
|
import fs from 'fs'
|
||||||
|
import execa from 'execa'
|
||||||
import NuxtCommand from './command'
|
import NuxtCommand from './command'
|
||||||
import * as commands from './commands'
|
|
||||||
import setup from './setup'
|
import setup from './setup'
|
||||||
import listCommands from './list'
|
import getCommand from './commands'
|
||||||
|
|
||||||
export default function run() {
|
export default async function run(_argv) {
|
||||||
const defaultCommand = 'dev'
|
// Read from process.argv
|
||||||
let cmd = process.argv[2]
|
const argv = _argv ? Array.from(_argv) : process.argv.slice(2)
|
||||||
|
|
||||||
if (commands[cmd]) { // eslint-disable-line import/namespace
|
// Check for internal command
|
||||||
process.argv.splice(2, 1)
|
let cmd = await getCommand(argv[0])
|
||||||
|
|
||||||
|
// Matching `nuxt` or `nuxt [dir]` or `nuxt -*` for `nuxt dev` shortcut
|
||||||
|
if (!cmd && (!argv[0] || argv[0][0] === '-' || fs.existsSync(argv[0]))) {
|
||||||
|
argv.unshift('dev')
|
||||||
|
cmd = await getCommand('dev')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup env
|
||||||
|
setup({ dev: argv[0] === 'dev' })
|
||||||
|
|
||||||
|
// Try internal command
|
||||||
|
if (cmd) {
|
||||||
|
return NuxtCommand.run(cmd, argv.slice(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try external command
|
||||||
|
try {
|
||||||
|
await execa(`nuxt-${argv[0]}`, argv.slice(1), {
|
||||||
|
stdout: process.stdout,
|
||||||
|
stderr: process.stderr,
|
||||||
|
stdin: process.stdin
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
throw String(`Command not found: nuxt-${argv[0]}`)
|
||||||
} else {
|
} else {
|
||||||
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
throw String(`Failed to run command \`nuxt-${argv[0]}\`:\n${error}`)
|
||||||
listCommands().then(() => process.exit(0))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
cmd = defaultCommand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup runtime
|
|
||||||
setup({
|
|
||||||
dev: cmd === 'dev'
|
|
||||||
})
|
|
||||||
|
|
||||||
return NuxtCommand.load(cmd)
|
|
||||||
.then(command => command.run())
|
|
||||||
.catch((error) => {
|
|
||||||
consola.fatal(error)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import chalk from 'chalk'
|
|||||||
import prettyBytes from 'pretty-bytes'
|
import prettyBytes from 'pretty-bytes'
|
||||||
import env from 'std-env'
|
import env from 'std-env'
|
||||||
|
|
||||||
const _require = esm(module, {
|
export const requireModule = esm(module, {
|
||||||
cache: false,
|
cache: false,
|
||||||
cjs: {
|
cjs: {
|
||||||
cache: true,
|
cache: true,
|
||||||
@ -35,7 +35,7 @@ export async function loadNuxtConfig(argv) {
|
|||||||
|
|
||||||
if (existsSync(nuxtConfigFile)) {
|
if (existsSync(nuxtConfigFile)) {
|
||||||
delete require.cache[nuxtConfigFile]
|
delete require.cache[nuxtConfigFile]
|
||||||
options = _require(nuxtConfigFile) || {}
|
options = requireModule(nuxtConfigFile) || {}
|
||||||
if (options.default) {
|
if (options.default) {
|
||||||
options = options.default
|
options = options.default
|
||||||
}
|
}
|
||||||
@ -120,6 +120,13 @@ export function showBanner(nuxt) {
|
|||||||
process.stdout.write(box + '\n')
|
process.stdout.write(box + '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatPath(filePath) {
|
||||||
|
if (!filePath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return filePath.replace(process.cwd() + path.sep, '')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize string argument in command
|
* Normalize string argument in command
|
||||||
*
|
*
|
||||||
@ -137,10 +144,3 @@ export function normalizeArg(arg, defaultValue) {
|
|||||||
}
|
}
|
||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatPath(filePath) {
|
|
||||||
if (!filePath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return filePath.replace(process.cwd() + path.sep, '')
|
|
||||||
}
|
|
||||||
|
@ -11,7 +11,7 @@ exports[`cli/command builds help text 1`] = `
|
|||||||
--universal, -u Launch in Universal mode (default)
|
--universal, -u Launch in Universal mode (default)
|
||||||
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
|
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
|
||||||
--modern, -m Build/Start app for modern browsers, e.g. server, client and false
|
--modern, -m Build/Start app for modern browsers, e.g. server, client and false
|
||||||
--version Display the Nuxt version
|
--version, -v Display the Nuxt version
|
||||||
--help, -h Display this message
|
--help, -h Display this message
|
||||||
--port, -p Port number on which to start the application
|
--port, -p Port number on which to start the application
|
||||||
--hostname, -H Hostname on which to start the application
|
--hostname, -H Hostname on which to start the application
|
||||||
@ -20,23 +20,3 @@ exports[`cli/command builds help text 1`] = `
|
|||||||
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`cli/command loads command from name 1`] = `
|
|
||||||
" Usage: nuxt dev <dir> [options]
|
|
||||||
|
|
||||||
Start the application in development mode (e.g. hot-code reloading, error reporting)
|
|
||||||
|
|
||||||
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)
|
|
||||||
--modern, -m Build/Start app for modern browsers, e.g. server, client and false
|
|
||||||
--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
|
|
||||||
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { consola, mockGetNuxt, mockGetBuilder, mockGetGenerator, NuxtCommand } from '../utils'
|
import { mockGetNuxt, mockGetBuilder, mockGetGenerator, NuxtCommand } from '../utils'
|
||||||
|
|
||||||
describe('build', () => {
|
describe('build', () => {
|
||||||
let build
|
let build
|
||||||
@ -8,7 +8,6 @@ describe('build', () => {
|
|||||||
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => process.exit.mockRestore())
|
|
||||||
afterEach(() => jest.resetAllMocks())
|
afterEach(() => jest.resetAllMocks())
|
||||||
|
|
||||||
test('has run function', () => {
|
test('has run function', () => {
|
||||||
@ -41,7 +40,6 @@ describe('build', () => {
|
|||||||
await NuxtCommand.from(build).run()
|
await NuxtCommand.from(build).run()
|
||||||
|
|
||||||
expect(generate).toHaveBeenCalled()
|
expect(generate).toHaveBeenCalled()
|
||||||
expect(process.exit).toHaveBeenCalled()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('build with devtools', async () => {
|
test('build with devtools', async () => {
|
||||||
@ -50,12 +48,9 @@ describe('build', () => {
|
|||||||
})
|
})
|
||||||
const builder = mockGetBuilder(Promise.resolve())
|
const builder = mockGetBuilder(Promise.resolve())
|
||||||
|
|
||||||
const cmd = NuxtCommand.from(build)
|
const cmd = NuxtCommand.from(build, ['build', '.', '--devtools'])
|
||||||
const args = ['build', '.', '--devtools']
|
|
||||||
const argv = cmd.getArgv(args)
|
|
||||||
argv._ = ['.']
|
|
||||||
|
|
||||||
const options = await cmd.getNuxtConfig(argv)
|
const options = await cmd.getNuxtConfig(cmd.argv)
|
||||||
|
|
||||||
await cmd.run()
|
await cmd.run()
|
||||||
|
|
||||||
@ -69,22 +64,12 @@ describe('build', () => {
|
|||||||
})
|
})
|
||||||
mockGetBuilder(Promise.resolve())
|
mockGetBuilder(Promise.resolve())
|
||||||
|
|
||||||
const cmd = NuxtCommand.from(build)
|
const cmd = NuxtCommand.from(build, ['build', '.', '--m'])
|
||||||
const args = ['build', '.', '--m']
|
|
||||||
|
|
||||||
const options = await cmd.getNuxtConfig(cmd.getArgv(args))
|
const options = await cmd.getNuxtConfig()
|
||||||
|
|
||||||
await cmd.run()
|
await cmd.run()
|
||||||
|
|
||||||
expect(options.modern).toBe(true)
|
expect(options.modern).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('catches error', async () => {
|
|
||||||
mockGetNuxt({ mode: 'universal' })
|
|
||||||
mockGetBuilder(Promise.reject(new Error('Builder Error')))
|
|
||||||
|
|
||||||
await NuxtCommand.from(build).run()
|
|
||||||
|
|
||||||
expect(consola.fatal).toHaveBeenCalledWith(new Error('Builder Error'))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -1,87 +1,41 @@
|
|||||||
import { readdir } from 'fs'
|
|
||||||
import { resolve } from 'path'
|
|
||||||
import { promisify } from 'util'
|
|
||||||
import { consola } from '../utils'
|
|
||||||
import { run } from '../../src'
|
import { run } from '../../src'
|
||||||
import * as commands from '../../src/commands'
|
import getCommand from '../../src/commands'
|
||||||
|
|
||||||
const readDir = promisify(readdir)
|
|
||||||
|
|
||||||
jest.mock('../../src/commands')
|
jest.mock('../../src/commands')
|
||||||
|
|
||||||
describe('cli', () => {
|
describe('cli', () => {
|
||||||
afterEach(() => jest.resetAllMocks())
|
afterEach(() => jest.resetAllMocks())
|
||||||
|
|
||||||
test('exports for all commands defined', async () => {
|
|
||||||
const cmds = await readDir(resolve(__dirname, '..', '..', 'src', 'commands'))
|
|
||||||
|
|
||||||
for (let cmd of cmds) {
|
|
||||||
if (cmd === 'index.js') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cmd = cmd.substring(0, cmd.length - 3)
|
|
||||||
|
|
||||||
const cmdFn = commands[cmd] // eslint-disable-line import/namespace
|
|
||||||
expect(cmdFn).toBeDefined()
|
|
||||||
expect(typeof cmdFn).toBe('function')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test('calls expected method', async () => {
|
test('calls expected method', async () => {
|
||||||
const argv = process.argv
|
const mockedCommand = {
|
||||||
process.argv = ['', '', 'dev']
|
run: jest.fn().mockImplementation(() => Promise.resolve({}))
|
||||||
const defaultExport = {
|
|
||||||
run: jest.fn().mockImplementation(() => Promise.resolve())
|
|
||||||
}
|
}
|
||||||
commands.dev.mockImplementationOnce(() => Promise.resolve({ default: defaultExport }))
|
getCommand.mockImplementationOnce(() => Promise.resolve(mockedCommand))
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
|
expect(mockedCommand.run).toHaveBeenCalled()
|
||||||
expect(defaultExport.run).toHaveBeenCalled()
|
|
||||||
process.argv = argv
|
|
||||||
})
|
|
||||||
|
|
||||||
test('unknown calls default method', async () => {
|
|
||||||
const argv = process.argv
|
|
||||||
process.argv = ['', '', 'test']
|
|
||||||
commands.dev.mockImplementationOnce(() => Promise.resolve())
|
|
||||||
|
|
||||||
await run()
|
|
||||||
|
|
||||||
expect(commands.dev).toHaveBeenCalled()
|
|
||||||
process.argv = argv
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('sets NODE_ENV=development for dev', async () => {
|
test('sets NODE_ENV=development for dev', async () => {
|
||||||
const nodeEnv = process.env.NODE_ENV
|
const nodeEnv = process.env.NODE_ENV
|
||||||
process.env.NODE_ENV = ''
|
process.env.NODE_ENV = ''
|
||||||
commands.dev.mockImplementationOnce(() => Promise.resolve())
|
|
||||||
|
|
||||||
await run()
|
getCommand.mockImplementationOnce(() => Promise.resolve({}))
|
||||||
|
|
||||||
|
await run(['dev'])
|
||||||
expect(process.env.NODE_ENV).toBe('development')
|
expect(process.env.NODE_ENV).toBe('development')
|
||||||
process.env.NODE_ENV = nodeEnv
|
process.env.NODE_ENV = nodeEnv
|
||||||
})
|
})
|
||||||
|
|
||||||
test('sets NODE_ENV=production for build', async () => {
|
test('sets NODE_ENV=production for build', async () => {
|
||||||
const argv = process.argv
|
|
||||||
const nodeEnv = process.env.NODE_ENV
|
const nodeEnv = process.env.NODE_ENV
|
||||||
process.argv = ['', '', 'build']
|
|
||||||
process.env.NODE_ENV = ''
|
process.env.NODE_ENV = ''
|
||||||
commands.build.mockImplementationOnce(() => Promise.resolve())
|
|
||||||
|
|
||||||
await run()
|
getCommand.mockImplementationOnce(() => Promise.resolve({}))
|
||||||
|
|
||||||
|
await run(['', '', 'build'])
|
||||||
expect(process.env.NODE_ENV).toBe('production')
|
expect(process.env.NODE_ENV).toBe('production')
|
||||||
process.argv = argv
|
|
||||||
process.env.NODE_ENV = nodeEnv
|
process.env.NODE_ENV = nodeEnv
|
||||||
})
|
})
|
||||||
|
|
||||||
test('catches fatal error', async () => {
|
|
||||||
commands.dev.mockImplementationOnce(() => Promise.reject(new Error('Command Error')))
|
|
||||||
|
|
||||||
await run()
|
|
||||||
|
|
||||||
expect(consola.fatal).toHaveBeenCalledWith(new Error('Command Error'))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -25,50 +25,38 @@ describe('cli/command', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('parses args', () => {
|
test('parses args', () => {
|
||||||
const cmd = new Command({ options: { ...common, ...server } })
|
const argv = ['-c', 'test-file', '-s', '-p', '3001']
|
||||||
|
const cmd = new Command({ options: { ...common, ...server } }, argv)
|
||||||
|
|
||||||
let args = ['-c', 'test-file', '-s', '-p', '3001']
|
expect(cmd.argv['config-file']).toBe(argv[1])
|
||||||
let argv = cmd.getArgv(args)
|
expect(cmd.argv.spa).toBe(true)
|
||||||
|
expect(cmd.argv.universal).toBe(false)
|
||||||
|
expect(cmd.argv.port).toBe('3001')
|
||||||
|
|
||||||
expect(argv['config-file']).toBe(args[1])
|
const cmd2 = new Command({ options: { ...common, ...server } }, ['--no-build'])
|
||||||
expect(argv.spa).toBe(true)
|
expect(cmd2.argv.build).toBe(false)
|
||||||
expect(argv.universal).toBe(false)
|
|
||||||
expect(argv.port).toBe('3001')
|
|
||||||
|
|
||||||
args = ['--no-build']
|
|
||||||
argv = cmd.getArgv(args)
|
|
||||||
|
|
||||||
expect(argv.build).toBe(false)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('prints version automatically', () => {
|
test('prints version automatically', async () => {
|
||||||
const cmd = new Command()
|
const cmd = new Command({}, ['--version'])
|
||||||
cmd.showVersion = jest.fn()
|
cmd.showVersion = jest.fn()
|
||||||
|
await cmd.run()
|
||||||
const args = ['--version']
|
|
||||||
cmd.getArgv(args)
|
|
||||||
|
|
||||||
expect(cmd.showVersion).toHaveBeenCalledTimes(1)
|
expect(cmd.showVersion).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('prints help automatically', () => {
|
test('prints help automatically', async () => {
|
||||||
const cmd = new Command({ options: allOptions })
|
const cmd = new Command({ options: allOptions }, ['-h'])
|
||||||
cmd.showHelp = jest.fn()
|
cmd.showHelp = jest.fn()
|
||||||
|
await cmd.run()
|
||||||
const args = ['-h']
|
|
||||||
cmd.getArgv(args)
|
|
||||||
|
|
||||||
expect(cmd.showHelp).toHaveBeenCalledTimes(1)
|
expect(cmd.showHelp).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('returns nuxt config', async () => {
|
test('returns nuxt config', async () => {
|
||||||
const cmd = new Command({ options: allOptions })
|
const cmd = new Command({ options: allOptions }, ['-c', 'test-file', '-a', '-p', '3001', '-q', '-H'])
|
||||||
|
|
||||||
const args = ['-c', 'test-file', '-a', '-p', '3001', '-q', '-H']
|
const options = await cmd.getNuxtConfig({ testOption: true })
|
||||||
const argv = cmd.getArgv(args)
|
|
||||||
argv._ = ['.']
|
|
||||||
|
|
||||||
const options = await cmd.getNuxtConfig(argv, { testOption: true })
|
|
||||||
|
|
||||||
expect(options.testOption).toBe(true)
|
expect(options.testOption).toBe(true)
|
||||||
expect(options.server.port).toBe(3001)
|
expect(options.server.port).toBe(3001)
|
||||||
@ -117,36 +105,19 @@ describe('cli/command', () => {
|
|||||||
expect(cmd._getHelp()).toMatchSnapshot()
|
expect(cmd._getHelp()).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('loads command from name', async () => {
|
|
||||||
const cmd = await Command.load('dev')
|
|
||||||
expect(cmd._getHelp()).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('show version prints to stdout and exits', () => {
|
test('show version prints to stdout and exits', () => {
|
||||||
jest.spyOn(process.stdout, 'write').mockImplementation(() => {})
|
jest.spyOn(process.stdout, 'write').mockImplementation(() => {})
|
||||||
jest.spyOn(process, 'exit').mockImplementationOnce(code => code)
|
|
||||||
|
|
||||||
const cmd = new Command()
|
const cmd = new Command()
|
||||||
cmd.showVersion()
|
cmd.showVersion()
|
||||||
|
|
||||||
expect(process.stdout.write).toHaveBeenCalled()
|
expect(process.stdout.write).toHaveBeenCalled()
|
||||||
expect(process.exit).toHaveBeenCalled()
|
|
||||||
|
|
||||||
process.stdout.write.mockRestore()
|
process.stdout.write.mockRestore()
|
||||||
process.exit.mockRestore()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('show help prints to stdout and exits', () => {
|
test('show help prints to stdout and exits', () => {
|
||||||
jest.spyOn(process.stdout, 'write').mockImplementation(() => {})
|
jest.spyOn(process.stdout, 'write').mockImplementation(() => {})
|
||||||
jest.spyOn(process, 'exit').mockImplementationOnce(code => code)
|
|
||||||
|
|
||||||
const cmd = new Command()
|
const cmd = new Command()
|
||||||
cmd.showHelp()
|
cmd.showHelp()
|
||||||
|
|
||||||
expect(process.stdout.write).toHaveBeenCalled()
|
expect(process.stdout.write).toHaveBeenCalled()
|
||||||
expect(process.exit).toHaveBeenCalled()
|
|
||||||
|
|
||||||
process.stdout.write.mockRestore()
|
process.stdout.write.mockRestore()
|
||||||
process.exit.mockRestore()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { consola, mockGetNuxt, mockGetGenerator, NuxtCommand } from '../utils'
|
import { mockGetNuxt, mockGetGenerator, NuxtCommand } from '../utils'
|
||||||
import Command from '../../src/command'
|
|
||||||
|
|
||||||
describe('generate', () => {
|
describe('generate', () => {
|
||||||
let generate
|
let generate
|
||||||
@ -9,7 +8,6 @@ describe('generate', () => {
|
|||||||
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
jest.spyOn(process, 'exit').mockImplementation(code => code)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => process.exit.mockRestore())
|
|
||||||
afterEach(() => jest.resetAllMocks())
|
afterEach(() => jest.resetAllMocks())
|
||||||
|
|
||||||
test('has run function', () => {
|
test('has run function', () => {
|
||||||
@ -28,34 +26,21 @@ describe('generate', () => {
|
|||||||
|
|
||||||
test('doesnt build with no-build', async () => {
|
test('doesnt build with no-build', async () => {
|
||||||
mockGetNuxt()
|
mockGetNuxt()
|
||||||
const getArgv = Command.prototype.getArgv
|
|
||||||
Command.prototype.getArgv = jest.fn().mockImplementationOnce(() => {
|
|
||||||
return {
|
|
||||||
'_': ['.'],
|
|
||||||
rootDir: '.',
|
|
||||||
'config-file': 'nuxt.config.js',
|
|
||||||
build: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const generator = mockGetGenerator(Promise.resolve())
|
const generator = mockGetGenerator(Promise.resolve())
|
||||||
|
|
||||||
await NuxtCommand.from(generate).run()
|
await NuxtCommand.run(generate, ['generate', '.', '--no-build'])
|
||||||
|
|
||||||
expect(generator).toHaveBeenCalled()
|
expect(generator).toHaveBeenCalled()
|
||||||
expect(generator.mock.calls[0][0].build).toBe(false)
|
expect(generator.mock.calls[0][0].build).toBe(false)
|
||||||
Command.prototype.getArgv = getArgv
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('build with devtools', async () => {
|
test('build with devtools', async () => {
|
||||||
mockGetNuxt()
|
mockGetNuxt()
|
||||||
const generator = mockGetGenerator(Promise.resolve())
|
const generator = mockGetGenerator(Promise.resolve())
|
||||||
|
|
||||||
const cmd = NuxtCommand.from(generate)
|
const cmd = NuxtCommand.from(generate, ['generate', '.', '--devtools'])
|
||||||
const args = ['generate', '.', '--devtools']
|
|
||||||
const argv = cmd.getArgv(args)
|
|
||||||
argv._ = ['.']
|
|
||||||
|
|
||||||
const options = await cmd.getNuxtConfig(argv)
|
const options = await cmd.getNuxtConfig()
|
||||||
|
|
||||||
await cmd.run()
|
await cmd.run()
|
||||||
|
|
||||||
@ -68,22 +53,12 @@ describe('generate', () => {
|
|||||||
mockGetNuxt()
|
mockGetNuxt()
|
||||||
mockGetGenerator(Promise.resolve())
|
mockGetGenerator(Promise.resolve())
|
||||||
|
|
||||||
const cmd = NuxtCommand.from(generate)
|
const cmd = NuxtCommand.from(generate, ['generate', '.', '--m'])
|
||||||
const args = ['generate', '.', '--m']
|
|
||||||
|
|
||||||
const options = await cmd.getNuxtConfig(cmd.getArgv(args))
|
const options = await cmd.getNuxtConfig()
|
||||||
|
|
||||||
await cmd.run()
|
await cmd.run()
|
||||||
|
|
||||||
expect(options.modern).toBe('client')
|
expect(options.modern).toBe('client')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('catches error', async () => {
|
|
||||||
mockGetNuxt()
|
|
||||||
mockGetGenerator(Promise.reject(new Error('Generator Error')))
|
|
||||||
|
|
||||||
await NuxtCommand.from(generate).run()
|
|
||||||
|
|
||||||
expect(consola.fatal).toHaveBeenCalledWith(new Error('Generator Error'))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
65
packages/cli/test/unit/run.test.js
Normal file
65
packages/cli/test/unit/run.test.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import execa from 'execa'
|
||||||
|
import run from '../../src/run'
|
||||||
|
import getCommand from '../../src/commands'
|
||||||
|
import NuxtCommand from '../../src/command'
|
||||||
|
|
||||||
|
jest.mock('execa')
|
||||||
|
jest.mock('../../src/commands')
|
||||||
|
jest.mock('../../src/command')
|
||||||
|
|
||||||
|
describe('run', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetAllMocks()
|
||||||
|
getCommand.mockImplementation(cmd => cmd === 'dev' ? ({ name: 'dev', run: jest.fn() }) : undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nuxt aliases to nuxt dev', async () => {
|
||||||
|
await run([])
|
||||||
|
expect(getCommand).toHaveBeenCalledWith('dev')
|
||||||
|
expect(NuxtCommand.run).toHaveBeenCalledWith(expect.anything(), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nuxt --foo aliases to nuxt dev --foo', async () => {
|
||||||
|
await run(['--foo'])
|
||||||
|
expect(getCommand).toHaveBeenCalledWith('dev')
|
||||||
|
expect(NuxtCommand.run).toHaveBeenCalledWith(expect.anything(), ['--foo'])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nuxt <dir> aliases to nuxt dev <dir>', async () => {
|
||||||
|
await run([__dirname])
|
||||||
|
expect(getCommand).toHaveBeenCalledWith('dev')
|
||||||
|
expect(NuxtCommand.run).toHaveBeenCalledWith(expect.anything(), [__dirname])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('external commands', async () => {
|
||||||
|
await run(['custom', 'command', '--args'])
|
||||||
|
|
||||||
|
expect(execa).toHaveBeenCalledWith('nuxt-custom', ['command', '--args'], {
|
||||||
|
stdout: process.stdout,
|
||||||
|
stderr: process.stderr,
|
||||||
|
stdin: process.stdin
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('throws error if external command not found', async () => {
|
||||||
|
execa.mockImplementationOnce(() => {
|
||||||
|
const e = new Error()
|
||||||
|
e.code = 'ENOENT'
|
||||||
|
throw e
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(run(['custom', 'command', '--args']))
|
||||||
|
.rejects.toBe('Command not found: nuxt-custom')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('throws error if external command failed', async () => {
|
||||||
|
execa.mockImplementationOnce(() => { throw new Error('boo') })
|
||||||
|
|
||||||
|
await expect(run(['custom', 'command', '--args']))
|
||||||
|
.rejects.toBe('Failed to run command `nuxt-custom`:\nError: boo')
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user