Skip to content

fix(astro): Adjust Vite plugin config to upload server source maps #9541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions packages/astro/src/integration/index.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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

Expand All @@ -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,
}),
],
},
Expand Down Expand Up @@ -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/**/*';
}
48 changes: 35 additions & 13 deletions packages/astro/test/integration/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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({
Expand All @@ -51,32 +56,52 @@ 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/**/*'],
},
});
});

it("doesn't enable source maps if `sourceMapsUploadOptions.enabled` is `false`", async () => {
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);
});

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'));
Expand All @@ -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'));
Expand Down