Skip to content

Commit bb94b1e

Browse files
feat: outdent error message
1 parent 71c1511 commit bb94b1e

File tree

3 files changed

+71
-88
lines changed

3 files changed

+71
-88
lines changed

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

Lines changed: 65 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ const { readFileSync } = require('fs');
44
const stackTrace = require('stack-trace');
55
const { SourceMapConsumer } = require('source-map');
66
const { error, info } = require('../../util');
7+
const outdent = require('outdent');
78

8-
module.exports = function(env, params) {
9+
module.exports = function prerender(env, params) {
910
params = params || {};
1011

1112
let entry = resolve(env.dest, './ssr-build/ssr-bundle.js');
@@ -46,12 +47,26 @@ module.exports = function(env, params) {
4647
}
4748
};
4849

50+
function getLines(env, position) {
51+
let sourcePath;
52+
try {
53+
sourcePath = resolve(env.src, position.source);
54+
return readFileSync(sourcePath, 'utf-8').split('\n');
55+
} catch (err) {
56+
try {
57+
sourcePath = resolve(env.cwd, position.source);
58+
return readFileSync(sourcePath, 'utf-8').split('\n');
59+
} catch (err) {
60+
error(`Unable to read file: ${sourcePath} (${position.source})\n`);
61+
}
62+
}
63+
}
64+
4965
async function handlePrerenderError(err, env, stack, entry) {
5066
const errorMessage = err.toString();
5167
const isReferenceError = errorMessage.startsWith('ReferenceError');
5268
const methodName = stack.getMethodName();
5369
const fileName = stack.getFileName().replace(/\\/g, '/');
54-
let sourceCodeHighlight = '';
5570

5671
let position;
5772

@@ -64,7 +79,9 @@ async function handlePrerenderError(err, env, stack, entry) {
6479
};
6580
} else {
6681
try {
67-
const sourceMapContent = JSON.parse(readFileSync(`${entry}.map`));
82+
const sourceMapContent = JSON.parse(
83+
readFileSync(`${entry}.map`, 'utf-8')
84+
);
6885

6986
await SourceMapConsumer.with(sourceMapContent, null, consumer => {
7087
position = consumer.originalPositionFor({
@@ -74,7 +91,6 @@ async function handlePrerenderError(err, env, stack, entry) {
7491
});
7592
} catch (err) {
7693
error(`Unable to read sourcemap: ${entry}.map`);
77-
return;
7894
}
7995
}
8096

@@ -88,59 +104,6 @@ async function handlePrerenderError(err, env, stack, entry) {
88104
.replace(/^(.*?\/node_modules\/(@[^/]+\/)?[^/]+)(\/.*)$/, '$1')
89105
);
90106
info(position.source);
91-
92-
let sourcePath;
93-
let sourceLines;
94-
try {
95-
sourcePath = resolve(env.src, position.source);
96-
sourceLines = readFileSync(sourcePath, 'utf-8').split('\n');
97-
} catch (err) {
98-
try {
99-
sourcePath = resolve(env.cwd, position.source);
100-
// sourcePath = require.resolve(position.source);
101-
sourceLines = readFileSync(sourcePath, 'utf-8').split('\n');
102-
} catch (err) {
103-
error(`Unable to read file: ${sourcePath} (${position.source})\n`);
104-
return;
105-
}
106-
}
107-
108-
if (sourceLines) {
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';
143-
}
144107
} else {
145108
position = {
146109
source: stack.getFileName(),
@@ -149,37 +112,51 @@ async function handlePrerenderError(err, env, stack, entry) {
149112
};
150113
}
151114

152-
process.stderr.write('\n');
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-
162-
process.stderr.write(
163-
`This ${
164-
isReferenceError ? 'is most likely' : 'could be'
165-
} caused by using DOM or Web APIs.\n`
166-
);
167-
process.stderr.write(
168-
`Pre-render runs in node and has no access to globals available in browsers.\n`
169-
);
170-
process.stderr.write(
171-
`Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }'\n`
172-
);
173-
174-
if (methodName === 'componentWillMount') {
175-
process.stderr.write(`or place logic in 'componentDidMount' method.\n`);
115+
const sourceLines = getLines(env, position);
116+
117+
let sourceCodeHighlight = '';
118+
if (sourceLines) {
119+
const lnrl = position.line.toString().length + 2;
120+
const line = position.line;
121+
const un = undefined;
122+
123+
const pad = l =>
124+
(l === undefined ? '' : (line + l || '') + '').padStart(lnrl);
125+
126+
sourceCodeHighlight = gray(outdent`
127+
${pad(-2)} | ${sourceLines[line - 3] || ''}
128+
${pad(-1)} | ${sourceLines[line - 2] || ''}
129+
${pad(-0)} | ${sourceLines[line - 1] || ''}
130+
${pad(un)} | ${red('^'.padStart(position.column + 1))}
131+
${pad(+1)} | ${sourceLines[line + 0] || ''}
132+
${pad(+2)} | ${sourceLines[line + 1] || ''}
133+
`);
176134
}
177-
process.stderr.write('\n');
178-
process.stderr.write(
179-
'Alternatively use `preact build --no-prerender` to disable prerendering.\n'
180-
);
181-
process.stderr.write(
182-
'See https://github.com/developit/preact-cli#pre-rendering for further information.'
183-
);
135+
136+
const stderr = process.stderr.write.bind(process.stderr);
137+
138+
stderr('\n');
139+
stderr(outdent`
140+
[PrerenderError]: ${red(`${errorMessage}`)}
141+
--> ${position.source}:${position.line}:${position.column} (${methodName ||
142+
'<anonymous>'})
143+
${sourceCodeHighlight}
144+
145+
${red(`${err.stack}`)}
146+
147+
This ${
148+
isReferenceError ? 'is most likely' : 'could be'
149+
} caused by using DOM or Web APIs.
150+
Pre-render runs in node and has no access to globals available in browsers.
151+
Consider wrapping code producing error in: 'if (typeof window !== "undefined") { ... }\
152+
${
153+
methodName === 'componentWillMount'
154+
? `\nor place logic in 'componentDidMount' method.`
155+
: ''
156+
}
157+
158+
Alternatively use \`preact build --no-prerender\` to disable prerendering.
159+
See https://github.com/developit/preact-cli#pre-rendering for further information.
160+
`);
184161
process.exit(1);
185162
}

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"minimatch": "^3.0.3",
106106
"optimize-css-assets-webpack-plugin": "^5.0.1",
107107
"ora": "^3.4.0",
108+
"outdent": "^0.7.0",
108109
"postcss-load-config": "^2.1.0",
109110
"postcss-loader": "^3.0.0",
110111
"progress-bar-webpack-plugin": "^1.12.1",

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9653,6 +9653,11 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5:
96539653
os-homedir "^1.0.0"
96549654
os-tmpdir "^1.0.0"
96559655

9656+
outdent@^0.7.0:
9657+
version "0.7.0"
9658+
resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.7.0.tgz#cfd1f1956305141e0cf3e898ada6547373c1997a"
9659+
integrity sha512-Ue462G+UIFoyQmOzapGIKWS3d/9NHeD/018WGEDZIhN2/VaQpVXbofMcZX0socv1fw4/tmEn7Vd3McOdPZfKzQ==
9660+
96569661
p-cancelable@^1.0.0:
96579662
version "1.1.0"
96589663
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"

0 commit comments

Comments
 (0)