Skip to content

Commit a41d498

Browse files
authored
fix: Improve prerender errors (#1756)
* fix: Improve prerender error logic * fix: Disable SSR JS minification for better stack trace positions * test: Fix output sizes * docs: Adding changeset
1 parent 696ccc0 commit a41d498

File tree

4 files changed

+83
-89
lines changed

4 files changed

+83
-89
lines changed

.changeset/metal-insects-yawn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-cli': patch
3+
---
4+
5+
Improves prerender error message's output and positioning

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

+73-87
Original file line numberDiff line numberDiff line change
@@ -45,112 +45,98 @@ async function handlePrerenderError(err, env, stack, entry) {
4545
let errorMessage = err.toString();
4646
let isReferenceError = errorMessage.startsWith('ReferenceError');
4747
let methodName = stack.getMethodName();
48+
let sourceMapContent, position, sourcePath, sourceLines, sourceCodeHighlight;
4849

49-
process.stderr.write('\n');
50-
process.stderr.write(red(`\n${errorMessage}\n`));
50+
try {
51+
sourceMapContent = JSON.parse(readFileSync(`${entry}.map`, 'utf-8'));
52+
} catch (err) {
53+
process.stderr.write(red(`\n\nUnable to read sourcemap: ${entry}.map\n`));
54+
}
5155

52-
// If a methodName exists, it's likely user code
53-
if (methodName) {
54-
let sourceMapContent,
55-
position,
56-
sourcePath,
57-
sourceLines,
58-
sourceCodeHighlight;
59-
try {
60-
sourceMapContent = JSON.parse(readFileSync(`${entry}.map`, 'utf-8'));
61-
} catch (err) {
62-
process.stderr.write(red(`\n\nUnable to read sourcemap: ${entry}.map\n`));
63-
}
56+
if (sourceMapContent) {
57+
position = await SourceMapConsumer.with(sourceMapContent, null, consumer =>
58+
consumer.originalPositionFor({
59+
line: stack.getLineNumber(),
60+
column: stack.getColumnNumber(),
61+
})
62+
);
6463

65-
if (sourceMapContent) {
66-
await SourceMapConsumer.with(sourceMapContent, null, consumer => {
67-
position = consumer.originalPositionFor({
68-
line: stack.getLineNumber(),
69-
column: stack.getColumnNumber(),
70-
});
71-
});
72-
73-
if (position.source) {
74-
position.source = position.source
75-
.replace('webpack://', '.')
76-
.replace(/^.*~\/((?:@[^/]+\/)?[^/]+)/, (s, name) =>
77-
require
78-
.resolve(name)
79-
.replace(/^(.*?\/node_modules\/(@[^/]+\/)?[^/]+)(\/.*)$/, '$1')
80-
);
81-
82-
sourcePath = resolve(env.src, position.source);
83-
sourceLines;
64+
if (position.source) {
65+
position.source = position.source
66+
.replace('webpack://', '.')
67+
.replace(/^.*~\/((?:@[^/]+\/)?[^/]+)/, (s, name) =>
68+
require
69+
.resolve(name)
70+
.replace(/^(.*?\/node_modules\/(@[^/]+\/)?[^/]+)(\/.*)$/, '$1')
71+
);
72+
73+
sourcePath = resolve(env.src, position.source);
74+
sourceLines;
75+
try {
76+
sourceLines = readFileSync(sourcePath, 'utf-8').split('\n');
77+
} catch (err) {
8478
try {
85-
sourceLines = readFileSync(sourcePath, 'utf-8').split('\n');
79+
sourceLines = readFileSync(
80+
require.resolve(position.source),
81+
'utf-8'
82+
).split('\n');
8683
} catch (err) {
87-
try {
88-
sourceLines = readFileSync(
89-
require.resolve(position.source),
90-
'utf-8'
91-
).split('\n');
92-
} catch (err) {
93-
process.stderr.write(
94-
red(`\n\nUnable to read file: ${sourcePath}\n`)
95-
);
96-
}
84+
process.stderr.write(red(`\n\nUnable to read file: ${sourcePath}\n`));
9785
}
98-
sourceCodeHighlight = '';
9986
}
87+
sourceCodeHighlight = '';
88+
}
10089

101-
if (sourceLines) {
102-
for (var i = -4; i <= 4; i++) {
103-
let color = i === 0 ? red : yellow;
104-
let line = position.line + i;
105-
let sourceLine = sourceLines[line - 1];
106-
sourceCodeHighlight += sourceLine ? `${color(sourceLine)}\n` : '';
107-
}
90+
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` : '\n';
10896
}
10997
}
98+
}
11099

100+
process.stderr.write('\n');
101+
process.stderr.write(red(`\n${errorMessage}\n`));
102+
103+
if (sourceMapContent && sourceCodeHighlight) {
111104
process.stderr.write(`method: ${methodName}\n`);
112-
if (sourceMapContent & sourceCodeHighlight) {
113-
process.stderr.write(
114-
`at: ${sourcePath}:${position.line}:${position.column}\n`
115-
);
116-
process.stderr.write('\n');
117-
process.stderr.write('Source code:\n\n');
118-
process.stderr.write(sourceCodeHighlight);
119-
process.stderr.write('\n');
120-
} else {
121-
process.stderr.write('\n');
122-
process.stderr.write('Stack:\n\n');
123-
process.stderr.write(JSON.stringify(stack, null, 4) + '\n');
124-
}
125-
} else {
126105
process.stderr.write(
127-
yellow(
128-
'Cannot determine error position. This most likely means it originated in node_modules.\n\n'
129-
)
106+
`at: ${sourcePath}:${position.line}:${position.column}\n`
130107
);
108+
process.stderr.write('\n');
109+
process.stderr.write('Source code:\n');
110+
process.stderr.write(sourceCodeHighlight);
111+
process.stderr.write('\n');
112+
} else {
113+
process.stderr.write('\n');
114+
process.stderr.write('Stack:\n\n');
115+
process.stderr.write(JSON.stringify(stack, null, 4) + '\n');
131116
}
132117

133-
process.stderr.write(
134-
`This ${
118+
const message = `
119+
This ${
135120
isReferenceError ? 'is most likely' : 'could be'
136-
} caused by using DOM or Web APIs.\n`
137-
);
138-
process.stderr.write(
139-
'Pre-render runs in node and has no access to globals available in browsers.\n\n'
140-
);
141-
process.stderr.write(
142-
'Consider wrapping code producing error in: "if (typeof window !== "undefined") { ... }"\n'
143-
);
121+
} caused by using DOM or Web APIs.
122+
Pre-rendering runs in Node and therefore has no access browser globals.
123+
124+
Consider wrapping the code producing the error in: 'if (typeof window !== "undefined") { ... }'
125+
${
126+
methodName === 'componentWillMount'
127+
? 'or place logic in "componentDidMount" method.'
128+
: ''
129+
}
144130
145-
if (methodName === 'componentWillMount') {
146-
process.stderr.write('or place logic in "componentDidMount" method.\n');
147-
}
148-
process.stderr.write('\n');
149-
process.stderr.write(
150-
'Alternatively use "preact build --no-prerender" to disable prerendering.\n\n'
151-
);
131+
Alternatively, disable prerendering altogether with 'preact build --no-prerender'.
132+
133+
See https://github.com/preactjs/preact-cli#pre-rendering for further information.
134+
`;
152135
process.stderr.write(
153-
'See https://github.com/preactjs/preact-cli#pre-rendering for further information.\n\n'
136+
message
137+
.trim()
138+
.replace(/^\t+/gm, '')
139+
.replace(/\n\n\n/, '\n\n') + '\n\n'
154140
);
155141
process.exit(1);
156142
}

packages/cli/src/lib/webpack/webpack-server-config.js

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ function serverConfig(env) {
2626
async: resolve(__dirname, './dummy-loader'),
2727
},
2828
},
29+
optimization: {
30+
minimize: false,
31+
},
2932
};
3033
}
3134

packages/cli/tests/images/build.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ exports.default = Object.assign({}, common, {
1313
'assets/favicon.ico': 15086,
1414
'ssr-build/ssr-bundle.89e23.css': 1281,
1515
'ssr-build/ssr-bundle.89e23.css.map': 2070,
16-
'ssr-build/ssr-bundle.js': 11937,
17-
'ssr-build/ssr-bundle.js.map': 42893,
16+
'ssr-build/ssr-bundle.js': 28830,
17+
'ssr-build/ssr-bundle.js.map': 52686,
1818
'ssr-build/asset-manifest.json': 178,
1919
'bundle.259c5.css': 901,
2020
'bundle.f79fb.js': 21429,

0 commit comments

Comments
 (0)