Skip to content

Commit

Permalink
feat(astro): Add enabled option to Astro integration options (#10007)
Browse files Browse the repository at this point in the history
Add a top level `enabled` option to the Astro integration
options. This option can be used to globally enable/disable all Sentry
features, either for client or server separately or for both sides
simultaneously.

* Disabeling either side will avoid the respective SDK code being
injected into the bundles.
* If both sides are disabled, source maps will not be generated and
uploaded.
* If both or just the server side is disabled, the Sentry middleware
won't be added.
* Obviously, this options defaults to `true`
  • Loading branch information
Lms24 authored and anonrig committed Jan 3, 2024
1 parent 2a4bf1d commit b5c3763
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 25 deletions.
53 changes: 31 additions & 22 deletions packages/astro/src/integration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => {
// Will revisit this later.
const env = process.env;

const uploadOptions = options.sourceMapsUploadOptions || {};
const sdkEnabled = {
client: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.client ?? true,
server: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.server ?? true,
};

const shouldUploadSourcemaps = uploadOptions?.enabled ?? true;
const sourceMapsNeeded = sdkEnabled.client || sdkEnabled.server;
const uploadOptions = options.sourceMapsUploadOptions || {};
const shouldUploadSourcemaps = (sourceMapsNeeded && uploadOptions?.enabled) ?? true;

// We don't need to check for AUTH_TOKEN here, because the plugin will pick it up from the env
if (shouldUploadSourcemaps && command !== 'dev') {
Expand All @@ -51,31 +56,35 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => {
});
}

const pathToClientInit = options.clientInitPath
? path.resolve(options.clientInitPath)
: findDefaultSdkInitFile('client');
const pathToServerInit = options.serverInitPath
? path.resolve(options.serverInitPath)
: findDefaultSdkInitFile('server');

if (pathToClientInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`);
injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit));
} else {
options.debug && console.log('[sentry-astro] Using default client init.');
injectScript('page', buildClientSnippet(options || {}));
if (sdkEnabled.client) {
const pathToClientInit = options.clientInitPath
? path.resolve(options.clientInitPath)
: findDefaultSdkInitFile('client');

if (pathToClientInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`);
injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit));
} else {
options.debug && console.log('[sentry-astro] Using default client init.');
injectScript('page', buildClientSnippet(options || {}));
}
}

if (pathToServerInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`);
injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit));
} else {
options.debug && console.log('[sentry-astro] Using default server init.');
injectScript('page-ssr', buildServerSnippet(options || {}));
if (sdkEnabled.server) {
const pathToServerInit = options.serverInitPath
? path.resolve(options.serverInitPath)
: findDefaultSdkInitFile('server');
if (pathToServerInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`);
injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit));
} else {
options.debug && console.log('[sentry-astro] Using default server init.');
injectScript('page-ssr', buildServerSnippet(options || {}));
}
}

const isSSR = config && (config.output === 'server' || config.output === 'hybrid');
const shouldAddMiddleware = options.autoInstrumentation?.requestHandler !== false;
const shouldAddMiddleware = sdkEnabled.server && options.autoInstrumentation?.requestHandler !== false;

// Guarding calling the addMiddleware function because it was only introduced in [email protected]
// Users on older versions of astro will need to add the middleware manually.
Expand Down
23 changes: 22 additions & 1 deletion packages/astro/src/integration/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ type InstrumentationOptions = {
};
};

type SdkEnabledOptions = {
/**
* Controls if the Sentry SDK is enabled or not.
*
* You can either set a boolean value to enable/disable the SDK for both client and server,
* or pass an object with `client` and `server` properties to enable/disable the SDK.
*
* If the SDK is disabled, no data will be caught or sent to Sentry. In this case, also no
* Sentry code will be added to your bundle.
*
* @default true - the SDK is enabled by default for both, client and server.
*/
enabled?:
| boolean
| {
client?: boolean;
server?: boolean;
};
};

/**
* A subset of Sentry SDK options that can be set via the `sentryAstro` integration.
* Some options (e.g. integrations) are set by default and cannot be changed here.
Expand All @@ -119,4 +139,5 @@ export type SentryOptions = SdkInitPaths &
Pick<Options, 'dsn' | 'release' | 'environment' | 'sampleRate' | 'tracesSampleRate' | 'debug'> &
Pick<BrowserOptions, 'replaysSessionSampleRate' | 'replaysOnErrorSampleRate'> &
SourceMapsOptions &
InstrumentationOptions;
InstrumentationOptions &
SdkEnabledOptions;
71 changes: 69 additions & 2 deletions packages/astro/test/integration/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,21 @@ describe('sentryAstro integration', () => {
expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0);
});

it('injects client and server init scripts', async () => {
const integration = sentryAstro({});
it("doesn't add the plugin or enable source maps if the SDK is disabled", async () => {
const integration = sentryAstro({
enabled: false,
});

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, config });

expect(updateConfig).toHaveBeenCalledTimes(0);
expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0);
});

it.each([{}, { enabled: true }])('injects client and server init scripts', async options => {
const integration = sentryAstro(options);

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
Expand All @@ -180,6 +193,41 @@ describe('sentryAstro integration', () => {
expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init'));
});

it("doesn't inject client init script if `enabled.client` is `false`", async () => {
const integration = sentryAstro({ enabled: { client: false } });

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, config });

expect(injectScript).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init'));
});

it("doesn't inject server init script if `enabled.server` is `false`", async () => {
const integration = sentryAstro({ enabled: { server: false } });

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, config });

expect(injectScript).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining('Sentry.init'));
});

it.each([false, { client: false, server: false }])(
"doesn't inject any init script if `enabled` is generally false (`%s`)",
async enabled => {
const integration = sentryAstro({ enabled });

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, config });

expect(injectScript).toHaveBeenCalledTimes(0);
},
);

it('injects client and server init scripts from custom paths', async () => {
const integration = sentryAstro({
clientInitPath: 'my-client-init-path.js',
Expand Down Expand Up @@ -278,4 +326,23 @@ describe('sentryAstro integration', () => {
expect(updateConfig).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledTimes(2);
});

it("doesn't add middleware if the SDK is disabled", () => {
const integration = sentryAstro({ enabled: false });
const addMiddleware = vi.fn();
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
integration.hooks['astro:config:setup']({
// @ts-expect-error - we only need to pass what we actually use
config: { output: 'server' },
addMiddleware,
updateConfig,
injectScript,
});

expect(addMiddleware).toHaveBeenCalledTimes(0);
});
});

0 comments on commit b5c3763

Please sign in to comment.