From eb755f07a21ab4cb4b710acd5a861e04a3cc0627 Mon Sep 17 00:00:00 2001 From: Tom Dale Date: Wed, 27 Jul 2016 15:26:11 -0400 Subject: [PATCH 1/2] Better `ember fastboot` error message --- lib/tasks/fastboot-server.js | 50 ++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/tasks/fastboot-server.js b/lib/tasks/fastboot-server.js index 7f5200ab4..4746d83cb 100644 --- a/lib/tasks/fastboot-server.js +++ b/lib/tasks/fastboot-server.js @@ -97,11 +97,11 @@ module.exports = CoreObject.extend({ this.restartPromise = this.stop() .then(() => this.clearRequireCache(options.outputPath)) .then(() => this.start(options)) - .catch(e => this.ui.writeLine(e)) + .catch(e => this.printError(e)) .finally(() => { this.restartPromise = null; if (this.restartAgain) { - debug('restart again') + debug('restart again'); this.restartAgain = false; this.restart(options); } @@ -120,5 +120,51 @@ module.exports = CoreObject.extend({ delete require.cache[key]; } }); + }, + + /* + * Try to show a useful error message if we're not able to start the user's + * app in FastBoot. + */ + printError: function(e) { + var preamble = ["There was an error trying to run your application in FastBoot.\n", + "This is usually caused by either your application code or an addon trying to access " + + "an API that isn't available in Node.js."]; + + // If there's a stack trace available, try to extract some information for + // it so we can generate a more helpful error message. + if (e.stack) { + // Look at the stack trace line by line + var stack = e.stack.split('\n'); + + // Verify there's a second line with path information. + // (First line is the error message itself.) + if (stack[1]) { + // Extract path and line number information. An example line looks like: + // at /Users/monegraph/Code/fastboot-test/dist/fastboot/vendor.js:65045:19 + var match = stack[1].match(/\s*at ([^:]+):(\d+):(\d+)$/); + if (match) { + // Print file name and line number from the top of the stack. This is displayed + // anyway, of course, but not everyone knows how to read a stack trace. This makes + // it more obvious. + var badFilePath = path.relative(process.cwd(), match[1]); + preamble.push("Based on the stack trace, it looks like the exception was generated in " + badFilePath + " on line " + match[2] + "."); + } + + // If the exception is coming from `vendor.js`, that usually means it's from an addon and thus may be + // out of the user's control. Give the user some instructions so they can try to figure out which + // addon is causing the problem. + if (match && match[1].substr(-9) === 'vendor.js') { + preamble.push("Because it's coming from vendor.js, an addon is most likely responsible for this error. You should look at this " + + "file and line number to determine which addon is not yet FastBoot compatible."); + + } + } + + preamble.push("\nThe full stack trace is:"); + } + + this.ui.writeError(preamble.join('\n') + '\n'); + this.ui.writeError(e); } }); From 1ed9c2f41be416c6cddb12ab16a0a15590581c43 Mon Sep 17 00:00:00 2001 From: Tom Dale Date: Wed, 27 Jul 2016 15:53:23 -0400 Subject: [PATCH 2/2] Handle stack trace with function name --- lib/tasks/fastboot-server.js | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/tasks/fastboot-server.js b/lib/tasks/fastboot-server.js index 4746d83cb..702c3dc0a 100644 --- a/lib/tasks/fastboot-server.js +++ b/lib/tasks/fastboot-server.js @@ -140,24 +140,31 @@ module.exports = CoreObject.extend({ // Verify there's a second line with path information. // (First line is the error message itself.) if (stack[1]) { - // Extract path and line number information. An example line looks like: + // Extract path and line number information. An example line looks like either: // at /Users/monegraph/Code/fastboot-test/dist/fastboot/vendor.js:65045:19 - var match = stack[1].match(/\s*at ([^:]+):(\d+):(\d+)$/); + // or + // at Module.callback (/Users/monegraph/Code/fastboot test/dist/fastboot/fastboot-test.js:23:31) + var match = stack[1].match(/\s*(?:at .* \(([^:]+):(\d+):(\d+)|at ([^:]+):(\d+):(\d+)$)/); if (match) { + var fileName = match[1] || match[4]; + var lineNumber = match[2] || match[5]; + // Print file name and line number from the top of the stack. This is displayed // anyway, of course, but not everyone knows how to read a stack trace. This makes // it more obvious. - var badFilePath = path.relative(process.cwd(), match[1]); - preamble.push("Based on the stack trace, it looks like the exception was generated in " + badFilePath + " on line " + match[2] + "."); - } - - // If the exception is coming from `vendor.js`, that usually means it's from an addon and thus may be - // out of the user's control. Give the user some instructions so they can try to figure out which - // addon is causing the problem. - if (match && match[1].substr(-9) === 'vendor.js') { - preamble.push("Because it's coming from vendor.js, an addon is most likely responsible for this error. You should look at this " + - "file and line number to determine which addon is not yet FastBoot compatible."); - + var badFilePath = path.relative(process.cwd(), fileName); + preamble.push("Based on the stack trace, it looks like the exception was generated in " + badFilePath + " on line " + lineNumber + "."); + + // If the exception is coming from `vendor.js`, that usually means it's from an addon and thus may be + // out of the user's control. Give the user some instructions so they can try to figure out which + // addon is causing the problem. + if (fileName.substr(-9) === 'vendor.js') { + preamble.push("Because it's coming from vendor.js, an addon is most likely responsible for this error. You should look at this " + + "file and line number to determine which addon is not yet FastBoot compatible."); + + } else { + preamble.push("The exception is probably coming from your app. Look at this file and line number to determine what is triggering the exception."); + } } }