1- const { red, yellow } = require ( 'kleur' ) ;
1+ const { red, gray } = require ( 'kleur' ) ;
22const { resolve } = require ( 'path' ) ;
33const { readFileSync } = require ( 'fs' ) ;
44const stackTrace = require ( 'stack-trace' ) ;
55const { SourceMapConsumer } = require ( 'source-map' ) ;
6+ const { error, info } = require ( '../../util' ) ;
67
78module . exports = function ( env , params ) {
89 params = params || { } ;
@@ -14,8 +15,8 @@ module.exports = function(env, params) {
1415 global . location = { href : url , pathname : url } ;
1516
1617 try {
17- let m = require ( entry ) ,
18- app = ( m && m . default ) || m ;
18+ const m = require ( entry ) ;
19+ const app = ( m && m . default ) || m ;
1920
2021 if ( typeof app !== 'function' ) {
2122 // eslint-disable-next-line no-console
@@ -33,91 +34,139 @@ module.exports = function(env, params) {
3334
3435 return renderToString ( preact . h ( app , { ...params , url } ) ) ;
3536 } catch ( err ) {
36- let stack = stackTrace . parse ( err ) . filter ( s => s . getFileName ( ) === entry ) [ 0 ] ;
37+ const stack = stackTrace
38+ . parse ( err )
39+ . filter ( s => s . getFileName ( ) . includes ( 'ssr-build' ) ) [ 0 ] ;
3740 if ( ! stack ) {
38- throw err ;
41+ error ( err ) ;
42+ return '' ;
3943 }
4044
4145 handlePrerenderError ( err , env , stack , entry ) ;
46+ return '' ;
4247 }
4348} ;
4449
4550async function handlePrerenderError ( err , env , stack , entry ) {
46- let errorMessage = err . toString ( ) ;
47- let isReferenceError = errorMessage . startsWith ( 'ReferenceError' ) ;
48- let methodName = stack . getMethodName ( ) ;
49- let sourceMapContent , position , sourcePath , sourceLines , sourceCodeHighlight ;
50-
51- try {
52- sourceMapContent = JSON . parse ( readFileSync ( `${ entry } .map` ) ) ;
53- } catch ( err ) {
54- process . stderr . write ( red ( `Unable to read sourcemap: ${ entry } .map\n` ) ) ;
55- }
51+ const errorMessage = err . toString ( ) ;
52+ const isReferenceError = errorMessage . startsWith ( 'ReferenceError' ) ;
53+ const methodName = stack . getMethodName ( ) ;
54+ const fileName = stack . getFileName ( ) . replace ( / \\ / g, '/' ) ;
55+ let sourceCodeHighlight = '' ;
56+
57+ let position ;
58+
59+ info ( fileName ) ;
60+ if ( / w e b p a c k : / . test ( fileName ) ) {
61+ position = {
62+ source : fileName . replace ( / .+ w e b p a c k : / , 'webpack://' ) ,
63+ line : stack . getLineNumber ( ) ,
64+ column : stack . getColumnNumber ( ) ,
65+ } ;
66+ } else {
67+ try {
68+ const sourceMapContent = JSON . parse ( readFileSync ( `${ entry } .map` ) ) ;
5669
57- if ( sourceMapContent ) {
58- await SourceMapConsumer . with ( sourceMapContent , null , consumer => {
59- position = consumer . originalPositionFor ( {
60- line : stack . getLineNumber ( ) ,
61- column : stack . getColumnNumber ( ) ,
70+ await SourceMapConsumer . with ( sourceMapContent , null , consumer => {
71+ position = consumer . originalPositionFor ( {
72+ line : stack . getLineNumber ( ) ,
73+ column : stack . getColumnNumber ( ) ,
74+ } ) ;
6275 } ) ;
63- } ) ;
76+ } catch ( err ) {
77+ error ( `Unable to read sourcemap: ${ entry } .map` ) ;
78+ return ;
79+ }
80+ }
6481
82+ if ( position ) {
83+ info ( position . source ) ;
6584 position . source = position . source
6685 . replace ( 'webpack://' , '.' )
6786 . replace ( / ^ .* ~ \/ ( (?: @ [ ^ / ] + \/ ) ? [ ^ / ] + ) / , ( s , name ) =>
6887 require
6988 . resolve ( name )
7089 . replace ( / ^ ( .* ?\/ n o d e _ m o d u l e s \/ ( @ [ ^ / ] + \/ ) ? [ ^ / ] + ) ( \/ .* ) $ / , '$1' )
7190 ) ;
91+ info ( position . source ) ;
7292
73- sourcePath = resolve ( env . src , position . source ) ;
74- sourceLines ;
93+ let sourcePath ;
94+ let sourceLines ;
7595 try {
96+ sourcePath = resolve ( env . src , position . source ) ;
7697 sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
7798 } catch ( err ) {
7899 try {
79- sourceLines = readFileSync (
80- require . resolve ( position . source ) ,
81- 'utf-8'
82- ) . split ( '\n' ) ;
100+ sourcePath = resolve ( env . cwd , position . source ) ;
101+ // sourcePath = require.resolve(position.source);
102+ sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
83103 } catch ( err ) {
84- process . stderr . write ( red ( `Unable to read file: ${ sourcePath } \n` ) ) ;
104+ error ( `Unable to read file: ${ sourcePath } (${ position . source } )\n` ) ;
105+ return ;
85106 }
86- // process.stderr.write(red(`Unable to read file: ${sourcePath}\n`));
87107 }
88- sourceCodeHighlight = '' ;
89108
90109 if ( sourceLines ) {
91- for ( var i = - 4 ; i <= 4 ; i ++ ) {
92- let color = i === 0 ? red : yellow ;
93- let line = position . line + i ;
94- let sourceLine = sourceLines [ line - 1 ] ;
95- sourceCodeHighlight += sourceLine ? `${ color ( sourceLine ) } \n` : '' ;
96- }
110+ let lnrl = position . line . toString ( ) . length + 1 ;
111+ sourceCodeHighlight +=
112+ gray (
113+ ( position . line - 2 || '' ) . toString ( ) . padStart ( lnrl ) +
114+ ' | ' +
115+ sourceLines [ position . line - 3 ] || ''
116+ ) + '\n' ;
117+ sourceCodeHighlight +=
118+ gray (
119+ ( position . line - 1 || '' ) . toString ( ) . padStart ( lnrl ) +
120+ ' | ' +
121+ sourceLines [ position . line - 2 ] || ''
122+ ) + '\n' ;
123+ sourceCodeHighlight +=
124+ red ( position . line . toString ( ) . padStart ( lnrl ) ) +
125+ gray ( ' | ' ) +
126+ sourceLines [ position . line - 1 ] +
127+ '\n' ;
128+ sourceCodeHighlight +=
129+ gray ( '| ' . padStart ( lnrl + 3 ) ) +
130+ red ( '^' . padStart ( position . column + 1 ) ) +
131+ '\n' ;
132+ sourceCodeHighlight +=
133+ gray (
134+ ( position . line + 1 ) . toString ( ) . padStart ( lnrl ) +
135+ ' | ' +
136+ sourceLines [ position . line + 0 ] || ''
137+ ) + '\n' ;
138+ sourceCodeHighlight +=
139+ gray (
140+ ( position . line + 2 ) . toString ( ) . padStart ( lnrl ) +
141+ ' | ' +
142+ sourceLines [ position . line + 1 ] || ''
143+ ) + '\n' ;
97144 }
145+ } else {
146+ position = {
147+ source : stack . getFileName ( ) ,
148+ line : stack . getLineNumber ( ) ,
149+ column : stack . getColumnNumber ( ) ,
150+ } ;
98151 }
99152
100153 process . stderr . write ( '\n' ) ;
101- process . stderr . write ( red ( `${ errorMessage } \n` ) ) ;
102- process . stderr . write ( `method: ${ methodName } \n` ) ;
103- if ( sourceMapContent ) {
104- process . stderr . write (
105- `at: ${ sourcePath } :${ position . line } :${ position . column } \n`
106- ) ;
107- process . stderr . write ( '\n' ) ;
108- process . stderr . write ( 'Source code:\n\n' ) ;
109- process . stderr . write ( sourceCodeHighlight ) ;
110- process . stderr . write ( '\n' ) ;
111- } else {
112- process . stderr . write ( stack . toString ( ) + '\n' ) ;
113- }
154+ process . stderr . write ( `[PrerenderError]: ${ red ( `${ errorMessage } \n` ) } ` ) ;
155+ process . stderr . write (
156+ ` --> ${ position . source } :${ position . line } :${
157+ position . column
158+ } (${ methodName || '<anonymous>' } )\n`
159+ ) ;
160+ process . stderr . write ( sourceCodeHighlight + '\n' ) ;
161+ process . stderr . write ( red ( `${ err . stack } \n` ) ) ;
162+
114163 process . stderr . write (
115164 `This ${
116165 isReferenceError ? 'is most likely' : 'could be'
117166 } caused by using DOM or Web APIs.\n`
118167 ) ;
119168 process . stderr . write (
120- `Pre-render runs in node and has no access to globals available in browsers.\n\n `
169+ `Pre-render runs in node and has no access to globals available in browsers.\n`
121170 ) ;
122171 process . stderr . write (
123172 `Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }'\n`
@@ -128,7 +177,7 @@ async function handlePrerenderError(err, env, stack, entry) {
128177 }
129178 process . stderr . write ( '\n' ) ;
130179 process . stderr . write (
131- ` Alternatively use ' preact build --no-prerender' to disable prerendering.\n\n`
180+ ' Alternatively use ` preact build --no-prerender` to disable prerendering.\n'
132181 ) ;
133182 process . stderr . write (
134183 'See https://github.com/developit/preact-cli#pre-rendering for further information.'
0 commit comments