Skip to content

Commit ec22f4d

Browse files
authored
Merge pull request #237 from ember-fastboot/better-error-message
Better `ember fastboot` error message
2 parents 32d40b2 + 1ed9c2f commit ec22f4d

1 file changed

Lines changed: 55 additions & 2 deletions

File tree

lib/tasks/fastboot-server.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ module.exports = CoreObject.extend({
9797
this.restartPromise = this.stop()
9898
.then(() => this.clearRequireCache(options.outputPath))
9999
.then(() => this.start(options))
100-
.catch(e => this.ui.writeLine(e))
100+
.catch(e => this.printError(e))
101101
.finally(() => {
102102
this.restartPromise = null;
103103
if (this.restartAgain) {
104-
debug('restart again')
104+
debug('restart again');
105105
this.restartAgain = false;
106106
this.restart(options);
107107
}
@@ -120,5 +120,58 @@ module.exports = CoreObject.extend({
120120
delete require.cache[key];
121121
}
122122
});
123+
},
124+
125+
/*
126+
* Try to show a useful error message if we're not able to start the user's
127+
* app in FastBoot.
128+
*/
129+
printError: function(e) {
130+
var preamble = ["There was an error trying to run your application in FastBoot.\n",
131+
"This is usually caused by either your application code or an addon trying to access " +
132+
"an API that isn't available in Node.js."];
133+
134+
// If there's a stack trace available, try to extract some information for
135+
// it so we can generate a more helpful error message.
136+
if (e.stack) {
137+
// Look at the stack trace line by line
138+
var stack = e.stack.split('\n');
139+
140+
// Verify there's a second line with path information.
141+
// (First line is the error message itself.)
142+
if (stack[1]) {
143+
// Extract path and line number information. An example line looks like either:
144+
// at /Users/monegraph/Code/fastboot-test/dist/fastboot/vendor.js:65045:19
145+
// or
146+
// at Module.callback (/Users/monegraph/Code/fastboot test/dist/fastboot/fastboot-test.js:23:31)
147+
var match = stack[1].match(/\s*(?:at .* \(([^:]+):(\d+):(\d+)|at ([^:]+):(\d+):(\d+)$)/);
148+
if (match) {
149+
var fileName = match[1] || match[4];
150+
var lineNumber = match[2] || match[5];
151+
152+
// Print file name and line number from the top of the stack. This is displayed
153+
// anyway, of course, but not everyone knows how to read a stack trace. This makes
154+
// it more obvious.
155+
var badFilePath = path.relative(process.cwd(), fileName);
156+
preamble.push("Based on the stack trace, it looks like the exception was generated in " + badFilePath + " on line " + lineNumber + ".");
157+
158+
// If the exception is coming from `vendor.js`, that usually means it's from an addon and thus may be
159+
// out of the user's control. Give the user some instructions so they can try to figure out which
160+
// addon is causing the problem.
161+
if (fileName.substr(-9) === 'vendor.js') {
162+
preamble.push("Because it's coming from vendor.js, an addon is most likely responsible for this error. You should look at this " +
163+
"file and line number to determine which addon is not yet FastBoot compatible.");
164+
165+
} else {
166+
preamble.push("The exception is probably coming from your app. Look at this file and line number to determine what is triggering the exception.");
167+
}
168+
}
169+
}
170+
171+
preamble.push("\nThe full stack trace is:");
172+
}
173+
174+
this.ui.writeError(preamble.join('\n') + '\n');
175+
this.ui.writeError(e);
123176
}
124177
});

0 commit comments

Comments
 (0)