Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show warning on forced exit #4958

Merged
merged 9 commits into from Feb 6, 2019
21 changes: 20 additions & 1 deletion packages/cli/src/command.js
@@ -1,8 +1,10 @@

import minimist from 'minimist'
import env from 'std-env'
import { name, version } from '../package.json'
import { loadNuxtConfig } from './utils'
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
import { indent, foldLines, colorize, warningBox } from './utils/formatting'
import { startSpaces, optionSpaces, forceExitTimeout } from './utils/settings'
import * as imports from './imports'

export default class NuxtCommand {
Expand All @@ -12,6 +14,10 @@ export default class NuxtCommand {
}
this.cmd = cmd

// If the cmd is a server then dont forcibly exit when the cmd is finished
this.isServer = cmd.isServer !== undefined ? cmd.isServer : Boolean(this.cmd.options.hostname)
this.forceExit = !this.isServer && !env.test

this._argv = Array.from(argv)
this._parsedArgv = null // Lazy evaluate
}
Expand Down Expand Up @@ -43,6 +49,19 @@ export default class NuxtCommand {
}

return Promise.resolve(this.cmd.run(this))
.then(() => {
if (this.forceExit) {
pimlie marked this conversation as resolved.
Show resolved Hide resolved
const exitTimeout = setTimeout(() => {
let msg = `The command 'nuxt ${this.cmd.name}' finished but Nuxt.js did not exit after ${forceExitTimeout}s\n`
msg += 'This is most likely not caused by a bug in Nuxt\n'
msg += 'Make sure to cleanup all timers and listeners you or your plugins/modules start.\n'
msg += 'Nuxt.js will now force exit'
process.stderr.write(warningBox(msg))
process.exit(0)
pimlie marked this conversation as resolved.
Show resolved Hide resolved
}, forceExitTimeout * 1000)
exitTimeout.unref()
}
})
}

showVersion() {
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/list.js
@@ -1,5 +1,6 @@
import chalk from 'chalk'
import { indent, foldLines, startSpaces, optionSpaces, colorize } from './utils/formatting'
import { indent, foldLines, colorize } from './utils/formatting'
import { startSpaces, optionSpaces } from './utils/settings'
import getCommand from './commands'

export default async function listCommands() {
Expand Down
14 changes: 2 additions & 12 deletions packages/cli/src/setup.js
@@ -1,6 +1,5 @@
import consola from 'consola'
import chalk from 'chalk'
import boxen from 'boxen'
import { fatalBox } from './utils/formatting'

let _setup = false

Expand All @@ -26,16 +25,7 @@ export default function setup({ dev }) {
consola.addReporter({
log(logObj) {
if (logObj.type === 'fatal') {
process.stderr.write(boxen([
chalk.red('✖ Nuxt Fatal Error'),
'',
chalk.white(String(logObj.args[0]))
].join('\n'), {
borderColor: 'red',
borderStyle: 'round',
padding: 1,
margin: 1
}) + '\n')
process.stderr.write(fatalBox(String(logObj.args[0])))
pimlie marked this conversation as resolved.
Show resolved Hide resolved
process.exit(1)
}
}
Expand Down
41 changes: 33 additions & 8 deletions packages/cli/src/utils/formatting.js
@@ -1,11 +1,7 @@
import wrapAnsi from 'wrap-ansi'
import chalk from 'chalk'

export const startSpaces = 2
export const optionSpaces = 2

// 80% of terminal column width
export const maxCharsPerLine = (process.stdout.columns || 100) * 80 / 100
import boxen from 'boxen'
import { maxCharsPerLine } from './settings'

export function indent(count, chr = ' ') {
return chr.repeat(count)
Expand All @@ -25,8 +21,8 @@ export function indentLines(string, spaces, firstLineSpaces) {
return s
}

export function foldLines(string, spaces, firstLineSpaces, maxCharsPerLine) {
return indentLines(wrapAnsi(string, maxCharsPerLine, { trim: false }), spaces, firstLineSpaces)
export function foldLines(string, spaces, firstLineSpaces, charsPerLine = maxCharsPerLine()) {
return indentLines(wrapAnsi(string, charsPerLine, { trim: false }), spaces, firstLineSpaces)
}

export function colorize(text) {
Expand All @@ -36,3 +32,32 @@ export function colorize(text) {
.replace(/ (-[-\w,]+)/g, m => chalk.bold(m))
.replace(/`(.+)`/g, (_, m) => chalk.bold.cyan(m))
}

export function box(message, title, options) {
pimlie marked this conversation as resolved.
Show resolved Hide resolved
return boxen([
title || chalk.white('Nuxt Message'),
'',
chalk.white(foldLines(message, 0, 0, maxCharsPerLine()))
].join('\n'), Object.assign({
borderColor: 'white',
borderStyle: 'round',
padding: 1,
margin: 1
}, options)) + '\n'
}

export function warningBox(message, title) {
return box(message, title || chalk.yellow('❗ Nuxt Warning'), {
pimlie marked this conversation as resolved.
Show resolved Hide resolved
borderColor: 'yellow'
})
}

export function errorBox(message, title) {
return box(message, title || chalk.red('✖ Nuxt Error'), {
borderColor: 'red'
})
}

export function fatalBox(message, title) {
return errorBox(message, title || chalk.red('✖ Nuxt Fatal Error'))
}
8 changes: 8 additions & 0 deletions packages/cli/src/utils/settings.js
@@ -0,0 +1,8 @@
export const forceExitTimeout = 5
pimlie marked this conversation as resolved.
Show resolved Hide resolved

export const startSpaces = 2
export const optionSpaces = 2

// 80% of terminal column width
// this is a fn because console width can have changed since startup
export const maxCharsPerLine = () => (process.stdout.columns || 100) * 80 / 100
30 changes: 21 additions & 9 deletions packages/cli/test/unit/__snapshots__/command.test.js.snap
@@ -1,22 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`cli/command builds help text 1`] = `
" Usage: nuxt this is how you do it [options]
" Usage: nuxt this is how you do it
[options]

a very long description that should not wrap to the next line because is not longer than the terminal width
a very long description that should wrap
to the next line because is not longer
than the terminal width

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, -v Display the Nuxt version
--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, -v 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
--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 not longer than the terminal width and should not wrap to the next line
--foo very long option that
is longer than the terminal width and
should wrap to the next line

"
`;
9 changes: 6 additions & 3 deletions packages/cli/test/unit/command.test.js
@@ -1,5 +1,6 @@
import Command from '../../src/command'
import { common, server } from '../../src/options'
import * as settings from '../../src/utils/settings'
import { consola } from '../utils'

jest.mock('@nuxt/core')
Expand Down Expand Up @@ -88,16 +89,18 @@ describe('cli/command', () => {
})

test('builds help text', () => {
jest.spyOn(settings, 'maxCharsPerLine').mockReturnValue(40)

const cmd = new Command({
description: 'a very long description that should not wrap to the next line because is not longer ' +
description: 'a very long description that should wrap to the next line because is not longer ' +
'than the terminal width',
usage: 'this is how you do it',
options: {
...allOptions,
foo: {
type: 'boolean',
description: 'very long option that is not longer than the terminal width and ' +
'should not wrap to the next line'
description: 'very long option that is longer than the terminal width and ' +
'should wrap to the next line'
}
}
})
Expand Down