Skip to content

Commit

Permalink
feat(solidstart): Add sentrySolidStartVite plugin to simplify sourc…
Browse files Browse the repository at this point in the history
…e maps upload
  • Loading branch information
andreiborza committed Aug 28, 2024
1 parent bf24740 commit f55e5bd
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 48 deletions.
6 changes: 3 additions & 3 deletions packages/solidstart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ render(

## Uploading Source Maps

To upload source maps, add the `sentrySolidStart` plugin from `@sentry/solidstart` to your `app.config.ts` and configure
To upload source maps, add the `sentrySolidStartVite` plugin from `@sentry/solidstart` to your `app.config.ts` and configure
an auth token. Auth tokens can be passed to the plugin explicitly with the `authToken` option, with a
`SENTRY_AUTH_TOKEN` environment variable, or with an `.env.sentry-build-plugin` file in the working directory when
building your project. We recommend you add the auth token to your CI/CD environment as an environment variable.
Expand All @@ -170,14 +170,14 @@ Learn more about configuring the plugin in our
```typescript
// app.config.ts
import { defineConfig } from '@solidjs/start/config';
import { sentrySolidStart } from '@sentry/solidstart';
import { sentrySolidStartVite } from '@sentry/solidstart';

export default defineConfig({
// ...

vite: {
plugins: [
sentrySolidStart({
sentrySolidStartVite({
sourceMapsUploadOptions: {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
Expand Down
44 changes: 1 addition & 43 deletions packages/solidstart/src/vite/index.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1 @@
import { sentryVitePlugin } from '@sentry/vite-plugin';
import type { Plugin } from 'vite';
import type { SentrySolidStartPluginOptions } from './types';

export const sentrySolidStart = (options: SentrySolidStartPluginOptions): Plugin[] => {
const sourceMapsUploadOptions = options.sourceMapsUploadOptions || {};

const sentryPlugins: Plugin[] = [];

if (process.env.NODE_ENV !== 'development') {
sentryPlugins.push(
{
name: 'sentry-solidstart-plugin-config',
config() {
return {
build: {
sourcemap: true,
},
};
},
},
sentryVitePlugin({
org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG,
project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT,
authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN,
telemetry: sourceMapsUploadOptions.telemetry ?? true,
sourcemaps: {
assets: sourceMapsUploadOptions.sourcemaps?.assets ?? undefined,
ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined,
filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
},
_metaOptions: {
telemetry: {
metaFramework: 'solidstart',
},
},
debug: options.debug ?? false,
}),
);
}

return sentryPlugins;
};
export * from './sentrySolidStartVite';
18 changes: 18 additions & 0 deletions packages/solidstart/src/vite/sentrySolidStartVite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Plugin } from 'vite';
import { makeSourceMapsVitePlugin } from './sourceMaps';
import type { SentrySolidStartPluginOptions } from './types';

/**
* Various Sentry vite plugins to be used for SolidStart.
*/
export const sentrySolidStartVite = (options: SentrySolidStartPluginOptions): Plugin[] => {
const sentryPlugins: Plugin[] = [];

if (process.env.NODE_ENV !== 'development') {
if (options.sourceMapsUploadOptions?.enabled ?? true) {
sentryPlugins.push(...makeSourceMapsVitePlugin({ ...options.sourceMapsUploadOptions, debug: options.debug }));
}
}

return sentryPlugins;
};
56 changes: 56 additions & 0 deletions packages/solidstart/src/vite/sourceMaps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { sentryVitePlugin } from '@sentry/vite-plugin';
import type { Plugin } from 'vite';
import type { SourceMapsOptions } from './types';

/**
* A Sentry plugin for SolidStart to enable source maps and use
* @sentry/vite-plugin to automatically upload source maps to Sentry.
* @param {SourceMapsOptions} options
*/
export function makeSourceMapsVitePlugin(options: SourceMapsOptions): Plugin[] {
return [
{
name: 'sentry-solidstart-source-maps',
apply: 'build',
enforce: 'post',
config(config) {
const sourceMapsPreviouslyNotEnabled = !config.build?.sourcemap;
if (options.debug && sourceMapsPreviouslyNotEnabled) {
// eslint-disable-next-line no-console
console.log('[Sentry SolidStart Plugin] Enabling source map generation');
if (!options.sourcemaps?.filesToDeleteAfterUpload) {
// eslint-disable-next-line no-console
console.warn(
`[Sentry SolidStart PLugin] We recommend setting the \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload\` option to clean up source maps after uploading.
[Sentry SolidStart Plugin] Otherwise, source maps might be deployed to production, depending on your configuration`,
);
}
}
return {
...config,
build: {
...config.build,
sourcemap: true,
},
};
},
},
...sentryVitePlugin({
org: options.org ?? process.env.SENTRY_ORG,
project: options.project ?? process.env.SENTRY_PROJECT,
authToken: options.authToken ?? process.env.SENTRY_AUTH_TOKEN,
telemetry: options.telemetry ?? true,
sourcemaps: {
assets: options.sourcemaps?.assets ?? undefined,
ignore: options.sourcemaps?.ignore ?? undefined,
filesToDeleteAfterUpload: options.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
},
_metaOptions: {
telemetry: {
metaFramework: 'solidstart',
},
},
debug: options.debug ?? false,
}),
];
}
10 changes: 8 additions & 2 deletions packages/solidstart/src/vite/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type SourceMapsOptions = {
export type SourceMapsOptions = {
/**
* If this flag is `true`, and an auth token is detected, the Sentry SDK will
* automatically generate and upload source maps to Sentry during a production build.
Expand Down Expand Up @@ -69,6 +69,12 @@ type SourceMapsOptions = {
*/
filesToDeleteAfterUpload?: string | Array<string>;
};

/**
* Enable debug functionality of the SDK during build-time.
* Enabling this will give you logs about source maps.
*/
debug?: boolean;
};

