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 (#13493)

This plugin simplifies source maps upload by using `@sentry/vite-plugin`
and enabling source map generation by default.

Usage:
```js
import { defineConfig } from '@solidjs/start/config'
import { sentrySolidStartVite } from '@sentry/solidstart'

export default defineConfig({
  vite: {
    plugins: [
      sentrySolidStartVite({
        org: process.env.SENTRY_ORG,
        project: process.env.SENTRY_PROJECT,
        authToken: process.env.SENTRY_AUTH_TOKEN,
        debug: true,
      }),
    ],
  }
})
```

Closes: #12553
  • Loading branch information
andreiborza authored Sep 5, 2024
1 parent a69da1b commit e2213fc
Show file tree
Hide file tree
Showing 19 changed files with 464 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ jobs:
working-directory: dev-packages/e2e-tests/test-applications/${{ matrix.test-application }}
timeout-minutes: 5
run: pnpm test:assert

- name: Upload Playwright Traces
uses: actions/upload-artifact@v4
if: failure()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { sentrySolidStartVite } from '@sentry/solidstart';
import { defineConfig } from '@solidjs/start/config';

export default defineConfig({});
export default defineConfig({
vite: {
plugins: [sentrySolidStartVite()],
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
"version": "0.0.0",
"scripts": {
"clean": "pnpx rimraf node_modules pnpm-lock.yaml .vinxi .output",
"clean:build": "pnpx rimraf .vinxi .output",
"dev": "NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
"build": "vinxi build",
"//": [
"We are using `vinxi dev` to start the server because `vinxi start` is experimental and ",
"doesn't correctly resolve modules for @sentry/solidstart/solidrouter.",
"This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177"
"This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177",
"We run the build command to ensure building succeeds. However, keeping",
"build output around slows down the vite dev server when using `@sentry/vite-plugin` so we clear it out",
"before actually running the tests.",
"Cleaning the build output should be removed once we can use `vinxi start`."
],
"preview": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
"preview": "pnpm clean:build && HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
"start": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi start",
"test:prod": "TEST_ENV=production playwright test",
"test:build": "pnpm install && npx playwright install && pnpm build",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,15 @@
import * as Sentry from '@sentry/solidstart';
import type { ParentProps } from 'solid-js';
import { ErrorBoundary, createSignal, onMount } from 'solid-js';

const SentryErrorBoundary = Sentry.withSentryErrorBoundary(ErrorBoundary);

const [count, setCount] = createSignal(1);
const [caughtError, setCaughtError] = createSignal(false);

export default function ClientErrorPage() {
return (
<SampleErrorBoundary>
{caughtError() && (
<Throw error={`Error ${count()} thrown from Sentry ErrorBoundary in Solid Start E2E test app`} />
)}
<section class="bg-gray-100 text-gray-700 p-8">
<div class="flex flex-col items-start space-x-2">
<button
class="border rounded-lg px-2 mb-2 border-red-500 text-red-500 cursor-pointer"
id="caughtErrorBtn"
onClick={() => setCaughtError(true)}
>
Throw caught error
</button>
</div>
<div class="flex flex-col items-start space-x-2">
<button
class="border rounded-lg px-2 mb-2 border-red-500 text-red-500 cursor-pointer"
id="errorBtn"
onClick={() => {
throw new Error('Error thrown from Solid Start E2E test app');
}}
>
Throw uncaught error
</button>
</div>
</section>
</SampleErrorBoundary>
);
}

function Throw(props: { error: string }) {
onMount(() => {
throw new Error(props.error);
});
return null;
}

function SampleErrorBoundary(props: ParentProps) {
return (
<SentryErrorBoundary
fallback={(error, reset) => (
<section class="bg-gray-100 text-gray-700 p-8">
<h1 class="text-2xl font-bold">Error Boundary Fallback</h1>
<div class="flex items-center space-x-2 mb-4">
<code>{error.message}</code>
</div>
<button
id="errorBoundaryResetBtn"
class="border rounded-lg px-2 border-gray-900"
onClick={() => {
setCount(count() + 1);
setCaughtError(false);
reset();
}}
>
Reset
</button>
</section>
)}
>
{props.children}
</SentryErrorBoundary>
<div class="flex flex-col items-start space-x-2">
<button
class="border rounded-lg px-2 mb-2 border-red-500 text-red-500 cursor-pointer"
id="errorBtn"
onClick={() => {
throw new Error('Uncaught error thrown from Solid Start E2E test app');
}}
>
Throw uncaught error
</button>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as Sentry from '@sentry/solidstart';
import type { ParentProps } from 'solid-js';
import { ErrorBoundary, createSignal, onMount } from 'solid-js';

const SentryErrorBoundary = Sentry.withSentryErrorBoundary(ErrorBoundary);

const [count, setCount] = createSignal(1);
const [caughtError, setCaughtError] = createSignal(false);

export default function ErrorBoundaryTestPage() {
return (
<SampleErrorBoundary>
{caughtError() && (
<Throw error={`Error ${count()} thrown from Sentry ErrorBoundary in Solid Start E2E test app`} />
)}
<section class="bg-gray-100 text-gray-700 p-8">
<div class="flex flex-col items-start space-x-2">
<button
class="border rounded-lg px-2 mb-2 border-red-500 text-red-500 cursor-pointer"
id="caughtErrorBtn"
onClick={() => setCaughtError(true)}
>
Throw caught error
</button>
</div>
</section>
</SampleErrorBoundary>
);
}

function Throw(props: { error: string }) {
onMount(() => {
throw new Error(props.error);
});
return null;
}

function SampleErrorBoundary(props: ParentProps) {
return (
<SentryErrorBoundary
fallback={(error, reset) => (
<section class="bg-gray-100 text-gray-700 p-8">
<h1 class="text-2xl font-bold">Error Boundary Fallback</h1>
<div class="flex items-center space-x-2 mb-4">
<code>{error.message}</code>
</div>
<button
id="errorBoundaryResetBtn"
class="border rounded-lg px-2 border-gray-900"
onClick={() => {
setCount(count() + 1);
setCaughtError(false);
reset();
}}
>
Reset
</button>
</section>
)}
>
{props.children}
</SentryErrorBoundary>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export default function Home() {
<li>
<A href="/server-error">Server error</A>
</li>
<li>
<A href="/error-boundary">Error Boundary</A>
</li>
<li>
<A id="navLink" href="/users/5">
User 5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test('captures an exception', async ({ page }) => {
);
});

await page.goto('/client-error');
await page.goto('/error-boundary');
await page.locator('#caughtErrorBtn').click();
const errorEvent = await errorEventPromise;

Expand All @@ -27,7 +27,7 @@ test('captures an exception', async ({ page }) => {
},
],
},
transaction: '/client-error',
transaction: '/error-boundary',
});
});

Expand All @@ -40,7 +40,7 @@ test('captures a second exception after resetting the boundary', async ({ page }
);
});

await page.goto('/client-error');
await page.goto('/error-boundary');
await page.locator('#caughtErrorBtn').click();
const firstErrorEvent = await firstErrorEventPromise;

Expand All @@ -57,7 +57,7 @@ test('captures a second exception after resetting the boundary', async ({ page }
},
],
},
transaction: '/client-error',
transaction: '/error-boundary',
});

