Skip to content

Commit 71c1511

Browse files
better prerender errors myb
1 parent b835770 commit 71c1511

1 file changed

Lines changed: 99 additions & 50 deletions

File tree

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

Lines changed: 99 additions & 50 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
@@ -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

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

Comments
 (0)