Add file location to errors in build (#5743)

* feat(errors): Add file location where error happened during build for user-generated errors

* chore: changeset

* fix(errors): Only add information if the error is in a compatible shape

* feat(errors): Add hint to throw Error objects instead of other types for better information

* test(errors): Add test to make sure errors in build have the error location

* chore(lockfile): Update lockfile

* chore: misc text fixes
This commit is contained in:
Erika 2023-01-04 13:31:28 +01:00 committed by GitHub
parent 000d3e6940
commit 2a57864195
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 4 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Add error location during build for user-generated errors

View file

@ -10,6 +10,7 @@ import type {
ComponentInstance,
EndpointHandler,
RouteType,
SSRError,
SSRLoadedRenderer,
} from '../../@types/astro';
import { getContentPaths } from '../../content/index.js';
@ -22,6 +23,7 @@ import {
import { runHookBuildGenerated } from '../../integrations/index.js';
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { call as callEndpoint, throwIfRedirectNotAllowed } from '../endpoint/index.js';
import { AstroError } from '../errors/index.js';
import { debug, info } from '../logger/core.js';
import { createEnvironment, createRenderContext, renderPage } from '../render/index.js';
import { callGetStaticPaths } from '../render/route-cache.js';
@ -397,7 +399,15 @@ async function generatePath(
encoding = result.encoding;
}
} else {
const response = await renderPage(mod, ctx, env);
let response: Response;
try {
response = await renderPage(mod, ctx, env);
} catch (err) {
if (!AstroError.is(err) && !(err as SSRError).id && typeof err === 'object') {
(err as SSRError).id = pageData.component;
}
throw err;
}
throwIfRedirectNotAllowed(response, opts.settings.config);
// If there's no body, do nothing
if (!response.body) return;

View file

@ -1,4 +1,5 @@
import { DiagnosticCode } from '@astrojs/compiler/shared/diagnostics.js';
import type { SSRError } from '../../@types/astro.js';
import { AstroErrorCodes, AstroErrorData } from './errors-data.js';
/**
@ -72,9 +73,17 @@ function getLineOffsets(text: string) {
/** Coalesce any throw variable to an Error instance. */
export function createSafeError(err: any): Error {
return err instanceof Error || (err && err.name && err.message)
? err
: new Error(JSON.stringify(err));
if (err instanceof Error || (err && err.name && err.message)) {
return err;
} else {
const error = new Error(JSON.stringify(err));
(
error as SSRError
).hint = `To get as much information as possible from your errors, make sure to throw Error objects instead of \`${typeof err}\`. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error for more information.`;
return error;
}
}
export function normalizeLF(code: string) {

View file

@ -0,0 +1,22 @@
import { expect } from 'chai';
import { loadFixture } from './test-utils.js';
describe('Errors information in build', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
it('includes the file where the error happened', async () => {
fixture = await loadFixture({
root: './fixtures/error-build-location',
});
let errorContent;
try {
await fixture.build();
} catch (e) {
errorContent = e;
}
expect(errorContent.id).to.equal('src/pages/index.astro');
});
});

View file

@ -0,0 +1,3 @@
import { defineConfig } from 'astro/config';
export default defineConfig({});

View file

@ -0,0 +1,15 @@
{
"name": "@test/error-non-error",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "workspace:*"
}
}

View file

@ -0,0 +1 @@
/// <reference types="astro/client" />

View file

@ -0,0 +1,3 @@
---
throw new Error("I'm happening in build!")
---

View file

@ -1781,6 +1781,12 @@ importers:
dependencies:
astro: link:../../..
packages/astro/test/fixtures/error-build-location:
specifiers:
astro: workspace:*
dependencies:
astro: link:../../..
packages/astro/test/fixtures/error-non-error:
specifiers:
astro: workspace:*