@@ -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 * (?: a t .* \( ( [ ^ : ] + ) : ( \d + ) : ( \d + ) | a t ( [ ^ : ] + ) : ( \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