Skip to content

Commit

Permalink
feat(v8/solidstart): Add withSentry wrapper for SolidStart config (#…
Browse files Browse the repository at this point in the history
…15135)

Backport of #14862
and #14863

---------

Co-authored-by: Andrei Borza <[email protected]>
  • Loading branch information
s1gr1d and andreiborza authored Jan 23, 2025
1 parent d5f80af commit a76f243
Show file tree
Hide file tree
Showing 69 changed files with 2,751 additions and 7 deletions.
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,50 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

- **feat(solidstart): Default to `--import` setup and add `autoInjectServerSentry` ([#14862](https://github.com/getsentry/sentry-javascript/pull/14862))**

To enable the SolidStart SDK, wrap your SolidStart Config with `withSentry`. The `sentrySolidStartVite` plugin is now automatically
added by `withSentry` and you can pass the Sentry build-time options like this:

```js
import { defineConfig } from '@solidjs/start/config';
import { withSentry } from '@sentry/solidstart';

export default defineConfig(
withSentry(
{
/* Your SolidStart config options... */
},
{
// Options for setting up source maps
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
},
),
);
```

With the `withSentry` wrapper, the Sentry server config should not be added to the `public` directory anymore.
Add the Sentry server config in `src/instrument.server.ts`. Then, the server config will be placed inside the server build output as `instrument.server.mjs`.

Now, there are two options to set up the SDK:

1. **(recommended)** Provide an `--import` CLI flag to the start command like this (path depends on your server setup):
`node --import ./.output/server/instrument.server.mjs .output/server/index.mjs`
2. Add `autoInjectServerSentry: 'top-level-import'` and the Sentry config will be imported at the top of the server entry (comes with tracing limitations)
```js
withSentry(
{
/* Your SolidStart config options... */
},
{
// Optional: Install Sentry with a top-level import
autoInjectServerSentry: 'top-level-import',
},
);
```

## 8.51.0

### Important Changes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

dist
.solid
.output
.vercel
.netlify
.vinxi

# Environment
.env
.env*.local

# dependencies
/node_modules
/.pnp
.pnp.js

# IDEs and editors
/.idea
.project
.classpath
*.launch
.settings/

# Temp
gitignore

# testing
/coverage

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

/test-results/
/playwright-report/
/playwright/.cache/

!*.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@sentry:registry=http://127.0.0.1:4873
@sentry-internal:registry=http://127.0.0.1:4873
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SolidStart

Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);

## Creating a project

```bash
# create a new project in the current directory
npm init solid@latest

# create a new project in my-app
npm init solid@latest my-app
```

## Developing

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a
development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open
```

## Building

Solid apps are built with _presets_, which optimise your project for deployment to different environments.

By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add
it to the `devDependencies` in `package.json` and specify in your `app.config.js`.

## Testing

Tests are written with `vitest`, `@solidjs/testing-library` and `@testing-library/jest-dom` to extend expect with some
helpful custom matchers.

To run them, simply start:

```sh
npm test
```

## This project was created with the [Solid CLI](https://solid-cli.netlify.app)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { withSentry } from '@sentry/solidstart';
import { defineConfig } from '@solidjs/start/config';

export default defineConfig(
withSentry(
{},
{
autoInjectServerSentry: 'experimental_dynamic-import',
},
),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "solidstart-dynamic-import-e2e-testapp",
"version": "0.0.0",
"scripts": {
"clean": "pnpx rimraf node_modules pnpm-lock.yaml .vinxi .output",
"dev": "vinxi dev",
"build": "vinxi build && sh ./post_build.sh",
"preview": "HOST=localhost PORT=3030 vinxi start",
"test:prod": "TEST_ENV=production playwright test",
"test:build": "pnpm install && pnpm build",
"test:assert": "pnpm test:prod"
},
"type": "module",
"dependencies": {
"@sentry/solidstart": "latest || *"
},
"devDependencies": {
"@playwright/test": "^1.44.1",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.13.4",
"@solidjs/start": "^1.0.2",
"@solidjs/testing-library": "^0.8.7",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/user-event": "^14.5.2",
"@vitest/ui": "^1.5.0",
"jsdom": "^24.0.0",
"solid-js": "1.8.17",
"typescript": "^5.4.5",
"vinxi": "^0.4.0",
"vite": "^5.4.10",
"vite-plugin-solid": "^2.10.2",
"vitest": "^1.5.0"
},
"overrides": {
"@vercel/nft": "0.27.4"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getPlaywrightConfig } from '@sentry-internal/test-utils';

const config = getPlaywrightConfig({
startCommand: 'pnpm preview',
port: 3030,
});

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# TODO: Investigate the need for this script periodically and remove once these modules are correctly resolved.

# This script copies `import-in-the-middle` and `@sentry/solidstart` from the E2E test project root `node_modules`
# to the nitro server build output `node_modules` as these are not properly resolved in our yarn workspace/pnpm
# e2e structure. Some files like `hook.mjs` and `@sentry/solidstart/solidrouter.server.js` are missing. This is
# not reproducible in an external project (when pinning `@vercel/nft` to `v0.27.0` and higher).
cp -r node_modules/.pnpm/import-in-the-middle@1.*/node_modules/import-in-the-middle .output/server/node_modules
cp -rL node_modules/@sentry/solidstart .output/server/node_modules/@sentry
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { withSentryRouterRouting } from '@sentry/solidstart/solidrouter';
import { MetaProvider, Title } from '@solidjs/meta';
import { Router } from '@solidjs/router';
import { FileRoutes } from '@solidjs/start/router';
import { Suspense } from 'solid-js';

const SentryRouter = withSentryRouterRouting(Router);

export default function App() {
return (
<SentryRouter
root={props => (
<MetaProvider>
<Title>SolidStart - with Vitest</Title>
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</SentryRouter>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @refresh reload
import * as Sentry from '@sentry/solidstart';
import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidrouter';
import { StartClient, mount } from '@solidjs/start/client';

Sentry.init({
// We can't use env variables here, seems like they are stripped
// out in production builds.
dsn: 'https://[email protected]/1337',
environment: 'qa', // dynamic sampling bias to keep transactions
integrations: [solidRouterBrowserTracingIntegration()],
tunnel: 'http://localhost:3031/', // proxy server
// Performance Monitoring
tracesSampleRate: 1.0, // Capture 100% of the transactions
debug: !!import.meta.env.DEBUG,
});

mount(() => <StartClient />, document.getElementById('app')!);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @refresh reload
import { StartServer, createHandler } from '@solidjs/start/server';

export default createHandler(() => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body>
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as Sentry from '@sentry/solidstart';

Sentry.init({
dsn: process.env.E2E_TEST_DSN,
environment: 'qa', // dynamic sampling bias to keep transactions
tracesSampleRate: 1.0, // Capture 100% of the transactions
tunnel: 'http://localhost:3031/', // proxy server
debug: !!process.env.DEBUG,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { A } from '@solidjs/router';

export default function BackNavigation() {
return (
<A id="navLink" href="/users/6">
User 6
</A>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function ClientErrorPage() {
return (
<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>
);
}
Loading

0 comments on commit a76f243

Please sign in to comment.