Skip to content

Commit 4b82aa9

Browse files
pimlieclarkdo
authored andcommitted
fix: dont force exit when it was explicitly disabled (#4973)
* fix: remove slash from warning text * fix: dont force-exit when explicitly disabled chore: add tests for force-exit behaviour * feat: default option value can be fn
1 parent 3d2deac commit 4b82aa9

File tree

10 files changed

+173
-34
lines changed

10 files changed

+173
-34
lines changed

packages/cli/src/command.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ export default class NuxtCommand {
1313
}
1414
this.cmd = cmd
1515

16-
// If the cmd is a server then dont forcibly exit when the cmd has finished
17-
this.isServer = cmd.isServer !== undefined ? cmd.isServer : Boolean(this.cmd.options.hostname)
18-
1916
this._argv = Array.from(argv)
2017
this._parsedArgv = null // Lazy evaluate
2118
}
@@ -48,9 +45,9 @@ export default class NuxtCommand {
4845

4946
const runResolve = Promise.resolve(this.cmd.run(this))
5047

51-
// TODO: For v3 set timeout to 0 when force-exit === true
52-
if (!this.isServer || this.argv['force-exit']) {
53-
runResolve.then(() => forceExit(this.cmd.name, forceExitTimeout))
48+
if (this.argv['force-exit']) {
49+
const forceExitByUser = this.isUserSuppliedArg('force-exit')
50+
runResolve.then(() => forceExit(this.cmd.name, forceExitByUser ? false : forceExitTimeout))
5451
}
5552

5653
return runResolve
@@ -102,6 +99,14 @@ export default class NuxtCommand {
10299
return new Generator(nuxt, builder)
103100
}
104101

102+
isUserSuppliedArg(option) {
103+
return this._argv.includes(`--${option}`) || this._argv.includes(`--no-${option}`)
104+
}
105+
106+
_getDefaultOptionValue(option) {
107+
return typeof option.default === 'function' ? option.default(this.cmd) : option.default
108+
}
109+
105110
_getMinimistOptions() {
106111
const minimistOptions = {
107112
alias: {},
@@ -120,7 +125,7 @@ export default class NuxtCommand {
120125
minimistOptions[option.type].push(option.alias || name)
121126
}
122127
if (option.default) {
123-
minimistOptions.default[option.alias || name] = option.default
128+
minimistOptions.default[option.alias || name] = this._getDefaultOptionValue(option)
124129
}
125130
}
126131

@@ -135,7 +140,7 @@ export default class NuxtCommand {
135140
const option = this.cmd.options[name]
136141

137142
let optionHelp = '--'
138-
optionHelp += option.type === 'boolean' && option.default ? 'no-' : ''
143+
optionHelp += option.type === 'boolean' && this._getDefaultOptionValue(option) ? 'no-' : ''
139144
optionHelp += name
140145
if (option.alias) {
141146
optionHelp += `, -${option.alias}`

packages/cli/src/options/common.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ export default {
2828
}
2929
}
3030
},
31-
// TODO: Change this to default: false in Nuxt v3 (see related todo's)
3231
'force-exit': {
3332
type: 'boolean',
34-
default: true,
35-
description: 'Do not force Nuxt.js to exit after the command has finished (this option has no effect on commands which start a server)'
33+
default(cmd) {
34+
return ['build', 'generate'].includes(cmd.name)
35+
},
36+
description: 'Whether Nuxt.js should force exit after the command has finished'
3637
},
3738
version: {
3839
alias: 'v',

packages/cli/src/utils/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,10 @@ export function normalizeArg(arg, defaultValue) {
140140
}
141141

142142
export function forceExit(cmdName, timeout) {
143-
if (timeout) {
143+
if (timeout !== false) {
144144
const exitTimeout = setTimeout(() => {
145145
const msg = `The command 'nuxt ${cmdName}' finished but did not exit after ${timeout}s
146-
This is most likely not caused by a bug in Nuxt.js\
146+
This is most likely not caused by a bug in Nuxt.js
147147
Make sure to cleanup all timers and listeners you or your plugins/modules start.
148148
Nuxt.js will now force exit
149149

packages/cli/test/unit/__snapshots__/command.test.js.snap

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,36 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`cli/command builds help text 1`] = `
4-
" Usage: nuxt this is how you do it
4+
" Usage: nuxt this is how you do it
55
[options]
66
7-
a very long description that should wrap
8-
to the next line because is not longer
7+
a very long description that should wrap
8+
to the next line because is not longer
99
than the terminal width
1010
1111
Options:
1212
1313
--spa, -s Launch in SPA mode
14-
--universal, -u Launch in Universal
14+
--universal, -u Launch in Universal
1515
mode (default)
16-
--config-file, -c Path to Nuxt.js
16+
--config-file, -c Path to Nuxt.js
1717
config file (default: nuxt.config.js)
18-
--modern, -m Build/Start app for
19-
modern browsers, e.g. server, client and
18+
--modern, -m Build/Start app for
19+
modern browsers, e.g. server, client and
2020
false
21-
--no-force-exit Do not force Nuxt.js
22-
to exit after the command has finished
23-
(this option has no effect on commands
24-
which start a server)
25-
--version, -v Display the Nuxt
21+
--force-exit Whether Nuxt.js
22+
should force exit after the command has
23+
finished
24+
--version, -v Display the Nuxt
2625
version
2726
--help, -h Display this message
28-
--port, -p Port number on which
27+
--port, -p Port number on which
2928
to start the application
30-
--hostname, -H Hostname on which to
29+
--hostname, -H Hostname on which to
3130
start the application
3231
--unix-socket, -n Path to a UNIX socket
33-
--foo very long option that
34-
is longer than the terminal width and
32+
--foo very long option that
33+
is longer than the terminal width and
3534
should wrap to the next line
3635
3736
"

packages/cli/test/unit/build.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,36 @@ describe('build', () => {
7474

7575
expect(options.modern).toBe(true)
7676
})
77+
78+
test('build force-exits by default', async () => {
79+
mockGetNuxt()
80+
mockGetBuilder(Promise.resolve())
81+
82+
const cmd = NuxtCommand.from(build, ['build', '.'])
83+
await cmd.run()
84+
85+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
86+
expect(utils.forceExit).toHaveBeenCalledWith('build', 5)
87+
})
88+
89+
test('build can set force exit explicitly', async () => {
90+
mockGetNuxt()
91+
mockGetBuilder(Promise.resolve())
92+
93+
const cmd = NuxtCommand.from(build, ['build', '.', '--force-exit'])
94+
await cmd.run()
95+
96+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
97+
expect(utils.forceExit).toHaveBeenCalledWith('build', false)
98+
})
99+
100+
test('build can disable force exit explicitly', async () => {
101+
mockGetNuxt()
102+
mockGetBuilder(Promise.resolve())
103+
104+
const cmd = NuxtCommand.from(build, ['build', '.', '--no-force-exit'])
105+
await cmd.run()
106+
107+
expect(utils.forceExit).not.toHaveBeenCalled()
108+
})
77109
})

packages/cli/test/unit/cli.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ jest.mock('../../src/commands')
66

77
describe('cli', () => {
88
beforeAll(() => {
9-
// TODO: Below spyOn can be removed in v3 when force-exit is default false
109
jest.spyOn(utils, 'forceExit').mockImplementation(() => {})
1110
})
1211

@@ -20,6 +19,7 @@ describe('cli', () => {
2019

2120
await run()
2221
expect(mockedCommand.run).toHaveBeenCalled()
22+
expect(utils.forceExit).not.toHaveBeenCalled()
2323
})
2424

2525
test('sets NODE_ENV=development for dev', async () => {

packages/cli/test/unit/dev.test.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ describe('dev', () => {
66

77
beforeAll(async () => {
88
dev = await import('../../src/commands/dev').then(m => m.default)
9-
// TODO: Below spyOn can be removed in v3 when force-exit is default false
109
jest.spyOn(utils, 'forceExit').mockImplementation(() => {})
1110
})
1211

@@ -107,4 +106,35 @@ describe('dev', () => {
107106

108107
expect(consola.error).toHaveBeenCalledWith(new Error('Listen Error'))
109108
})
109+
110+
test('dev doesnt force-exit by default', async () => {
111+
mockNuxt()
112+
mockBuilder()
113+
114+
const cmd = NuxtCommand.from(dev, ['dev', '.'])
115+
await cmd.run()
116+
117+
expect(utils.forceExit).not.toHaveBeenCalled()
118+
})
119+
120+
test('dev can set force exit explicitly', async () => {
121+
mockNuxt()
122+
mockBuilder()
123+
124+
const cmd = NuxtCommand.from(dev, ['dev', '.', '--force-exit'])
125+
await cmd.run()
126+
127+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
128+
expect(utils.forceExit).toHaveBeenCalledWith('dev', false)
129+
})
130+
131+
test('dev can disable force exit explicitly', async () => {
132+
mockNuxt()
133+
mockBuilder()
134+
135+
const cmd = NuxtCommand.from(dev, ['dev', '.', '--no-force-exit'])
136+
await cmd.run()
137+
138+
expect(utils.forceExit).not.toHaveBeenCalled()
139+
})
110140
})

packages/cli/test/unit/generate.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,49 @@ describe('generate', () => {
6363

6464
expect(options.modern).toBe('client')
6565
})
66+
67+
test('generate with modern mode', async () => {
68+
mockGetNuxt()
69+
mockGetGenerator(Promise.resolve())
70+
71+
const cmd = NuxtCommand.from(generate, ['generate', '.', '--m'])
72+
73+
const options = await cmd.getNuxtConfig()
74+
75+
await cmd.run()
76+
77+
expect(options.modern).toBe('client')
78+
})
79+
80+
test('generate force-exits by default', async () => {
81+
mockGetNuxt()
82+
mockGetGenerator(Promise.resolve())
83+
84+
const cmd = NuxtCommand.from(generate, ['generate', '.'])
85+
await cmd.run()
86+
87+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
88+
expect(utils.forceExit).toHaveBeenCalledWith('generate', 5)
89+
})
90+
91+
test('generate can set force exit explicitly', async () => {
92+
mockGetNuxt()
93+
mockGetGenerator(Promise.resolve())
94+
95+
const cmd = NuxtCommand.from(generate, ['generate', '.', '--force-exit'])
96+
await cmd.run()
97+
98+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
99+
expect(utils.forceExit).toHaveBeenCalledWith('generate', false)
100+
})
101+
102+
test('generate can disable force exit explicitly', async () => {
103+
mockGetNuxt()
104+
mockGetGenerator(Promise.resolve())
105+
106+
const cmd = NuxtCommand.from(generate, ['generate', '.', '--no-force-exit'])
107+
await cmd.run()
108+
109+
expect(utils.forceExit).not.toHaveBeenCalled()
110+
})
66111
})

packages/cli/test/unit/start.test.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ describe('start', () => {
77

88
beforeAll(async () => {
99
start = await import('../../src/commands/start').then(m => m.default)
10-
// TODO: Below spyOn can be removed in v3 when force-exit is default false
1110
jest.spyOn(utils, 'forceExit').mockImplementation(() => {})
1211
})
1312

@@ -35,4 +34,32 @@ describe('start', () => {
3534
await NuxtCommand.from(start).run()
3635
expect(consola.fatal).not.toHaveBeenCalled()
3736
})
37+
38+
test('start doesnt force-exit by default', async () => {
39+
mockGetNuxtStart()
40+
41+
const cmd = NuxtCommand.from(start, ['start', '.'])
42+
await cmd.run()
43+
44+
expect(utils.forceExit).not.toHaveBeenCalled()
45+
})
46+
47+
test('start can set force exit explicitly', async () => {
48+
mockGetNuxtStart()
49+
50+
const cmd = NuxtCommand.from(start, ['start', '.', '--force-exit'])
51+
await cmd.run()
52+
53+
expect(utils.forceExit).toHaveBeenCalledTimes(1)
54+
expect(utils.forceExit).toHaveBeenCalledWith('start', false)
55+
})
56+
57+
test('start can disable force exit explicitly', async () => {
58+
mockGetNuxtStart()
59+
60+
const cmd = NuxtCommand.from(start, ['start', '.', '--no-force-exit'])
61+
await cmd.run()
62+
63+
expect(utils.forceExit).not.toHaveBeenCalled()
64+
})
3865
})

packages/cli/test/utils/mocking.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ jest.mock('../../src/imports', () => {
1818
}
1919
})
2020

21-
export const mockGetNuxt = (options, implementation) => {
21+
export const mockGetNuxt = (options = {}, implementation) => {
2222
Command.prototype.getNuxt = jest.fn().mockImplementationOnce(() => {
2323
return Object.assign({
2424
hook: jest.fn(),
2525
options
26-
}, implementation || {})
26+
}, implementation)
2727
})
2828
}
2929

0 commit comments

Comments
 (0)