Skip to content

Commit f55e5bd

Browse files
committed
feat(solidstart): Add sentrySolidStartVite plugin to simplify source maps upload
1 parent bf24740 commit f55e5bd

File tree

7 files changed

+197
-48
lines changed

7 files changed

+197
-48
lines changed

packages/solidstart/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ render(
159159

160160
## Uploading Source Maps
161161

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

175175
export default defineConfig({
176176
// ...
177177

178178
vite: {
179179
plugins: [
180-
sentrySolidStart({
180+
sentrySolidStartVite({
181181
sourceMapsUploadOptions: {
182182
org: process.env.SENTRY_ORG,
183183
project: process.env.SENTRY_PROJECT,

packages/solidstart/src/vite/index.ts

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1 @@
1-
import { sentryVitePlugin } from '@sentry/vite-plugin';
2-
import type { Plugin } from 'vite';
3-
import type { SentrySolidStartPluginOptions } from './types';
4-
5-
export const sentrySolidStart = (options: SentrySolidStartPluginOptions): Plugin[] => {
6-
const sourceMapsUploadOptions = options.sourceMapsUploadOptions || {};
7-
8-
const sentryPlugins: Plugin[] = [];
9-
10-
if (process.env.NODE_ENV !== 'development') {
11-
sentryPlugins.push(
12-
{
13-
name: 'sentry-solidstart-plugin-config',
14-
config() {
15-
return {
16-
build: {
17-
sourcemap: true,
18-
},
19-
};
20-
},
21-
},
22-
sentryVitePlugin({
23-
org: sourceMapsUploadOptions.org ?? process.env.SENTRY_ORG,
24-
project: sourceMapsUploadOptions.project ?? process.env.SENTRY_PROJECT,
25-
authToken: sourceMapsUploadOptions.authToken ?? process.env.SENTRY_AUTH_TOKEN,
26-
telemetry: sourceMapsUploadOptions.telemetry ?? true,
27-
sourcemaps: {
28-
assets: sourceMapsUploadOptions.sourcemaps?.assets ?? undefined,
29-
ignore: sourceMapsUploadOptions.sourcemaps?.ignore ?? undefined,
30-
filesToDeleteAfterUpload: sourceMapsUploadOptions.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
31-
},
32-
_metaOptions: {
33-
telemetry: {
34-
metaFramework: 'solidstart',
35-
},
36-
},
37-
debug: options.debug ?? false,
38-
}),
39-
);
40-
}
41-
42-
return sentryPlugins;
43-
};
1+
export * from './sentrySolidStartVite';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Plugin } from 'vite';
2+
import { makeSourceMapsVitePlugin } from './sourceMaps';
3+
import type { SentrySolidStartPluginOptions } from './types';
4+
5+
/**
6+
* Various Sentry vite plugins to be used for SolidStart.
7+
*/
8+
export const sentrySolidStartVite = (options: SentrySolidStartPluginOptions): Plugin[] => {
9+
const sentryPlugins: Plugin[] = [];
10+
11+
if (process.env.NODE_ENV !== 'development') {
12+
if (options.sourceMapsUploadOptions?.enabled ?? true) {
13+
sentryPlugins.push(...makeSourceMapsVitePlugin({ ...options.sourceMapsUploadOptions, debug: options.debug }));
14+
}
15+
}
16+
17+
return sentryPlugins;
18+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { sentryVitePlugin } from '@sentry/vite-plugin';
2+
import type { Plugin } from 'vite';
3+
import type { SourceMapsOptions } from './types';
4+
5+
/**
6+
* A Sentry plugin for SolidStart to enable source maps and use
7+
* @sentry/vite-plugin to automatically upload source maps to Sentry.
8+
* @param {SourceMapsOptions} options
9+
*/
10+
export function makeSourceMapsVitePlugin(options: SourceMapsOptions): Plugin[] {
11+
return [
12+
{
13+
name: 'sentry-solidstart-source-maps',
14+
apply: 'build',
15+
enforce: 'post',
16+
config(config) {
17+
const sourceMapsPreviouslyNotEnabled = !config.build?.sourcemap;
18+
if (options.debug && sourceMapsPreviouslyNotEnabled) {
19+
// eslint-disable-next-line no-console
20+
console.log('[Sentry SolidStart Plugin] Enabling source map generation');
21+
if (!options.sourcemaps?.filesToDeleteAfterUpload) {
22+
// eslint-disable-next-line no-console
23+
console.warn(
24+
`[Sentry SolidStart PLugin] We recommend setting the \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload\` option to clean up source maps after uploading.
25+
[Sentry SolidStart Plugin] Otherwise, source maps might be deployed to production, depending on your configuration`,
26+
);
27+
}
28+
}
29+
return {
30+
...config,
31+
build: {
32+
...config.build,
33+
sourcemap: true,
34+
},
35+
};
36+
},
37+
},
38+
...sentryVitePlugin({
39+
org: options.org ?? process.env.SENTRY_ORG,
40+
project: options.project ?? process.env.SENTRY_PROJECT,
41+
authToken: options.authToken ?? process.env.SENTRY_AUTH_TOKEN,
42+
telemetry: options.telemetry ?? true,
43+
sourcemaps: {
44+
assets: options.sourcemaps?.assets ?? undefined,
45+
ignore: options.sourcemaps?.ignore ?? undefined,
46+
filesToDeleteAfterUpload: options.sourcemaps?.filesToDeleteAfterUpload ?? undefined,
47+
},
48+
_metaOptions: {
49+
telemetry: {
50+
metaFramework: 'solidstart',
51+
},
52+
},
53+
debug: options.debug ?? false,
54+
}),
55+
];
56+
}

packages/solidstart/src/vite/types.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
type SourceMapsOptions = {
1+
export type SourceMapsOptions = {
22
/**
33
* If this flag is `true`, and an auth token is detected, the Sentry SDK will
44
* automatically generate and upload source maps to Sentry during a production build.
@@ -69,6 +69,12 @@ type SourceMapsOptions = {
6969
*/
7070
filesToDeleteAfterUpload?: string | Array<string>;
7171
};
72+
73+
/**
74+
* Enable debug functionality of the SDK during build-time.
75+
* Enabling this will give you logs about source maps.
76+
*/
77+
debug?: boolean;
7278
};
7379

7480
/**
@@ -82,7 +88,7 @@ export type SentrySolidStartPluginOptions = {
8288

8389
/**
8490
* Enable debug functionality of the SDK during build-time.
85-
* Enabling this will give you, for example, logs about source maps.
91+
* Enabling this will give you, for example logs about source maps.
8692
*/
8793
debug?: boolean;
8894
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { Plugin } from 'vite';
2+
import { describe, expect, it, vi } from 'vitest';
3+
import { sentrySolidStartVite } from '../../src/vite/sentrySolidStartVite';
4+
5+
vi.spyOn(console, 'log').mockImplementation(() => {
6+
/* noop */
7+
});
8+
vi.spyOn(console, 'warn').mockImplementation(() => {
9+
/* noop */
10+
});
11+
12+
function getSentrySolidStartVitePlugins(options?: Parameters<typeof sentrySolidStartVite>[0]): Plugin[] {
13+
return sentrySolidStartVite({
14+
sourceMapsUploadOptions: {
15+
authToken: 'token',
16+
org: 'org',
17+
project: 'project',
18+
...options?.sourceMapsUploadOptions,
19+
},
20+
...options,
21+
});
22+
}
23+
24+
describe('sentrySolidStartVite()', () => {
25+
it('returns an array of vite plugins', () => {
26+
const plugins = getSentrySolidStartVitePlugins();
27+
const names = plugins.map(plugin => plugin.name);
28+
expect(names).toEqual([
29+
'sentry-solidstart-source-maps',
30+
'sentry-telemetry-plugin',
31+
'sentry-vite-release-injection-plugin',
32+
'sentry-debug-id-upload-plugin',
33+
'sentry-vite-debug-id-injection-plugin',
34+
'sentry-file-deletion-plugin',
35+
'sentry-vite-debug-id-upload-plugin',
36+
]);
37+
});
38+
39+
it("returns an empty array if source maps upload isn't enabled", () => {
40+
const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: false } });
41+
expect(plugins).toHaveLength(0);
42+
});
43+
44+
it('returns an empty array if `NODE_ENV` is development', async () => {
45+
const previousEnv = process.env.NODE_ENV;
46+
process.env.NODE_ENV = 'development';
47+
48+
const plugins = getSentrySolidStartVitePlugins({ sourceMapsUploadOptions: { enabled: true } });
49+
expect(plugins).toHaveLength(0);
50+
51+
process.env.NODE_ENV = previousEnv;
52+
});
53+
});
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { makeSourceMapsVitePlugin } from '../../src/vite/sourceMaps';
3+
import * as sourceMaps from '../../src/vite/sourceMaps';
4+
5+
const mockedSentryVitePlugin = {
6+
name: 'sentry-vite-debug-id-upload-plugin',
7+
writeBundle: vi.fn(),
8+
};
9+
10+
vi.mock('@sentry/vite-plugin', async () => {
11+
const original = (await vi.importActual('@sentry/vite-plugin')) as any;
12+
13+
return {
14+
...original,
15+
sentryVitePlugin: () => [mockedSentryVitePlugin],
16+
};
17+
});
18+
19+
beforeEach(() => {
20+
vi.clearAllMocks();
21+
});
22+
23+
describe('makeSourceMapsVitePlugin()', () => {
24+
it('returns a plugin to set `sourcemaps` to `true`', async () => {
25+
const [sourceMapsConfigPlugin, sentryVitePlugin] = makeSourceMapsVitePlugin({});
26+
27+
expect(sourceMapsConfigPlugin?.name).toEqual('sentry-solidstart-source-maps');
28+
expect(sourceMapsConfigPlugin?.apply).toEqual('build');
29+
expect(sourceMapsConfigPlugin?.enforce).toEqual('post');
30+
expect(sourceMapsConfigPlugin?.config).toEqual(expect.any(Function));
31+
32+
expect(sentryVitePlugin).toEqual(mockedSentryVitePlugin);
33+
});
34+
35+
it('passes user-specified vite plugin options to vite plugin plugin', async () => {
36+
const makePluginSpy = vi.spyOn(sourceMaps, 'makeSourceMapsVitePlugin');
37+
38+
makeSourceMapsVitePlugin({
39+
org: 'my-org',
40+
authToken: 'my-token',
41+
sourcemaps: {
42+
assets: ['foo/*.js'],
43+
ignore: ['bar/*.js'],
44+
filesToDeleteAfterUpload: ['baz/*.js'],
45+
},
46+
});
47+
48+
expect(makePluginSpy).toHaveBeenCalledWith({
49+
org: 'my-org',
50+
authToken: 'my-token',
51+
sourcemaps: {
52+
assets: ['foo/*.js'],
53+
ignore: ['bar/*.js'],
54+
filesToDeleteAfterUpload: ['baz/*.js'],
55+
},
56+
});
57+
});
58+
});

0 commit comments

Comments
 (0)