summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/thirty-fans-know.md6
-rw-r--r--packages/astro-parser/src/interfaces.ts2
-rw-r--r--packages/astro-parser/src/utils/error.ts29
-rw-r--r--packages/astro/src/dev.ts1
-rw-r--r--packages/astro/src/logger.ts2
-rw-r--r--packages/astro/src/runtime.ts44
6 files changed, 61 insertions, 23 deletions
diff --git a/.changeset/thirty-fans-know.md b/.changeset/thirty-fans-know.md
new file mode 100644
index 000000000..ff8010931
--- /dev/null
+++ b/.changeset/thirty-fans-know.md
@@ -0,0 +1,6 @@
+---
+'astro': patch
+'astro-parser': patch
+---
+
+Improve error display for missing local files
diff --git a/packages/astro-parser/src/interfaces.ts b/packages/astro-parser/src/interfaces.ts
index 40eeb04f5..f3fa5da9d 100644
--- a/packages/astro-parser/src/interfaces.ts
+++ b/packages/astro-parser/src/interfaces.ts
@@ -1,5 +1,5 @@
import type { SourceMap } from 'magic-string';
-export type { CompileError } from './utils/error';
+export { CompileError } from './utils/error';
export interface BaseNode {
start: number;
diff --git a/packages/astro-parser/src/utils/error.ts b/packages/astro-parser/src/utils/error.ts
index 8ebb5b093..00eed866f 100644
--- a/packages/astro-parser/src/utils/error.ts
+++ b/packages/astro-parser/src/utils/error.ts
@@ -5,14 +5,23 @@ import get_code_frame from './get_code_frame.js';
export class CompileError extends Error {
code: string;
- start: { line: number; column: number };
end: { line: number; column: number };
- pos: number;
filename: string;
frame: string;
+ start: { line: number; column: number };
+
+ constructor({ code, filename, start, end, message }: { code: string; filename: string; start: number; message: string; end?: number }) {
+ super(message);
+
+ this.start = locate(code, start, { offsetLine: 1 });
+ this.end = locate(code, end || start, { offsetLine: 1 });
+ this.filename = filename;
+ this.message = message;
+ this.frame = get_code_frame(code, this.start.line - 1, this.start.column);
+ }
toString() {
- return `${this.message} (${this.start.line}:${this.start.column})\n${this.frame}`;
+ return `${this.filename}:${this.start.line}:${this.start.column}\n\t${this.message}\n${this.frame}`;
}
}
@@ -21,26 +30,14 @@ export default function error(
message: string,
props: {
name: string;
- code: string;
source: string;
filename: string;
start: number;
end?: number;
}
): never {
- const err = new CompileError(message);
+ const err = new CompileError({ message, start: props.start, end: props.end, filename: props.filename });
err.name = props.name;
- const start = locate(props.source, props.start, { offsetLine: 1 });
- const end = locate(props.source, props.end || props.start, { offsetLine: 1 });
-
- err.code = props.code;
- err.start = start;
- err.end = end;
- err.pos = props.start;
- err.filename = props.filename;
-
- err.frame = get_code_frame(props.source, start.line - 1, start.column);
-
throw err;
}
diff --git a/packages/astro/src/dev.ts b/packages/astro/src/dev.ts
index 7f61492d7..5d1f20cff 100644
--- a/packages/astro/src/dev.ts
+++ b/packages/astro/src/dev.ts
@@ -66,6 +66,7 @@ export default async function dev(astroConfig: AstroConfig) {
break;
}
case 500: {
+ res.setHeader('Content-Type', 'text/html;charset=utf-8');
switch (result.type) {
case 'parse-error': {
const err = result.error;
diff --git a/packages/astro/src/logger.ts b/packages/astro/src/logger.ts
index 282e8506e..84572e86e 100644
--- a/packages/astro/src/logger.ts
+++ b/packages/astro/src/logger.ts
@@ -131,7 +131,7 @@ export function parseError(opts: LogOptions, err: CompileError) {
'parse-error',
`
- ${underline(bold(grey(`${err.filename}:${err.start.line}:${err.start.column}`)))}
+ ${underline(bold(grey(`${err.filename || ''}:${err.start.line}:${err.start.column}`)))}
${bold(red(`š˜… ${err.message}`))}
diff --git a/packages/astro/src/runtime.ts b/packages/astro/src/runtime.ts
index 2beb9d7f3..a73df33d6 100644
--- a/packages/astro/src/runtime.ts
+++ b/packages/astro/src/runtime.ts
@@ -1,16 +1,16 @@
import 'source-map-support/register.js';
-import type { SnowpackDevServer, ServerRuntime as SnowpackServerRuntime, SnowpackConfig } from 'snowpack';
-import type { CompileError } from 'astro-parser';
import type { LogOptions } from './logger';
import type { AstroConfig, CollectionResult, CollectionRSS, CreateCollection, Params, RuntimeMode } from './@types/astro';
import resolve from 'resolve';
-import { existsSync } from 'fs';
+import { existsSync, promises as fs } from 'fs';
import { fileURLToPath, pathToFileURL } from 'url';
import { posix as path } from 'path';
import { performance } from 'perf_hooks';
+import { SnowpackDevServer, ServerRuntime as SnowpackServerRuntime, SnowpackConfig, NotFoundError } from 'snowpack';
+import { CompileError } from 'astro-parser';
import { loadConfiguration, logger as snowpackLogger, startServer as startSnowpackServer } from 'snowpack';
-import { canonicalURL, stopTimer } from './build/util.js';
+import { canonicalURL, getSrcPath, stopTimer } from './build/util.js';
import { debug, info } from './logger.js';
import { searchForPage } from './search.js';
import snowpackExternals from './external.js';
@@ -40,7 +40,7 @@ type LoadResultSuccess = {
};
type LoadResultNotFound = { statusCode: 404; error: Error; collectionInfo?: CollectionInfo };
type LoadResultRedirect = { statusCode: 301 | 302; location: string; collectionInfo?: CollectionInfo };
-type LoadResultError = { statusCode: 500 } & ({ type: 'parse-error'; error: CompileError } | { type: 'unknown'; error: Error });
+type LoadResultError = { statusCode: 500 } & ({ type: 'parse-error'; error: CompileError } | { type: 'not-found'; error: CompileError } | { type: 'unknown'; error: Error });
export type LoadResult = (LoadResultSuccess | LoadResultNotFound | LoadResultRedirect | LoadResultError) & { collectionInfo?: CollectionInfo };
@@ -242,6 +242,40 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
error: err,
};
}
+
+ if (err instanceof NotFoundError && rawPathname) {
+ const fileMatch = err.toString().match(/\(([^\)]+)\)/);
+ const missingFile: string | undefined = (fileMatch && fileMatch[1].replace(/^\/_astro/, '').replace(/\.proxy\.js$/, '')) || undefined;
+ const distPath = path.extname(rawPathname) ? rawPathname : rawPathname.replace(/\/?$/, '/index.html');
+ const srcFile = getSrcPath(distPath, { astroConfig: config.astroConfig });
+ const code = existsSync(srcFile) ? await fs.readFile(srcFile, 'utf8') : '';
+
+ // try and find the import statement within the module. this is a bit hacky, as we don’t know the line, but
+ // given that we know this is for sure a ā€œnot foundā€ error, and we know what file is erring,
+ // we can make some safe assumptions about how to locate the line in question
+ let start = 0;
+ const segments = missingFile ? missingFile.split('/').filter((segment) => !!segment) : [];
+ while (segments.length) {
+ const importMatch = code.indexOf(segments.join('/'));
+ if (importMatch >= 0) {
+ start = importMatch;
+ break;
+ }
+ segments.shift();
+ }
+
+ return {
+ statusCode: 500,
+ type: 'not-found',
+ error: new CompileError({
+ code,
+ filename: srcFile.pathname,
+ start,
+ message: `Could not find${missingFile ? ` "${missingFile}"` : ' file'}`,
+ }),
+ };
+ }
+
return {
statusCode: 500,
type: 'unknown',