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
@@ -32,91 +33,139 @@ module.exports = function(env, params) {
3233 ) ) ;
3334 return renderToString ( preact . h ( app , { ...params , url } ) ) ;
3435 } catch ( err ) {
35- let stack = stackTrace . parse ( err ) . filter ( s => s . getFileName ( ) === entry ) [ 0 ] ;
36+ const stack = stackTrace
37+ . parse ( err )
38+ . filter ( s => s . getFileName ( ) . includes ( 'ssr-build' ) ) [ 0 ] ;
3639 if ( ! stack ) {
37- throw err ;
40+ error ( err ) ;
41+ return '' ;
3842 }
3943
4044 handlePrerenderError ( err , env , stack , entry ) ;
45+ return '' ;
4146 }
4247} ;
4348
4449async function handlePrerenderError ( err , env , stack , entry ) {
45- let errorMessage = err . toString ( ) ;
46- let isReferenceError = errorMessage . startsWith ( 'ReferenceError' ) ;
47- let methodName = stack . getMethodName ( ) ;
48- let sourceMapContent , position , sourcePath , sourceLines , sourceCodeHighlight ;
50+ const errorMessage = err . toString ( ) ;
51+ const isReferenceError = errorMessage . startsWith ( 'ReferenceError' ) ;
52+ const methodName = stack . getMethodName ( ) ;
53+ const fileName = stack . getFileName ( ) . replace ( / \\ / g, '/' ) ;
54+ let sourceCodeHighlight = '' ;
4955
50- try {
51- sourceMapContent = JSON . parse ( readFileSync ( `${ entry } .map` ) ) ;
52- } catch ( err ) {
53- process . stderr . write ( red ( `Unable to read sourcemap: ${ entry } .map\n` ) ) ;
54- }
56+ let position ;
5557
56- if ( sourceMapContent ) {
57- await SourceMapConsumer . with ( sourceMapContent , null , consumer => {
58- position = consumer . originalPositionFor ( {
59- line : stack . getLineNumber ( ) ,
60- column : stack . getColumnNumber ( ) ,
58+ info ( fileName ) ;
59+ if ( / w e b p a c k : / . test ( fileName ) ) {
60+ position = {
61+ source : fileName . replace ( / .+ w e b p a c k : / , 'webpack://' ) ,
62+ line : stack . getLineNumber ( ) ,
63+ column : stack . getColumnNumber ( ) ,
64+ } ;
65+ } else {
66+ try {
67+ const sourceMapContent = JSON . parse ( readFileSync ( `${ entry } .map` ) ) ;
68+
69+ await SourceMapConsumer . with ( sourceMapContent , null , consumer => {
70+ position = consumer . originalPositionFor ( {
71+ line : stack . getLineNumber ( ) ,
72+ column : stack . getColumnNumber ( ) ,
73+ } ) ;
6174 } ) ;
62- } ) ;
75+ } catch ( err ) {
76+ error ( `Unable to read sourcemap: ${ entry } .map` ) ;
77+ return ;
78+ }
79+ }
6380
81+ if ( position ) {
82+ info ( position . source ) ;
6483 position . source = position . source
6584 . replace ( 'webpack://' , '.' )
6685 . replace ( / ^ .* ~ \/ ( (?: @ [ ^ / ] + \/ ) ? [ ^ / ] + ) / , ( s , name ) =>
6786 require
6887 . resolve ( name )
6988 . replace ( / ^ ( .* ?\/ n o d e _ m o d u l e s \/ ( @ [ ^ / ] + \/ ) ? [ ^ / ] + ) ( \/ .* ) $ / , '$1' )
7089 ) ;
90+ info ( position . source ) ;
7191
72- sourcePath = resolve ( env . src , position . source ) ;
73- sourceLines ;
92+ let sourcePath ;
93+ let sourceLines ;
7494 try {
95+ sourcePath = resolve ( env . src , position . source ) ;
7596 sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
7697 } catch ( err ) {
7798 try {
78- sourceLines = readFileSync (
79- require . resolve ( position . source ) ,
80- 'utf-8'
81- ) . split ( '\n' ) ;
99+ sourcePath = resolve ( env . cwd , position . source ) ;
100+ // sourcePath = require.resolve(position.source);
101+ sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
82102 } catch ( err ) {
83- process . stderr . write ( red ( `Unable to read file: ${ sourcePath } \n` ) ) ;
103+ error ( `Unable to read file: ${ sourcePath } (${ position . source } )\n` ) ;
104+ return ;
84105 }
85- // process.stderr.write(red(`Unable to read file: ${sourcePath}\n`));
86106 }
87- sourceCodeHighlight = '' ;
88107
89108 if ( sourceLines ) {
90- for ( var i = - 4 ; i <= 4 ; i ++ ) {
91- let color = i === 0 ? red : yellow ;
92- let line = position . line + i ;
93- let sourceLine = sourceLines [ line - 1 ] ;
94- sourceCodeHighlight += sourceLine ? `${ color ( sourceLine ) } \n` : '' ;
95- }
109+ let lnrl = position . line . toString ( ) . length + 1 ;
110+ sourceCodeHighlight +=
111+ gray (
112+ ( position . line - 2 || '' ) . toString ( ) . padStart ( lnrl ) +
113+ ' | ' +
114+ sourceLines [ position . line - 3 ] || ''
115+ ) + '\n' ;
116+ sourceCodeHighlight +=
117+ gray (
118+ ( position . line - 1 || '' ) . toString ( ) . padStart ( lnrl ) +
119+ ' | ' +
120+ sourceLines [ position . line - 2 ] || ''
121+ ) + '\n' ;
122+ sourceCodeHighlight +=
123+ red ( position . line . toString ( ) . padStart ( lnrl ) ) +
124+ gray ( ' | ' ) +
125+ sourceLines [ position . line - 1 ] +
126+ '\n' ;
127+ sourceCodeHighlight +=
128+ gray ( '| ' . padStart ( lnrl + 3 ) ) +
129+ red ( '^' . padStart ( position . column + 1 ) ) +
130+ '\n' ;
131+ sourceCodeHighlight +=
132+ gray (
133+ ( position . line + 1 ) . toString ( ) . padStart ( lnrl ) +
134+ ' | ' +
135+ sourceLines [ position . line + 0 ] || ''
136+ ) + '\n' ;
137+ sourceCodeHighlight +=
138+ gray (
139+ ( position . line + 2 ) . toString ( ) . padStart ( lnrl ) +
140+ ' | ' +
141+ sourceLines [ position . line + 1 ] || ''
142+ ) + '\n' ;
96143 }
144+ } else {
145+ position = {
146+ source : stack . getFileName ( ) ,
147+ line : stack . getLineNumber ( ) ,
148+ column : stack . getColumnNumber ( ) ,
149+ } ;
97150 }
98151
99152 process . stderr . write ( '\n' ) ;
100- process . stderr . write ( red ( `${ errorMessage } \n` ) ) ;
101- process . stderr . write ( `method: ${ methodName } \n` ) ;
102- if ( sourceMapContent ) {
103- process . stderr . write (
104- `at: ${ sourcePath } :${ position . line } :${ position . column } \n`
105- ) ;
106- process . stderr . write ( '\n' ) ;
107- process . stderr . write ( 'Source code:\n\n' ) ;
108- process . stderr . write ( sourceCodeHighlight ) ;
109- process . stderr . write ( '\n' ) ;
110- } else {
111- process . stderr . write ( stack . toString ( ) + '\n' ) ;
112- }
153+ process . stderr . write ( `[PrerenderError]: ${ red ( `${ errorMessage } \n` ) } ` ) ;
154+ process . stderr . write (
155+ ` --> ${ position . source } :${ position . line } :${
156+ position . column
157+ } (${ methodName || '<anonymous>' } )\n`
158+ ) ;
159+ process . stderr . write ( sourceCodeHighlight + '\n' ) ;
160+ process . stderr . write ( red ( `${ err . stack } \n` ) ) ;
161+
113162 process . stderr . write (
114163 `This ${
115164 isReferenceError ? 'is most likely' : 'could be'
116165 } caused by using DOM or Web APIs.\n`
117166 ) ;
118167 process . stderr . write (
119- `Pre-render runs in node and has no access to globals available in browsers.\n\n `
168+ `Pre-render runs in node and has no access to globals available in browsers.\n`
120169 ) ;
121170 process . stderr . write (
122171 `Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }'\n`
@@ -127,7 +176,7 @@ async function handlePrerenderError(err, env, stack, entry) {
127176 }
128177 process . stderr . write ( '\n' ) ;
129178 process . stderr . write (
130- ` Alternatively use ' preact build --no-prerender' to disable prerendering.\n\n`
179+ ' Alternatively use ` preact build --no-prerender` to disable prerendering.\n'
131180 ) ;
132181 process . stderr . write (
133182 'See https://github.com/developit/preact-cli#pre-rendering for further information.'
0 commit comments