const secondErrorEventPromise = waitForError('solidstart', errorEvent => {
Expand Down Expand Up @@ -85,6 +85,6 @@ test('captures a second exception after resetting the boundary', async ({ page }
},
],
},
transaction: '/client-error',
transaction: '/error-boundary',
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { waitForError } from '@sentry-internal/test-utils';
test.describe('client-side errors', () => {
test('captures error thrown on click', async ({ page }) => {
const errorPromise = waitForError('solidstart', async errorEvent => {
return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Solid Start E2E test app';
return errorEvent?.exception?.values?.[0]?.value === 'Uncaught error thrown from Solid Start E2E test app';
});

await page.goto(`/client-error`);
Expand All @@ -16,9 +16,8 @@ test.describe('client-side errors', () => {
values: [
{
type: 'Error',
value: 'Error thrown from Solid Start E2E test app',
value: 'Uncaught error thrown from Solid Start E2E test app',
mechanism: {
type: 'instrument',
handled: false,
},
},
Expand Down
1 change: 1 addition & 0 deletions packages/solidstart/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = {
files: ['src/vite/**', 'src/server/**'],
rules: {
'@sentry-internal/sdk/no-optional-chaining': 'off',
'@sentry-internal/sdk/no-nullish-coalescing': 'off',
},
},
],
Expand Down
46 changes: 11 additions & 35 deletions packages/solidstart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,58 +157,34 @@ render(
);
```

# Sourcemaps and Releases
## Uploading Source Maps

To generate and upload source maps of your Solid Start app use our Vite bundler plugin.

1. Install the Sentry Vite plugin

```bash
# Using npm
npm install @sentry/vite-plugin --save-dev

# Using yarn
yarn add @sentry/vite-plugin --dev
```

2. Configure the vite plugin

To upload source maps you have to 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.
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.

Learn more about configuring the plugin in our
[Sentry Vite Plugin documentation](https://www.npmjs.com/package/@sentry/vite-plugin).

```bash
// .env.sentry-build-plugin
SENTRY_AUTH_TOKEN=<your auth token>
SENTRY_ORG=<your org>
SENTRY_PROJECT=<your project name>
```

3. Finally, add the plugin to your `app.config.ts` file.

```javascript
```typescript
// app.config.ts
import { defineConfig } from '@solidjs/start/config';
import { sentryVitePlugin } from '@sentry/vite-plugin';
import { sentrySolidStartVite } from '@sentry/solidstart';

export default defineConfig({
// rest of your config
// ...

vite: {
build: {
sourcemap: true,
},
plugins: [
sentryVitePlugin({
sentrySolidStartVite({
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
debug: true,
}),
],
},
// ...
});
```
1 change: 1 addition & 0 deletions packages/solidstart/src/index.server.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './server';
export * from './vite';
1 change: 1 addition & 0 deletions packages/solidstart/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// exports in this file - which we do below.
export * from './client';
export * from './server';
export * from './vite';

import type { Integration, Options, StackParser } from '@sentry/types';

Expand Down
1 change: 1 addition & 0 deletions packages/solidstart/src/vite/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
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));
}
}

return sentryPlugins;
};
Loading

0 comments on commit e2213fc

Please sign in to comment.