From 2a5786419599b8674473c699300172b9aacbae2e Mon Sep 17 00:00:00 2001 From: Erika <3019731+Princesseuh@users.noreply.github.com> Date: Wed, 4 Jan 2023 13:31:28 +0100 Subject: [PATCH] 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 --- .changeset/shaggy-melons-tap.md | 5 +++++ packages/astro/src/core/build/generate.ts | 12 +++++++++- packages/astro/src/core/errors/utils.ts | 15 ++++++++++--- .../astro/test/error-build-location.test.js | 22 +++++++++++++++++++ .../error-build-location/astro.config.mjs | 3 +++ .../error-build-location/package.json | 15 +++++++++++++ .../error-build-location/src/env.d.ts | 1 + .../src/pages/index.astro | 3 +++ pnpm-lock.yaml | 6 +++++ 9 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 .changeset/shaggy-melons-tap.md create mode 100644 packages/astro/test/error-build-location.test.js create mode 100644 packages/astro/test/fixtures/error-build-location/astro.config.mjs create mode 100644 packages/astro/test/fixtures/error-build-location/package.json create mode 100644 packages/astro/test/fixtures/error-build-location/src/env.d.ts create mode 100644 packages/astro/test/fixtures/error-build-location/src/pages/index.astro diff --git a/.changeset/shaggy-melons-tap.md b/.changeset/shaggy-melons-tap.md new file mode 100644 index 000000000..f991e3168 --- /dev/null +++ b/.changeset/shaggy-melons-tap.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Add error location during build for user-generated errors diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 968e1b648..b4c8ee8f0 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -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; diff --git a/packages/astro/src/core/errors/utils.ts b/packages/astro/src/core/errors/utils.ts index c2c71a079..0d503b09d 100644 --- a/packages/astro/src/core/errors/utils.ts +++ b/packages/astro/src/core/errors/utils.ts @@ -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) { diff --git a/packages/astro/test/error-build-location.test.js b/packages/astro/test/error-build-location.test.js new file mode 100644 index 000000000..01de98b5a --- /dev/null +++ b/packages/astro/test/error-build-location.test.js @@ -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'); + }); +}); diff --git a/packages/astro/test/fixtures/error-build-location/astro.config.mjs b/packages/astro/test/fixtures/error-build-location/astro.config.mjs new file mode 100644 index 000000000..86dbfb924 --- /dev/null +++ b/packages/astro/test/fixtures/error-build-location/astro.config.mjs @@ -0,0 +1,3 @@ +import { defineConfig } from 'astro/config'; + +export default defineConfig({}); diff --git a/packages/astro/test/fixtures/error-build-location/package.json b/packages/astro/test/fixtures/error-build-location/package.json new file mode 100644 index 000000000..2366e345e --- /dev/null +++ b/packages/astro/test/fixtures/error-build-location/package.json @@ -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:*" + } +} diff --git a/packages/astro/test/fixtures/error-build-location/src/env.d.ts b/packages/astro/test/fixtures/error-build-location/src/env.d.ts new file mode 100644 index 000000000..f964fe0cf --- /dev/null +++ b/packages/astro/test/fixtures/error-build-location/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/astro/test/fixtures/error-build-location/src/pages/index.astro b/packages/astro/test/fixtures/error-build-location/src/pages/index.astro new file mode 100644 index 000000000..932b255ea --- /dev/null +++ b/packages/astro/test/fixtures/error-build-location/src/pages/index.astro @@ -0,0 +1,3 @@ +--- +throw new Error("I'm happening in build!") +--- diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f615035e7..5f4402cd9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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:*