Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detect unfulfilled async hook actions and report error on exit (#4320)
* Better user experience with buggy plugins that previously caused rollup to exit abruptly without any output, error or warning, and a zero process exit code incorrectly indicating success. Co-authored-by: Lukas Taegert-Atkinson <lukastaegert@users.noreply.github.com>
- Loading branch information
1 parent
2fea0d7
commit 0ceee1d
Showing
13 changed files
with
143 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function addUnresolvedAction(_actionTuple: [string, string, Parameters<any>]): void {} | ||
|
||
export function resolveAction(_actionTuple: [string, string, Parameters<any>]): void {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
const unfulfilledActions: Set<[string, string, Parameters<any>]> = new Set(); | ||
|
||
export function addUnresolvedAction(actionTuple: [string, string, Parameters<any>]): void { | ||
unfulfilledActions.add(actionTuple); | ||
} | ||
|
||
export function resolveAction(actionTuple: [string, string, Parameters<any>]): void { | ||
unfulfilledActions.delete(actionTuple); | ||
} | ||
|
||
function formatAction([pluginName, hookName, args]: [string, string, Parameters<any>]): string { | ||
let action = `(${pluginName}) ${hookName}`; | ||
const s = JSON.stringify; | ||
switch (hookName) { | ||
case 'resolveId': | ||
action += ` ${s(args[0])} ${s(args[1])}`; | ||
break; | ||
case 'load': | ||
action += ` ${s(args[0])}`; | ||
break; | ||
case 'transform': | ||
action += ` ${s(args[1])}`; | ||
break; | ||
} | ||
return action; | ||
} | ||
|
||
process.on('exit', () => { | ||
if (unfulfilledActions.size) { | ||
let err = '[!] Error: unfinished hook action(s) on exit:\n'; | ||
for (const action of unfulfilledActions) { | ||
err += formatAction(action) + '\n'; | ||
} | ||
console.error('%s', err); | ||
process.exit(1); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const assert = require('assert'); | ||
const { assertIncludes } = require('../../../utils.js'); | ||
|
||
module.exports = { | ||
description: 'show errors with non-zero exit code for unfulfilled async plugin actions on exit', | ||
command: 'rollup main.js -p ./buggy-plugin.js --silent', | ||
after(err) { | ||
// exit code check has to be here as error(err) is only called upon failure | ||
assert.strictEqual(err && err.code, 1); | ||
}, | ||
error(err) { | ||
// do not abort test upon error | ||
return true; | ||
}, | ||
stderr(stderr) { | ||
assertIncludes(stderr, '[!] Error: unfinished hook action(s) on exit'); | ||
|
||
// these unfulfilled async hook actions may occur in random order | ||
assertIncludes(stderr, '(buggy-plugin) resolveId "./c.js" "main.js"'); | ||
assertIncludes(stderr, '(buggy-plugin) load "./b.js"'); | ||
assertIncludes(stderr, '(buggy-plugin) transform "./a.js"'); | ||
assertIncludes(stderr, '(buggy-plugin) moduleParsed'); | ||
} | ||
}; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('a'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('b'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
var path = require('path'); | ||
|
||
function relative(id) { | ||
if (id[0] != '/') return id; | ||
if (id[0] != '\\') return id; | ||
return './' + path.relative(process.cwd(), id); | ||
} | ||
|
||
module.exports = function() { | ||
return { | ||
name: 'buggy-plugin', | ||
resolveId(id) { | ||
if (id.includes('\0')) return; | ||
|
||
// this action will never resolve or reject | ||
if (id.endsWith('c.js')) return new Promise(() => {}); | ||
|
||
return relative(id); | ||
}, | ||
load(id) { | ||
// this action will never resolve or reject | ||
if (id.endsWith('b.js')) return new Promise(() => {}); | ||
}, | ||
transform(code, id) { | ||
// this action will never resolve or reject | ||
if (id.endsWith('a.js')) return new Promise(() => {}); | ||
}, | ||
moduleParsed(mod) { | ||
// this action will never resolve or reject | ||
if (mod.id.endsWith('d.js')) return new Promise(() => {}); | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('c'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('d'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import './a.js'; | ||
import './b.js'; | ||
import './c.js'; | ||
import './d.js'; | ||
console.log('main'); |