/**
Expand All @@ -82,7 +88,7 @@ export type SentrySolidStartPluginOptions = {

/**
* Enable debug functionality of the SDK during build-time.
* Enabling this will give you, for example, logs about source maps.
* Enabling this will give you, for example logs about source maps.
*/
debug?: boolean;
};
53 changes: 53 additions & 0 deletions packages/solidstart/test/vite/sentrySolidStartVite.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { Plugin } from 'vite';
import { describe, expect, it, vi } from 'vitest';
import { sentrySolidStartVite } from '../../src/vite/sentrySolidStartVite';

vi.spyOn(console, 'log').mockImplementation(() => {
/* noop */
});
vi.spyOn(console, 'warn').mockImplementation(() => {
/* noop */
});

function getSentrySolidStartVitePlugins(options?: Parameters<typeof sentrySolidStartVite>[0]): Plugin[] {
return sentrySolidStartVite({
sourceMapsUploadOptions: {
authToken: 'token',
org: 'org',
project: 'project',
...options?.sourceMapsUploadOptions,
},
...options,
});
}

describe('sentrySolidStartVite()', () => {
it('returns an array of vite plugins', () => {
const plugins = getSentrySolidStartVitePlugins();
const names = plugins.map(plugin => plugin.name);
expect(names).toEqual([
'sentry-solidstart-source-maps',
'sentry-telemetry-plugin',
'sentry-vite-release-injection-plugin',
'sentry-debug-id-upload-plugin',
'sentry-vite-debug-id-injection-plugin',
'sentry-file-deletion-plugin',
'sentry-vite-debug-id-upload-plugin',
]);
});

it("returns an empty array if source maps upload isn't enabled", () => {
const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: false } });
expect(plugins).toHaveLength(0);
});

it('returns an empty array if `NODE_ENV` is development', async () => {
const previousEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';

const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: true } });
expect(plugins).toHaveLength(0);

process.env.NODE_ENV = previousEnv;
});
});
58 changes: 58 additions & 0 deletions packages/solidstart/test/vite/sourceMaps.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { makeSourceMapsVitePlugin } from '../../src/vite/sourceMaps';
import * as sourceMaps from '../../src/vite/sourceMaps';

const mockedSentryVitePlugin = {
name: 'sentry-vite-debug-id-upload-plugin',
writeBundle: vi.fn(),
};

vi.mock('@sentry/vite-plugin', async () => {
const original = (await vi.importActual('@sentry/vite-plugin')) as any;

return {
...original,
sentryVitePlugin: () => [mockedSentryVitePlugin],
};
});

beforeEach(() => {
vi.clearAllMocks();
});

describe('makeSourceMapsVitePlugin()', () => {
it('returns a plugin to set `sourcemaps` to `true`', async () => {
const [sourceMapsConfigPlugin, sentryVitePlugin] = makeSourceMapsVitePlugin({});

expect(sourceMapsConfigPlugin?.name).toEqual('sentry-solidstart-source-maps');
expect(sourceMapsConfigPlugin?.apply).toEqual('build');
expect(sourceMapsConfigPlugin?.enforce).toEqual('post');
expect(sourceMapsConfigPlugin?.config).toEqual(expect.any(Function));

expect(sentryVitePlugin).toEqual(mockedSentryVitePlugin);
});

it('passes user-specified vite plugin options to vite plugin plugin', async () => {
const makePluginSpy = vi.spyOn(sourceMaps, 'makeSourceMapsVitePlugin');

makeSourceMapsVitePlugin({
org: 'my-org',
authToken: 'my-token',
sourcemaps: {
assets: ['foo/*.js'],
ignore: ['bar/*.js'],
filesToDeleteAfterUpload: ['baz/*.js'],
},
});

expect(makePluginSpy).toHaveBeenCalledWith({
org: 'my-org',
authToken: 'my-token',
sourcemaps: {
assets: ['foo/*.js'],
ignore: ['bar/*.js'],
filesToDeleteAfterUpload: ['baz/*.js'],
},
});
});
});

0 comments on commit f55e5bd

Please sign in to comment.