Skip to content

Commit dd4a7d7

Browse files
andreiborzamydealforst
authored
feat(solid): Remove need to pass router hooks to solid integration (#12617)
⚠️ This PR introduces **breaking changes** to `@sentry/solid`⚠️ Previously, we had to pass `useBeforeLeave` and `useLocation` to `solidRouterBrowserTracingIntegration`. This has now been removed in favor of importing the router hooks directly within the sdk as needed. Import `solidRouterBrowserTracingIntegration` from `@sentry/solid/solidrouter` and add it to `Sentry.init`: ```js import * as Sentry from '@sentry/solid'; import { solidRouterBrowserTracingIntegration, withSentryRouterRouting } from '@sentry/solid/solidrouter'; import { Router } from '@solidjs/router'; Sentry.init({ dsn: '__PUBLIC_DSN__', integrations: [solidRouterBrowserTracingIntegration()], tracesSampleRate: 1.0, // Capture 100% of the transactions }); const SentryRouter = withSentryRouterRouting(Router); ``` As a result, the SDK has an optional peer dependency on `@solidjs/router` `v0.13.4+` when using `solidRouterBrowserTracingIntegration`. **Note to maintainers** This package outputs types at the `build` root instead of `build/types` to better support projects that don't use `moduleResolution: "bundler"`. --------- Co-authored-by: Francesco Novy <francesco.novy@sentry.io> Co-authored-by: Luca Forstner <luca.forstner@sentry.io>
1 parent c49c9f3 commit dd4a7d7

File tree

10 files changed

+95
-109
lines changed

10 files changed

+95
-109
lines changed

CHANGELOG.md

+22
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@
44

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

7+
- **feat(solid): Remove need to pass router hooks to solid integration** (breaking)
8+
9+
This release introduces breaking changes to the `@sentry/solid` package (which is currently out in alpha).
10+
11+
We've made it easier to get started with the solid router integration by removing the need to pass **use\*** hooks
12+
explicitly to `solidRouterBrowserTracingIntegration`. Import `solidRouterBrowserTracingIntegration` from
13+
`@sentry/solid/solidrouter` and add it to `Sentry.init`
14+
15+
```js
16+
import * as Sentry from '@sentry/solid';
17+
import { solidRouterBrowserTracingIntegration, withSentryRouterRouting } from '@sentry/solid/solidrouter';
18+
import { Router } from '@solidjs/router';
19+
20+
Sentry.init({
21+
dsn: '__PUBLIC_DSN__',
22+
integrations: [solidRouterBrowserTracingIntegration()],
23+
tracesSampleRate: 1.0, // Capture 100% of the transactions
24+
});
25+
26+
const SentryRouter = withSentryRouterRouting(Router);
27+
```
28+
729
## 8.11.0
830

931
### Important Changes
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @refresh reload */
22
import * as Sentry from '@sentry/solid';
3-
import { Router, useBeforeLeave, useLocation } from '@solidjs/router';
3+
import { solidRouterBrowserTracingIntegration, withSentryRouterRouting } from '@sentry/solid/solidrouter';
4+
import { Router } from '@solidjs/router';
45
import { render } from 'solid-js/web';
56
import './index.css';
67
import PageRoot from './pageroot';
@@ -10,12 +11,12 @@ Sentry.init({
1011
dsn: import.meta.env.PUBLIC_E2E_TEST_DSN,
1112
debug: true,
1213
environment: 'qa', // dynamic sampling bias to keep transactions
13-
integrations: [Sentry.solidRouterBrowserTracingIntegration({ useBeforeLeave, useLocation })],
14+
integrations: [solidRouterBrowserTracingIntegration()],
1415
release: 'e2e-test',
1516
tunnel: 'http://localhost:3031/', // proxy server
1617
tracesSampleRate: 1.0,
1718
});
1819

19-
const SentryRouter = Sentry.withSentryRouterRouting(Router);
20+
const SentryRouter = withSentryRouterRouting(Router);
2021

2122
render(() => <SentryRouter root={PageRoot}>{routes}</SentryRouter>, document.getElementById('root'));

packages/solid/README.md

+11-14
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
</a>
55
</p>
66

7-
# Official Sentry SDK for Solid
7+
# Official Sentry SDK for Solid (EXPERIMENTAL)
88

99
[![npm version](https://img.shields.io/npm/v/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid)
1010
[![npm dm](https://img.shields.io/npm/dm/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid)
1111
[![npm dt](https://img.shields.io/npm/dt/@sentry/solid.svg)](https://www.npmjs.com/package/@sentry/solid)
1212

13-
This SDK is considered **experimental and in an alpha state**. It may experience breaking changes. Please reach out on
14-
[GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This
13+
This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out
14+
on [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns. This
1515
SDK currently only supports [Solid](https://www.solidjs.com/) and is not yet officially compatible with
1616
[Solid Start](https://start.solidjs.com/).
1717

@@ -20,25 +20,22 @@ SDK currently only supports [Solid](https://www.solidjs.com/) and is not yet off
2020
The Solid Router instrumentation uses the Solid Router library to create navigation spans to ensure you collect
2121
meaningful performance data about the health of your page loads and associated requests.
2222

23-
Add `Sentry.solidRouterBrowserTracingIntegration` instead of the regular `Sentry.browserTracingIntegration` and provide
24-
the hooks it needs to enable performance tracing:
23+
Add `solidRouterBrowserTracingIntegration` instead of the regular `Sentry.browserTracingIntegration`.
2524

26-
`useBeforeLeave` from `@solidjs/router`
27-
`useLocation` from `@solidjs/router`
25+
Make sure `solidRouterBrowserTracingIntegration` is initialized by your `Sentry.init` call. Otherwise, the routing
26+
instrumentation will not work properly.
2827

29-
Make sure `Sentry.solidRouterBrowserTracingIntegration` is initialized by your `Sentry.init` call, before you wrap
30-
`Router`. Otherwise, the routing instrumentation may not work properly.
31-
32-
Wrap `Router`, `MemoryRouter` or `HashRouter` from `@solidjs/router` using `Sentry.withSentryRouterRouting`. This
33-
creates a higher order component, which will enable Sentry to reach your router context.
28+
Wrap `Router`, `MemoryRouter` or `HashRouter` from `@solidjs/router` using `withSentryRouterRouting`. This creates a
29+
higher order component, which will enable Sentry to reach your router context.
3430

3531
```js
3632
import * as Sentry from '@sentry/solid';
37-
import { Route, Router, useBeforeLeave, useLocation } from '@solidjs/router';
33+
import { solidRouterBrowserTracingIntegration, withSentryRouterRouting } from '@sentry/solid/solidrouter';
34+
import { Route, Router } from '@solidjs/router';
3835

3936
Sentry.init({
4037
dsn: '__PUBLIC_DSN__',
41-
integrations: [Sentry.solidRouterBrowserTracingIntegration({ useBeforeLeave, useLocation })],
38+
integrations: [solidRouterBrowserTracingIntegration()],
4239
tracesSampleRate: 1.0, // Capture 100% of the transactions
4340
});
4441

packages/solid/package.json

+25-15
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,35 @@
1212
"files": [
1313
"cjs",
1414
"esm",
15-
"types",
16-
"types-ts3.8"
15+
"index.d.ts",
16+
"index.d.ts.map",
17+
"solidrouter.d.ts",
18+
"solidrouter.d.ts.map"
1719
],
1820
"main": "build/cjs/index.js",
1921
"module": "build/esm/index.js",
20-
"types": "build/types/index.d.ts",
22+
"types": "build/index.d.ts",
2123
"exports": {
2224
"./package.json": "./package.json",
2325
".": {
2426
"import": {
25-
"types": "./build/types/index.d.ts",
27+
"types": "./build/index.d.ts",
2628
"default": "./build/esm/index.js"
2729
},
2830
"require": {
29-
"types": "./build/types/index.d.ts",
31+
"types": "./build/index.d.ts",
3032
"default": "./build/cjs/index.js"
3133
}
32-
}
33-
},
34-
"typesVersions": {
35-
"<4.9": {
36-
"build/types/index.d.ts": [
37-
"build/types-ts3.8/index.d.ts"
38-
]
34+
},
35+
"./solidrouter": {
36+
"import": {
37+
"types": "./build/solidrouter.d.ts",
38+
"default": "./build/esm/solidrouter.js"
39+
},
40+
"require": {
41+
"types": "./build/solidrouter.d.ts",
42+
"default": "./build/cjs/solidrouter.js"
43+
}
3944
}
4045
},
4146
"publishConfig": {
@@ -48,10 +53,16 @@
4853
"@sentry/utils": "8.11.0"
4954
},
5055
"peerDependencies": {
56+
"@solidjs/router": "^0.13.4",
5157
"solid-js": "^1.8.4"
5258
},
59+
"peerDependenciesMeta": {
60+
"@solidjs/router": {
61+
"optional": true
62+
}
63+
},
5364
"devDependencies": {
54-
"@solidjs/router": "^0.13.5",
65+
"@solidjs/router": "^0.13.4",
5566
"@solidjs/testing-library": "0.8.5",
5667
"@testing-library/jest-dom": "^6.4.5",
5768
"@testing-library/user-event": "^14.5.2",
@@ -62,9 +73,8 @@
6273
"build": "run-p build:transpile build:types",
6374
"build:dev": "yarn build",
6475
"build:transpile": "rollup -c rollup.npm.config.mjs",
65-
"build:types": "run-s build:types:core build:types:downlevel",
76+
"build:types": "run-s build:types:core",
6677
"build:types:core": "tsc -p tsconfig.types.json",
67-
"build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8",
6878
"build:watch": "run-p build:transpile:watch build:types:watch",
6979
"build:dev:watch": "yarn build:watch",
7080
"build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch",

packages/solid/rollup.npm.config.mjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import { makeBaseNPMConfig, makeNPMConfigVariants } from '@sentry-internal/rollup-utils';
22

3-
export default makeNPMConfigVariants(makeBaseNPMConfig());
3+
export default makeNPMConfigVariants(
4+
makeBaseNPMConfig({
5+
entrypoints: ['src/index.ts', 'src/solidrouter.ts'],
6+
}),
7+
);

packages/solid/src/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ export * from '@sentry/browser';
22

33
export { init } from './sdk';
44

5-
export * from './solidrouter';
65
export * from './errorboundary';

packages/solid/src/solidrouter.ts

+17-61
Original file line numberDiff line numberDiff line change
@@ -12,55 +12,21 @@ import {
1212
getClient,
1313
} from '@sentry/core';
1414
import type { Client, Integration, Span } from '@sentry/types';
15-
import { logger } from '@sentry/utils';
15+
import type {
16+
BeforeLeaveEventArgs,
17+
HashRouter,
18+
MemoryRouter,
19+
RouteSectionProps,
20+
Router as BaseRouter,
21+
StaticRouter,
22+
} from '@solidjs/router';
23+
import { useBeforeLeave, useLocation } from '@solidjs/router';
1624
import { createEffect, mergeProps, splitProps } from 'solid-js';
1725
import type { Component, JSX, ParentProps } from 'solid-js';
1826
import { createComponent } from 'solid-js/web';
19-
import { DEBUG_BUILD } from './debug-build';
20-
21-
// Vendored solid router types so that we don't need to depend on solid router.
22-
// These are not exhaustive and loose on purpose.
23-
interface Location {
24-
pathname: string;
25-
}
26-
27-
interface BeforeLeaveEventArgs {
28-
from: Location;
29-
to: string | number;
30-
}
31-
32-
interface RouteSectionProps<T = unknown> {
33-
location: Location;
34-
data?: T;
35-
children?: JSX.Element;
36-
}
37-
38-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
39-
type RouteDefinition<S extends string | string[] = any, T = unknown> = {
40-
path?: S;
41-
children?: RouteDefinition | RouteDefinition[];
42-
component?: Component<RouteSectionProps<T>>;
43-
};
44-
45-
interface RouterProps {
46-
base?: string;
47-
root?: Component<RouteSectionProps>;
48-
children?: JSX.Element | RouteDefinition | RouteDefinition[];
49-
}
50-
51-
interface SolidRouterOptions {
52-
useBeforeLeave: UserBeforeLeave;
53-
useLocation: UseLocation;
54-
}
55-
56-
type UserBeforeLeave = (listener: (e: BeforeLeaveEventArgs) => void) => void;
57-
type UseLocation = () => Location;
5827

5928
const CLIENTS_WITH_INSTRUMENT_NAVIGATION = new WeakSet<Client>();
6029

61-
let _useBeforeLeave: UserBeforeLeave;
62-
let _useLocation: UseLocation;
63-
6430
function handleNavigation(location: string): void {
6531
const client = getClient();
6632
if (!client || !CLIENTS_WITH_INSTRUMENT_NAVIGATION.has(client)) {
@@ -98,12 +64,12 @@ function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<Rou
9864
// - use query params
9965
// - parameterize the route
10066

101-
_useBeforeLeave(({ to }: BeforeLeaveEventArgs) => {
67+
useBeforeLeave(({ to }: BeforeLeaveEventArgs) => {
10268
// `to` could be `-1` if the browser back-button was used
10369
handleNavigation(to.toString());
10470
});
10571

106-
const location = _useLocation();
72+
const location = useLocation();
10773
createEffect(() => {
10874
const name = location.pathname;
10975
const rootSpan = getActiveRootSpan();
@@ -130,21 +96,17 @@ function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<Rou
13096
* A browser tracing integration that uses Solid Router to instrument navigations.
13197
*/
13298
export function solidRouterBrowserTracingIntegration(
133-
options: Parameters<typeof browserTracingIntegration>[0] & SolidRouterOptions,
99+
options: Parameters<typeof browserTracingIntegration>[0] = {},
134100
): Integration {
135101
const integration = browserTracingIntegration({
136102
...options,
137103
instrumentNavigation: false,
138104
});
139105

140-
const { instrumentNavigation = true, useBeforeLeave, useLocation } = options;
106+
const { instrumentNavigation = true } = options;
141107

142108
return {
143109
...integration,
144-
setup() {
145-
_useBeforeLeave = useBeforeLeave;
146-
_useLocation = useLocation;
147-
},
148110
afterAllSetup(client) {
149111
integration.afterAllSetup(client);
150112

@@ -155,19 +117,13 @@ export function solidRouterBrowserTracingIntegration(
155117
};
156118
}
157119

120+
type RouterType = typeof BaseRouter | typeof HashRouter | typeof MemoryRouter | typeof StaticRouter;
121+
158122
/**
159123
* A higher-order component to instrument Solid Router to create navigation spans.
160124
*/
161-
export function withSentryRouterRouting(Router: Component<RouterProps>): Component<RouterProps> {
162-
if (!_useBeforeLeave || !_useLocation) {
163-
DEBUG_BUILD &&
164-
logger.warn(`solidRouterBrowserTracingIntegration was unable to wrap Solid Router because of one or more missing hooks.
165-
useBeforeLeave: ${_useBeforeLeave}. useLocation: ${_useLocation}.`);
166-
167-
return Router;
168-
}
169-
170-
const SentryRouter = (props: RouterProps): JSX.Element => {
125+
export function withSentryRouterRouting(Router: RouterType): RouterType {
126+
const SentryRouter = (props: Parameters<RouterType>[0]): JSX.Element => {
171127
const [local, others] = splitProps(props, ['root']);
172128
// We need to wrap root here in case the user passed in their own root
173129
const Root = withSentryRouterRoot(local.root ? local.root : SentryDefaultRoot);

packages/solid/test/solidrouter.test.tsx

+6-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
getCurrentScope,
88
setCurrentClient,
99
} from '@sentry/core';
10-
import { MemoryRouter, Navigate, Route, createMemoryHistory, useBeforeLeave, useLocation } from '@solidjs/router';
10+
import type { MemoryHistory } from '@solidjs/router';
11+
import { MemoryRouter, Navigate, Route, createMemoryHistory } from '@solidjs/router';
1112
import { render } from '@solidjs/testing-library';
1213
import { vi } from 'vitest';
1314

@@ -17,7 +18,7 @@ import { solidRouterBrowserTracingIntegration, withSentryRouterRouting } from '.
1718
// solid router uses `window.scrollTo` when navigating
1819
vi.spyOn(global, 'scrollTo').mockImplementation(() => {});
1920

20-
const renderRouter = (SentryRouter, history) =>
21+
const renderRouter = (SentryRouter: typeof MemoryRouter, history: MemoryHistory) =>
2122
render(() => (
2223
<SentryRouter history={history}>
2324
<Route path="/" component={() => <div>Home</div>} />
@@ -58,7 +59,7 @@ describe('solidRouterBrowserTracingIntegration', () => {
5859
setCurrentClient(client);
5960

6061
client.on('spanStart', span => spanStartMock(spanToJSON(span)));
61-
client.addIntegration(solidRouterBrowserTracingIntegration({ useBeforeLeave, useLocation }));
62+
client.addIntegration(solidRouterBrowserTracingIntegration());
6263

6364
const history = createMemoryHistory();
6465
history.set({ value: '/' });
@@ -86,8 +87,6 @@ describe('solidRouterBrowserTracingIntegration', () => {
8687
client.addIntegration(
8788
solidRouterBrowserTracingIntegration({
8889
instrumentPageLoad: false,
89-
useBeforeLeave,
90-
useLocation,
9190
}),
9291
);
9392
const SentryRouter = withSentryRouterRouting(MemoryRouter);
@@ -124,7 +123,7 @@ describe('solidRouterBrowserTracingIntegration', () => {
124123
client.on('spanStart', span => {
125124
spanStartMock(spanToJSON(span));
126125
});
127-
client.addIntegration(solidRouterBrowserTracingIntegration({ useBeforeLeave, useLocation }));
126+
client.addIntegration(solidRouterBrowserTracingIntegration());
128127
const SentryRouter = withSentryRouterRouting(MemoryRouter);
129128

130129
const history = createMemoryHistory();
@@ -155,8 +154,6 @@ describe('solidRouterBrowserTracingIntegration', () => {
155154
client.addIntegration(
156155
solidRouterBrowserTracingIntegration({
157156
instrumentNavigation: false,
158-
useBeforeLeave,
159-
useLocation,
160157
}),
161158
);
162159
const SentryRouter = withSentryRouterRouting(MemoryRouter);
@@ -188,7 +185,7 @@ describe('solidRouterBrowserTracingIntegration', () => {
188185
client.on('spanStart', span => {
189186
spanStartMock(spanToJSON(span));
190187
});
191-
client.addIntegration(solidRouterBrowserTracingIntegration({ useBeforeLeave, useLocation }));
188+
client.addIntegration(solidRouterBrowserTracingIntegration());
192189
const SentryRouter = withSentryRouterRouting(MemoryRouter);
193190

194191
const history = createMemoryHistory();

packages/solid/tsconfig.types.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"declaration": true,
66
"declarationMap": true,
77
"emitDeclarationOnly": true,
8-
"outDir": "build/types"
8+
"outDir": "build"
99
}
1010
}

0 commit comments

Comments
 (0)