Skip to content

Commit 73ba72b

Browse files
better prerender errors myb
1 parent 7df92f9 commit 73ba72b

File tree

1 file changed

+100
-51
lines changed

1 file changed

+100
-51
lines changed

packages/cli/lib/lib/webpack/prerender.js

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
const { red, yellow } = require('kleur');
1+
const { red, gray } = require('kleur');
22
const { resolve } = require('path');
33
const { readFileSync } = require('fs');
44
const stackTrace = require('stack-trace');
55
const { SourceMapConsumer } = require('source-map');
6+
const { error, info } = require('../../util');
67

78
module.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

4550
async 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 (/webpack:/.test(fileName)) {
61+
position = {
62+
source: fileName.replace(/.+webpack:/, '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(/^(.*?\/node_modules\/(@[^/]+\/)?[^/]+)(\/.*)$/, '$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

Comments
 (0)