summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/nervous-pillows-sing.md5
-rw-r--r--packages/astro/src/build.ts29
-rw-r--r--packages/astro/src/build/page.ts8
-rw-r--r--packages/astro/src/compiler/codegen/index.ts2
-rw-r--r--packages/astro/test/astro-throw.test.js28
-rw-r--r--packages/astro/test/fixtures/astro-throw/snowpack.config.json3
-rw-r--r--packages/astro/test/fixtures/astro-throw/src/pages/index.astro13
7 files changed, 81 insertions, 7 deletions
diff --git a/.changeset/nervous-pillows-sing.md b/.changeset/nervous-pillows-sing.md
new file mode 100644
index 000000000..851749d0a
--- /dev/null
+++ b/.changeset/nervous-pillows-sing.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Improve error handling within `.astro` files (#526)
diff --git a/packages/astro/src/build.ts b/packages/astro/src/build.ts
index fbe990169..81d86ddb4 100644
--- a/packages/astro/src/build.ts
+++ b/packages/astro/src/build.ts
@@ -9,7 +9,7 @@ import { performance } from 'perf_hooks';
import eslexer from 'es-module-lexer';
import cheerio from 'cheerio';
import del from 'del';
-import { bold, green, yellow } from 'kleur/colors';
+import { bold, green, yellow, red, dim, underline } from 'kleur/colors';
import mime from 'mime';
import glob from 'tiny-glob';
import { bundleCSS } from './build/bundle/css.js';
@@ -71,10 +71,11 @@ export async function build(astroConfig: AstroConfig, logging: LogOptions = defa
timer.build = performance.now();
const pages = await allPages(pagesRoot);
info(logging, 'build', yellow('! building pages...'));
- await Promise.all(
- pages.map(async (filepath) => {
+ try {
+ await Promise.all(
+ pages.map((filepath) => {
const buildPage = getPageType(filepath) === 'collection' ? buildCollectionPage : buildStaticPage;
- await buildPage({
+ return buildPage({
astroConfig,
buildState,
filepath,
@@ -85,7 +86,25 @@ export async function build(astroConfig: AstroConfig, logging: LogOptions = defa
site: astroConfig.buildOptions.site,
});
})
- );
+ )
+ } catch (e) {
+ if (e.filename) {
+ let stack = e.stack.replace(/Object\.__render \(/gm, '').replace(/\/_astro\/(.+)\.astro\.js\:\d+\:\d+\)/gm, (_: string, $1: string) => 'file://' + fileURLToPath(projectRoot) + $1 + '.astro').split('\n');
+ stack.splice(1, 0, ` at file://${e.filename}`)
+ stack = stack.join('\n')
+
+ error(logging, 'build', `${red(`Unable to render ${underline(e.filename.replace(fileURLToPath(projectRoot), ''))}`)}
+
+${stack}
+`);
+ } else {
+ error(logging, 'build', e);
+ }
+ error(logging, 'build', red('✕ building pages failed!'));
+
+ await runtime.shutdown();
+ return 1;
+ }
info(logging, 'build', green('✔'), 'pages built.');
debug(logging, 'build', `built pages [${stopTimer(timer.build)}]`);
diff --git a/packages/astro/src/build/page.ts b/packages/astro/src/build/page.ts
index e19cf097b..d7e8e276c 100644
--- a/packages/astro/src/build/page.ts
+++ b/packages/astro/src/build/page.ts
@@ -3,6 +3,7 @@ import type { AstroRuntime, LoadResult } from '../runtime';
import type { LogOptions } from '../logger';
import path from 'path';
import { generateRSS } from './rss.js';
+import { fileURLToPath } from 'url';
interface PageBuildOptions {
astroConfig: AstroConfig;
@@ -92,7 +93,12 @@ export async function buildStaticPage({ astroConfig, buildState, filepath, runti
const { pages: pagesRoot } = astroConfig;
const url = filepath.pathname.replace(pagesRoot.pathname, '/').replace(/(index)?\.(astro|md)$/, '');
const result = await runtime.load(url);
- if (result.statusCode !== 200) throw new Error((result as any).error);
+ if (result.statusCode !== 200) {
+ let err = (result as any).error;
+ if (!(err instanceof Error)) err = new Error(err);
+ err.filename = fileURLToPath(filepath);
+ throw err;
+ }
const outFile = path.posix.join(url, '/index.html');
buildState[outFile] = {
srcPath: filepath,
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 8e1edf763..843ecc428 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -277,7 +277,7 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
if (module) {
const parseOptions: babelParser.ParserOptions = {
sourceType: 'module',
- plugins: ['jsx', 'typescript', 'topLevelAwait'],
+ plugins: ['jsx', 'typescript', 'topLevelAwait', 'throwExpressions'],
};
let parseResult;
try {
diff --git a/packages/astro/test/astro-throw.test.js b/packages/astro/test/astro-throw.test.js
new file mode 100644
index 000000000..702828187
--- /dev/null
+++ b/packages/astro/test/astro-throw.test.js
@@ -0,0 +1,28 @@
+import { suite } from 'uvu';
+import * as assert from 'uvu/assert';
+import { doc } from './test-utils.js';
+import { setup, setupBuild } from './helpers.js';
+
+const Throwable = suite('Throw test');
+
+setup(Throwable, './fixtures/astro-throw', {
+ runtimeOptions: {
+ mode: 'development',
+ },
+});
+setupBuild(Throwable, './fixtures/astro-throw');
+
+Throwable('Can throw an error from an `.astro` file', async ({ runtime }) => {
+ const result = await runtime.load('/');
+ assert.equal(result.statusCode, 500);
+ assert.equal(result.error.message, 'Oops!');
+});
+
+Throwable('Does not complete build when Error is thrown', async ({ build }) => {
+ await build().catch(e => {
+ assert.ok(e, 'Build threw');
+ })
+});
+
+
+Throwable.run();
diff --git a/packages/astro/test/fixtures/astro-throw/snowpack.config.json b/packages/astro/test/fixtures/astro-throw/snowpack.config.json
new file mode 100644
index 000000000..8f034781d
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-throw/snowpack.config.json
@@ -0,0 +1,3 @@
+{
+ "workspaceRoot": "../../../../../"
+}
diff --git a/packages/astro/test/fixtures/astro-throw/src/pages/index.astro b/packages/astro/test/fixtures/astro-throw/src/pages/index.astro
new file mode 100644
index 000000000..69e9fcd30
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-throw/src/pages/index.astro
@@ -0,0 +1,13 @@
+---
+let title = 'My App'
+
+throw new Error('Oops!')
+---
+
+<html>
+ <head>
+ </head>
+ <body>
+ <h1>I will never render.</h1>
+ </body>
+</html>