@@ -4,8 +4,9 @@ const { readFileSync } = require('fs');
4
4
const stackTrace = require ( 'stack-trace' ) ;
5
5
const { SourceMapConsumer } = require ( 'source-map' ) ;
6
6
const { error, info } = require ( '../../util' ) ;
7
+ const outdent = require ( 'outdent' ) ;
7
8
8
- module . exports = function ( env , params ) {
9
+ module . exports = function prerender ( env , params ) {
9
10
params = params || { } ;
10
11
11
12
let entry = resolve ( env . dest , './ssr-build/ssr-bundle.js' ) ;
@@ -47,12 +48,26 @@ module.exports = function(env, params) {
47
48
}
48
49
} ;
49
50
51
+ function getLines ( env , position ) {
52
+ let sourcePath ;
53
+ try {
54
+ sourcePath = resolve ( env . src , position . source ) ;
55
+ return readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
56
+ } catch ( err ) {
57
+ try {
58
+ sourcePath = resolve ( env . cwd , position . source ) ;
59
+ return readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
60
+ } catch ( err ) {
61
+ error ( `Unable to read file: ${ sourcePath } (${ position . source } )\n` ) ;
62
+ }
63
+ }
64
+ }
65
+
50
66
async function handlePrerenderError ( err , env , stack , entry ) {
51
67
const errorMessage = err . toString ( ) ;
52
68
const isReferenceError = errorMessage . startsWith ( 'ReferenceError' ) ;
53
69
const methodName = stack . getMethodName ( ) ;
54
70
const fileName = stack . getFileName ( ) . replace ( / \\ / g, '/' ) ;
55
- let sourceCodeHighlight = '' ;
56
71
57
72
let position ;
58
73
@@ -65,7 +80,9 @@ async function handlePrerenderError(err, env, stack, entry) {
65
80
} ;
66
81
} else {
67
82
try {
68
- const sourceMapContent = JSON . parse ( readFileSync ( `${ entry } .map` ) ) ;
83
+ const sourceMapContent = JSON . parse (
84
+ readFileSync ( `${ entry } .map` , 'utf-8' )
85
+ ) ;
69
86
70
87
await SourceMapConsumer . with ( sourceMapContent , null , consumer => {
71
88
position = consumer . originalPositionFor ( {
@@ -75,7 +92,6 @@ async function handlePrerenderError(err, env, stack, entry) {
75
92
} ) ;
76
93
} catch ( err ) {
77
94
error ( `Unable to read sourcemap: ${ entry } .map` ) ;
78
- return ;
79
95
}
80
96
}
81
97
@@ -89,59 +105,6 @@ async function handlePrerenderError(err, env, stack, entry) {
89
105
. replace ( / ^ ( .* ?\/ n o d e _ m o d u l e s \/ ( @ [ ^ / ] + \/ ) ? [ ^ / ] + ) ( \/ .* ) $ / , '$1' )
90
106
) ;
91
107
info ( position . source ) ;
92
-
93
- let sourcePath ;
94
- let sourceLines ;
95
- try {
96
- sourcePath = resolve ( env . src , position . source ) ;
97
- sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
98
- } catch ( err ) {
99
- try {
100
- sourcePath = resolve ( env . cwd , position . source ) ;
101
- // sourcePath = require.resolve(position.source);
102
- sourceLines = readFileSync ( sourcePath , 'utf-8' ) . split ( '\n' ) ;
103
- } catch ( err ) {
104
- error ( `Unable to read file: ${ sourcePath } (${ position . source } )\n` ) ;
105
- return ;
106
- }
107
- }
108
-
109
- if ( sourceLines ) {
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' ;
144
- }
145
108
} else {
146
109
position = {
147
110
source : stack . getFileName ( ) ,
@@ -150,37 +113,51 @@ async function handlePrerenderError(err, env, stack, entry) {
150
113
} ;
151
114
}
152
115
153
- process . stderr . write ( '\n' ) ;
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
-
163
- process . stderr . write (
164
- `This ${
165
- isReferenceError ? 'is most likely' : 'could be'
166
- } caused by using DOM or Web APIs.\n`
167
- ) ;
168
- process . stderr . write (
169
- `Pre-render runs in node and has no access to globals available in browsers.\n`
170
- ) ;
171
- process . stderr . write (
172
- `Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }'\n`
173
- ) ;
174
-
175
- if ( methodName === 'componentWillMount' ) {
176
- process . stderr . write ( `or place logic in 'componentDidMount' method.\n` ) ;
116
+ const sourceLines = getLines ( env , position ) ;
117
+
118
+ let sourceCodeHighlight = '' ;
119
+ if ( sourceLines ) {
120
+ const lnrl = position . line . toString ( ) . length + 2 ;
121
+ const line = position . line ;
122
+ const un = undefined ;
123
+
124
+ const pad = l =>
125
+ ( l === undefined ? '' : ( line + l || '' ) + '' ) . padStart ( lnrl ) ;
126
+
127
+ sourceCodeHighlight = gray ( outdent `
128
+ ${ pad ( - 2 ) } | ${ sourceLines [ line - 3 ] || '' }
129
+ ${ pad ( - 1 ) } | ${ sourceLines [ line - 2 ] || '' }
130
+ ${ pad ( - 0 ) } | ${ sourceLines [ line - 1 ] || '' }
131
+ ${ pad ( un ) } | ${ red ( '^' . padStart ( position . column + 1 ) ) }
132
+ ${ pad ( + 1 ) } | ${ sourceLines [ line + 0 ] || '' }
133
+ ${ pad ( + 2 ) } | ${ sourceLines [ line + 1 ] || '' }
134
+ ` ) ;
177
135
}
178
- process . stderr . write ( '\n' ) ;
179
- process . stderr . write (
180
- 'Alternatively use `preact build --no-prerender` to disable prerendering.\n'
181
- ) ;
182
- process . stderr . write (
183
- 'See https://github.com/developit/preact-cli#pre-rendering for further information.'
184
- ) ;
136
+
137
+ const stderr = process . stderr . write . bind ( process . stderr ) ;
138
+
139
+ stderr ( '\n' ) ;
140
+ stderr ( outdent `
141
+ [PrerenderError]: ${ red ( `${ errorMessage } ` ) }
142
+ --> ${ position . source } :${ position . line } :${ position . column } (${ methodName ||
143
+ '<anonymous>' } )
144
+ ${ sourceCodeHighlight }
145
+
146
+ ${ red ( `${ err . stack } ` ) }
147
+
148
+ This ${
149
+ isReferenceError ? 'is most likely' : 'could be'
150
+ } caused by using DOM or Web APIs.
151
+ Pre-render runs in node and has no access to globals available in browsers.
152
+ Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }\
153
+ ${
154
+ methodName === 'componentWillMount'
155
+ ? `\nor place logic in 'componentDidMount' method.`
156
+ : ''
157
+ }
158
+
159
+ Alternatively use \`preact build --no-prerender\` to disable prerendering.
160
+ See https://github.com/developit/preact-cli#pre-rendering for further information.
161
+ ` ) ;
185
162
process . exit ( 1 ) ;
186
163
}
0 commit comments