diff --git a/packages/astro/src/integration/index.ts b/packages/astro/src/integration/index.ts index 0432fb8108d3..caaf6a073380 100644 --- a/packages/astro/src/integration/index.ts +++ b/packages/astro/src/integration/index.ts @@ -1,6 +1,6 @@ /* eslint-disable no-console */ import { sentryVitePlugin } from '@sentry/vite-plugin'; -import type { AstroIntegration } from 'astro'; +import type { AstroConfig, AstroIntegration } from 'astro'; import * as fs from 'fs'; import * as path from 'path'; @@ -13,7 +13,8 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => { return { name: PKG_NAME, hooks: { - 'astro:config:setup': async ({ updateConfig, injectScript }) => { + // eslint-disable-next-line complexity + 'astro:config:setup': async ({ updateConfig, injectScript, config }) => { // The third param here enables loading of all env vars, regardless of prefix // see: https://main.vitejs.dev/config/#using-environment-variables-in-config @@ -40,6 +41,10 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => { project: uploadOptions.project ?? env.SENTRY_PROJECT, authToken: uploadOptions.authToken ?? env.SENTRY_AUTH_TOKEN, telemetry: uploadOptions.telemetry ?? true, + sourcemaps: { + assets: [getSourcemapsAssetsGlob(config)], + }, + debug: options.debug ?? false, }), ], }, @@ -79,3 +84,17 @@ function findDefaultSdkInitFile(type: 'server' | 'client'): string | undefined { .map(ext => path.resolve(path.join(process.cwd(), `sentry.${type}.config.${ext}`))) .find(filename => fs.existsSync(filename)); } + +function getSourcemapsAssetsGlob(config: AstroConfig): string { + // paths are stored as "file://" URLs + const outDirPathname = config.outDir && path.resolve(config.outDir.pathname); + const rootDirName = path.resolve((config.root && config.root.pathname) || process.cwd()); + + if (outDirPathname) { + const relativePath = path.relative(rootDirName, outDirPathname); + return `${relativePath}/**/*`; + } + + // fallback to default output dir + return 'dist/**/*'; +} diff --git a/packages/astro/test/integration/index.test.ts b/packages/astro/test/integration/index.test.ts index fe876023c9c4..2f98fc991065 100644 --- a/packages/astro/test/integration/index.test.ts +++ b/packages/astro/test/integration/index.test.ts @@ -14,6 +14,13 @@ process.env = { SENTRY_AUTH_TOKEN: 'my-token', }; +const updateConfig = vi.fn(); +const injectScript = vi.fn(); +const config = { + root: new URL('file://path/to/project'), + outDir: new URL('file://path/to/project/out'), +}; + describe('sentryAstro integration', () => { afterEach(() => { vi.clearAllMocks(); @@ -28,12 +35,10 @@ describe('sentryAstro integration', () => { const integration = sentryAstro({ sourceMapsUploadOptions: { enabled: true, org: 'my-org', project: 'my-project', telemetry: false }, }); - const updateConfig = vi.fn(); - const injectScript = vi.fn(); expect(integration.hooks['astro:config:setup']).toBeDefined(); // @ts-expect-error - the hook exists and we only need to pass what we actually use - await integration.hooks['astro:config:setup']({ updateConfig, injectScript }); + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); expect(updateConfig).toHaveBeenCalledTimes(1); expect(updateConfig).toHaveBeenCalledWith({ @@ -51,6 +56,30 @@ describe('sentryAstro integration', () => { org: 'my-org', project: 'my-project', telemetry: false, + debug: false, + sourcemaps: { + assets: ['out/**/*'], + }, + }); + }); + + it('falls back to default output dir, if out and root dir are not available', async () => { + const integration = sentryAstro({ + sourceMapsUploadOptions: { enabled: true, org: 'my-org', project: 'my-project', telemetry: false }, + }); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config: {} }); + + expect(sentryVitePluginSpy).toHaveBeenCalledTimes(1); + expect(sentryVitePluginSpy).toHaveBeenCalledWith({ + authToken: 'my-token', + org: 'my-org', + project: 'my-project', + telemetry: false, + debug: false, + sourcemaps: { + assets: ['dist/**/*'], + }, }); }); @@ -58,12 +87,10 @@ describe('sentryAstro integration', () => { const integration = sentryAstro({ sourceMapsUploadOptions: { enabled: false }, }); - const updateConfig = vi.fn(); - const injectScript = vi.fn(); expect(integration.hooks['astro:config:setup']).toBeDefined(); // @ts-expect-error - the hook exists and we only need to pass what we actually use - await integration.hooks['astro:config:setup']({ updateConfig, injectScript }); + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); expect(updateConfig).toHaveBeenCalledTimes(0); expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0); @@ -71,12 +98,10 @@ describe('sentryAstro integration', () => { it('injects client and server init scripts', async () => { const integration = sentryAstro({}); - const updateConfig = vi.fn(); - const injectScript = vi.fn(); expect(integration.hooks['astro:config:setup']).toBeDefined(); // @ts-expect-error - the hook exists and we only need to pass what we actually use - await integration.hooks['astro:config:setup']({ updateConfig, injectScript }); + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); expect(injectScript).toHaveBeenCalledTimes(2); expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining('Sentry.init')); @@ -89,12 +114,9 @@ describe('sentryAstro integration', () => { serverInitPath: 'my-server-init-path.js', }); - const updateConfig = vi.fn(); - const injectScript = vi.fn(); - expect(integration.hooks['astro:config:setup']).toBeDefined(); // @ts-expect-error - the hook exists and we only need to pass what we actually use - await integration.hooks['astro:config:setup']({ updateConfig, injectScript }); + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); expect(injectScript).toHaveBeenCalledTimes(2); expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining('my-client-init-path.js'));