Skip to content

Commit

Permalink
Also recover from plugin errors during the initial build (#3219)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Nov 9, 2019
1 parent 68fbefc commit 1a63383
Show file tree
Hide file tree
Showing 19 changed files with 99 additions and 23 deletions.
2 changes: 0 additions & 2 deletions src/Module.ts
Expand Up @@ -272,8 +272,6 @@ export default class Module {
props.frame = getCodeFrame(this.originalCode, location.line, location.column);
}

props.watchFiles = Object.keys(this.graph.watchFiles);

error(props);
}

Expand Down
4 changes: 4 additions & 0 deletions src/rollup/index.ts
Expand Up @@ -199,6 +199,10 @@ export default async function rollup(rawInputOptions: GenericConfigObject): Prom
inputOptions.inlineDynamicImports as boolean
);
} catch (err) {
const watchFiles = Object.keys(graph.watchFiles);
if (watchFiles.length > 0) {
err.watchFiles = watchFiles;
}
await graph.pluginDriver.hookParallel('buildEnd', [err]);
throw err;
}
Expand Down
Expand Up @@ -20,6 +20,7 @@ module.exports = {
message:
'setAssetSource cannot be called in transform for caching reasons. Use emitFile with a source, or call setAssetSource in another hook.',
plugin: 'test-plugin',
pluginCode: 'INVALID_SETASSETSOURCE'
pluginCode: 'INVALID_SETASSETSOURCE',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
@@ -1,3 +1,5 @@
const path = require('path');

module.exports = {
description: 'Throws if an emitted entry chunk cannot be resolved',
options: {
Expand All @@ -11,6 +13,7 @@ module.exports = {
},
error: {
code: 'UNRESOLVED_ENTRY',
message: 'Could not resolve entry module (not-found.js).'
message: 'Could not resolve entry module (not-found.js).',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
Expand Up @@ -16,6 +16,7 @@ module.exports = {
message:
'Returning "dependencies" from the "transform" hook as done by plugin at position 1 is deprecated. The "this.addWatchFile" plugin context function should be used instead.',
plugin: 'at position 1',
pluginCode: 'DEPRECATED_FEATURE'
pluginCode: 'DEPRECATED_FEATURE',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
@@ -1,7 +1,10 @@
const path = require('path');

module.exports = {
description: 'throws if a dynamic relative import is not found',
error: {
code: 'UNRESOLVED_IMPORT',
message: `Could not resolve './mod' from main.js`
message: `Could not resolve './mod' from main.js`,
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
5 changes: 4 additions & 1 deletion test/function/samples/emit-file/chunk-not-found/_config.js
@@ -1,3 +1,5 @@
const path = require('path');

module.exports = {
description: 'Throws if an emitted entry chunk cannot be resolved',
options: {
Expand All @@ -10,6 +12,7 @@ module.exports = {
},
error: {
code: 'UNRESOLVED_ENTRY',
message: 'Could not resolve entry module (not-found.js).'
message: 'Could not resolve entry module (not-found.js).',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
Expand Up @@ -19,6 +19,7 @@ module.exports = {
message:
'setAssetSource cannot be called in transform for caching reasons. Use emitFile with a source, or call setAssetSource in another hook.',
plugin: 'test-plugin',
pluginCode: 'INVALID_SETASSETSOURCE'
pluginCode: 'INVALID_SETASSETSOURCE',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
18 changes: 10 additions & 8 deletions test/function/samples/external-conflict/_config.js
@@ -1,22 +1,24 @@
const path = require('path');

module.exports = {
description: 'external paths from custom resolver remain external (#633)',
options: {
external: (_id, parent) => parent === 'dep',
plugins: [
{
resolveId (id, parent) {
if (id === 'dep')
return id;
resolveId(id, parent) {
if (id === 'dep') return id;
},
load (id) {
if (id === 'dep')
return `import 'dep'`;
load(id) {
if (id === 'dep') return `import 'dep'`;
}
}
]
},
error: {
code: "INVALID_EXTERNAL_ID",
message: "'dep' is imported as an external by dep, but is already an existing non-external module id."
code: 'INVALID_EXTERNAL_ID',
message:
"'dep' is imported as an external by dep, but is already an existing non-external module id.",
watchFiles: [path.resolve(__dirname, 'main.js'), 'dep']
}
};
5 changes: 4 additions & 1 deletion test/function/samples/load-returns-string-or-null/_config.js
@@ -1,3 +1,5 @@
const path = require('path');

module.exports = {
description: 'throws error if load returns something wacky',
options: {
Expand All @@ -12,6 +14,7 @@ module.exports = {
},
error: {
code: 'BAD_LOADER',
message: `Error loading main.js: plugin load hook should return a string, a { code, map } object, or nothing/null`
message: `Error loading main.js: plugin load hook should return a string, a { code, map } object, or nothing/null`,
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
5 changes: 4 additions & 1 deletion test/function/samples/manual-chunks-conflict/_config.js
@@ -1,3 +1,5 @@
const path = require('path');

module.exports = {
description: 'Throws for conflicts between manual chunks',
options: {
Expand All @@ -9,6 +11,7 @@ module.exports = {
},
error: {
code: 'INVALID_CHUNK',
message: `Cannot assign dep.js to the "dep2" chunk as it is already in the "dep1" chunk.`
message: `Cannot assign dep.js to the "dep2" chunk as it is already in the "dep1" chunk.`,
watchFiles: [path.resolve(__dirname, 'main.js'), path.resolve(__dirname, 'dep.js')]
}
};
5 changes: 4 additions & 1 deletion test/function/samples/no-relative-external/_config.js
@@ -1,7 +1,10 @@
const path = require('path');

module.exports = {
description: 'missing relative imports are an error, not a warning',
error: {
code: 'UNRESOLVED_IMPORT',
message: `Could not resolve './missing.js' from main.js`
message: `Could not resolve './missing.js' from main.js`,
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
5 changes: 4 additions & 1 deletion test/function/samples/paths-are-case-sensitive/_config.js
@@ -1,7 +1,10 @@
const path = require('path');

module.exports = {
description: 'insists on correct casing for imports',
error: {
code: 'UNRESOLVED_IMPORT',
message: `Could not resolve './foo.js' from main.js`
message: `Could not resolve './foo.js' from main.js`,
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
Expand Up @@ -18,6 +18,7 @@ module.exports = {
message: 'nope',
hook: 'transform',
id: path.resolve(__dirname, 'main.js'),
watchFiles: [path.resolve(__dirname, 'main.js')],
loc: {
file: path.resolve(__dirname, 'main.js'),
line: 1,
Expand Down
Expand Up @@ -23,6 +23,7 @@ module.exports = {
message: `Something happened 1`,
plugin: 'plugin1',
hook: 'transform',
id: path.resolve(__dirname, 'main.js')
id: path.resolve(__dirname, 'main.js'),
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
3 changes: 2 additions & 1 deletion test/function/samples/plugin-error/load/_config.js
Expand Up @@ -16,6 +16,7 @@ module.exports = {
code: 'PLUGIN_ERROR',
plugin: 'test',
message: `Could not load ${path.resolve(__dirname, 'main.js')}: nope`,
hook: 'load'
hook: 'load',
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
1 change: 1 addition & 0 deletions test/function/samples/plugin-error/transform/_config.js
Expand Up @@ -18,6 +18,7 @@ module.exports = {
message: 'nope',
hook: 'transform',
id: path.resolve(__dirname, 'main.js'),
watchFiles: [path.resolve(__dirname, 'main.js')],
pos: 22,
loc: {
file: path.resolve(__dirname, 'main.js'),
Expand Down
5 changes: 4 additions & 1 deletion test/function/samples/throws-not-found-module/_config.js
@@ -1,7 +1,10 @@
const path = require('path');

module.exports = {
description: 'throws error if module is not found',
error: {
code: 'UNRESOLVED_IMPORT',
message: `Could not resolve './mod' from main.js`
message: `Could not resolve './mod' from main.js`,
watchFiles: [path.resolve(__dirname, 'main.js')]
}
};
41 changes: 41 additions & 0 deletions test/watch/index.js
Expand Up @@ -363,6 +363,47 @@ describe('rollup.watch', () => {
});
});

it('recovers from a plugin error on initial build', () => {
let count = 0;
return sander
.copydir('test/watch/samples/basic')
.to('test/_tmp/input')
.then(() => {
const watcher = rollup.watch({
input: 'test/_tmp/input/main.js',
plugins: {
transform() {
if (count++ === 0) {
this.error('The first run failed, try again.');
}
}
},
output: {
file: 'test/_tmp/output/bundle.js',
format: 'cjs'
},
watch: { chokidar }
});

return sequence(watcher, [
'START',
'BUNDLE_START',
'ERROR',
() => {
assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false);
sander.writeFileSync('test/_tmp/input/main.js', 'export default 43;');
},
'START',
'BUNDLE_START',
'BUNDLE_END',
'END',
() => {
assert.strictEqual(run('../_tmp/output/bundle.js'), 43);
}
]);
});
});

it('recovers from an error even when erroring file was "renamed" (#38)', () => {
return sander
.copydir('test/watch/samples/basic')
Expand Down

0 comments on commit 1a63383

Please sign in to comment.