Skip to content

Commit d89826a

Browse files
feat(js): Move some configuration pages to "Best Practices" (#9571)
* move configuration pages to best practices * move shared environments docs * Update capitalization * fix link --------- Co-authored-by: Stephanie Anderson <[email protected]>
1 parent 1236ab7 commit d89826a

File tree

9 files changed

+199
-112
lines changed

9 files changed

+199
-112
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
title: Browser Extensions
3+
sidebar_order: 50
4+
description: Learn how to use Sentry in shared environments (for example in browser extensions or VSCode extensions).
5+
keywords:
6+
[
7+
"BrowserClient",
8+
"NodeClient",
9+
"shared environment",
10+
"browser extension",
11+
"VSCode extension"
12+
]
13+
---
14+
15+
When setting up Sentry in a shared environment where multiple Sentry instances may run, for example, in a browser extension or similar, you should **not use `Sentry.init()`**, as this will pollute the global state. If your browser extension uses `Sentry.init()`, and the website the extension is running on also uses Sentry, the extension may send events to the website's Sentry project, or vice versa.
16+
17+
For such scenarios, you have to set up a client manually as seen in the example below.
18+
In addition, you should also avoid adding any integrations that use global state, like `Breadcrumbs` or `TryCatch`.
19+
As a rule of thumb, it's best to avoid using any integrations and to rely on manual capture of errors only in such scenarios.
20+
21+
<SignInNote />
22+
23+
```javascript
24+
import {
25+
BrowserClient,
26+
defaultStackParser,
27+
defaultIntegrations,
28+
makeFetchTransport,
29+
Scope,
30+
} from "@sentry/browser";
31+
32+
const client = new BrowserClient({
33+
dsn: "___PUBLIC_DSN___",
34+
transport: makeFetchTransport,
35+
stackParser: defaultStackParser,
36+
integrations: defaultIntegrations,
37+
});
38+
39+
const scope = new Scope();
40+
scope.setClient(client);
41+
42+
client.init() // initializing has to be done after setting the client on the scope
43+
44+
// You can capture exceptions manually for this client like this:
45+
scope.captureException(new Error("example"));
46+
47+
```
48+
49+
If you notice that Sentry is not capturing error events from the browser extension,
50+
try disabling the Browser extension errors option in the Inbound Filters of your Sentry configuration.
51+
Read more about Inbound Filters in the product documentation under [Inbound filters](/product/data-management-settings/filtering/#inbound-data-filters).
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Best Practices
3+
description: "Learn how to set up Sentry in specific scenarios with those best practice guides"
4+
sidebar_order: 3
5+
---
6+
7+
<PageGrid />

docs/platforms/javascript/common/configuration/micro-frontend-support.mdx renamed to docs/platforms/javascript/common/best-practices/micro-frontends.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Micro Frontend Support
2+
title: Micro Frontends
33
sidebar_order: 200
44
description: Learn how to identify the source of errors and route events to different Sentry projects when using micro frontend or module federation.
55
keywords:
@@ -14,7 +14,7 @@ keywords:
1414
If your frontend includes JavaScript bundles from multiple sources with
1515
different release cycles, you may want to identify these or route events to specific projects. This is especially useful if you've set up [module federation](https://module-federation.github.io/) or a similar frontend architecture.
1616

17-
Below we offer two approaches.
17+
Below we offer two approaches.
1818

1919
<Note>
2020
In all cases `Sentry.init()` must never be called more than once, doing so will result in undefined behavior.
@@ -60,7 +60,7 @@ module.exports = {
6060
};
6161
```
6262

63-
Once metadata has been injected into modules, the `moduleMetadataIntegration`
63+
Once metadata has been injected into modules, the `moduleMetadataIntegration`
6464
can be used to look up that metadata and attach it to stack frames with
6565
matching file names. This metadata is then available in the `beforeSend` callback
6666
as the `module_metadata` property on each `StackFrame`. This can be used to identify
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
title: Multiple Sentry Instances
3+
sidebar_order: 300
4+
description: Learn how to manage several Sentry instances by creating your own clients.
5+
keywords:
6+
[
7+
"multiple instances",
8+
"multiple clients",
9+
"BrowserClient",
10+
"NodeClient",
11+
"monorepo"
12+
]
13+
---
14+
15+
<Note>
16+
17+
Creating multiple Sentry clients is not recommended in general, as it can lead to unexpected behavior. If you are using Micro Frontends or similar, multiplexing might be a better solution that using multiple clients. Check out [Micro Frontends](/platforms/javascript/best-practices/micro-frontends) in the Best Practices for more information.
18+
19+
</ Note>
20+
21+
To be able to manage several Sentry instances without any conflicts between them you need to create your own `Client`.
22+
This also helps to prevent tracking of any parent application errors in case your application is integrated
23+
inside of it. In this example we use `BrowserClient` from `@sentry/browser` but it's also applicable to `NodeClient` from `@sentry/node`.
24+
25+
<SignInNote />
26+
27+
```javascript
28+
import {
29+
BrowserClient,
30+
defaultStackParser,
31+
defaultIntegrations,
32+
makeFetchTransport,
33+
Scope,
34+
} from "@sentry/browser";
35+
36+
const client = new BrowserClient({
37+
dsn: "___PUBLIC_DSN___",
38+
transport: makeFetchTransport,
39+
stackParser: defaultStackParser,
40+
integrations: defaultIntegrations,
41+
});
42+
43+
const scope = new Scope();
44+
scope.setClient(client);
45+
46+
client.init() // initializing has to be done after setting the client on the scope
47+
48+
// You can capture exceptions manually for this client like this:
49+
scope.captureException(new Error("example"));
50+
```
51+
52+
You can now customize the scope to your liking, without affecting other hubs/clients.
53+
54+
### Dealing with Integrations
55+
56+
Integrations are setup on the `Client`, if you need to deal with multiple clients and hubs you have to make sure to also do the integration handling correctly.
57+
58+
We do not recommend doing this if you are using Sentry in a browser extension or in similar scenarios.
59+
If you can't avoid using global integrations (e.g. in a micro frontend application), here is a working example of how to use multiple clients with multiple scopes running global integrations.
60+
61+
<SignInNote />
62+
63+
```javascript
64+
import * as Sentry from "@sentry/browser";
65+
66+
// Very happy integration that'll prepend and append very happy stick figure to the message
67+
function happyIntegration() {
68+
return {
69+
name: 'Happy',
70+
setupOnce() {
71+
Sentry.addGlobalEventProcessor((event) => {
72+
const self = Sentry.getClient().getIntegration(HappyIntegration);
73+
// Run the integration ONLY when it was installed on the current Hub
74+
if (self) {
75+
event.message = `\\o/ ${event.message} \\o/`;
76+
}
77+
return event;
78+
});
79+
}
80+
}
81+
}
82+
83+
const client1 = new Sentry.BrowserClient({
84+
dsn: "___PUBLIC_DSN___",
85+
transport: Sentry.makeFetchTransport,
86+
stackParser: Sentry.defaultStackParser,
87+
integrations: [...Sentry.defaultIntegrations, happyIntegration()],
88+
beforeSend(event) {
89+
console.log("client 1", event);
90+
return null; // Returning `null` prevents the event from being sent
91+
},
92+
});
93+
const scope1 = new Sentry.Scope(client1);
94+
95+
const client2 = new Sentry.BrowserClient({
96+
dsn: "___PUBLIC_DSN___", // Can be a different DSN
97+
transport: Sentry.makeFetchTransport,
98+
stackParser: Sentry.defaultStackParser,
99+
integrations: [...Sentry.defaultIntegrations, happyIntegration()],
100+
beforeSend(event) {
101+
console.log("client 2", event);
102+
return null; // Returning `null` prevents the event from being sent
103+
},
104+
});
105+
const scope2 = new Sentry.Scope(client2);
106+
107+
scope1.captureMessage("a");
108+
scope1.setTag("a", "b");
109+
110+
scope2.captureMessage("x");
111+
scope2.setTag("c", "d");
112+
```
113+
114+

docs/platforms/javascript/common/troubleshooting/index.mdx

Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -284,115 +284,6 @@ If you would like to copy and paste the snippet directly, here it is minified:
284284
</script>
285285
```
286286
287-
## Using a Client directly
288-
289-
To be able to manage several Sentry instances without any conflicts between them you need to create your own `Client`.
290-
This also helps to prevent tracking of any parent application errors in case your application is integrated
291-
inside of it. In this example we use `@sentry/browser` but it's also applicable to `@sentry/node`.
292-
293-
<SignInNote />
294-
295-
```javascript
296-
import {
297-
BrowserClient,
298-
defaultStackParser,
299-
defaultIntegrations,
300-
makeFetchTransport,
301-
Scope,
302-
} from "@sentry/browser";
303-
304-
const client = new BrowserClient({
305-
dsn: "___PUBLIC_DSN___",
306-
transport: makeFetchTransport,
307-
stackParser: defaultStackParser,
308-
integrations: defaultIntegrations,
309-
});
310-
311-
const scope = new Scope();
312-
scope.setClient(client);
313-
314-
client.init() // initializing has to be done after setting the client on the scope
315-
316-
// You can capture exceptions manually for this client like this:
317-
scope.captureException(new Error("example"));
318-
```
319-
320-
You can now customize the hub to your liking, without affecting other hubs/clients.
321-
322-
### Setting up Sentry in shared environments (e.g. Browser Extensions)
323-
324-
When setting up Sentry in a shared environment where multiple Sentry instances may run, for example, in a browser extension or similar, you should **not use `Sentry.init()`**, as this will pollute the global state. If your browser extension uses `Sentry.init()`, and the website the extension is running on also uses Sentry, the extension may send events to the website's Sentry project, or vice versa.
325-
326-
For such scenarios, you have to set up a client manually as seen in the example above.
327-
In addition, you should also avoid adding any integrations that use global state, like `Breadcrumbs` or `TryCatch`.
328-
As a rule of thumb, it's best to avoid using any integrations and to rely on manual capture of errors only in such scenarios.
329-
330-
### Dealing with Integrations
331-
332-
Integrations are setup on the `Client`, if you need to deal with multiple clients and hubs you have to make sure to also do the integration handling correctly.
333-
334-
We do not recommend doing this if you are using Sentry in a browser extension or in similar scenarios.
335-
If you can't avoid using global integrations (e.g. in a micro frontend application), here is a working example of how to use multiple clients with multiple hubs running global integrations.
336-
337-
<SignInNote />
338-
339-
```javascript
340-
import * as Sentry from "@sentry/browser";
341-
342-
// Very happy integration that'll prepend and append very happy stick figure to the message
343-
function happyIntegration() {
344-
return {
345-
name: 'Happy',
346-
setupOnce() {
347-
Sentry.addGlobalEventProcessor((event) => {
348-
const self = Sentry.getClient().getIntegration(HappyIntegration);
349-
// Run the integration ONLY when it was installed on the current Hub
350-
if (self) {
351-
event.message = `\\o/ ${event.message} \\o/`;
352-
}
353-
return event;
354-
});
355-
}
356-
}
357-
}
358-
359-
const client1 = new Sentry.BrowserClient({
360-
dsn: "___PUBLIC_DSN___",
361-
transport: Sentry.makeFetchTransport,
362-
stackParser: Sentry.defaultStackParser,
363-
integrations: [...Sentry.defaultIntegrations, happyIntegration()],
364-
beforeSend(event) {
365-
console.log("client 1", event);
366-
return null; // Returning `null` prevents the event from being sent
367-
},
368-
});
369-
const hub1 = new Sentry.Hub(client1);
370-
371-
const client2 = new Sentry.BrowserClient({
372-
dsn: "___PUBLIC_DSN___", // Can be a different DSN
373-
transport: Sentry.makeFetchTransport,
374-
stackParser: Sentry.defaultStackParser,
375-
integrations: [...Sentry.defaultIntegrations, happyIntegration()],
376-
beforeSend(event) {
377-
console.log("client 2", event);
378-
return null; // Returning `null` prevents the event from being sent
379-
},
380-
});
381-
const hub2 = new Sentry.Hub(client2);
382-
383-
hub1.run((currentHub) => {
384-
// The `hub.run` method makes sure that `Sentry.getCurrentHub()` returns this hub during the callback
385-
currentHub.captureMessage("a");
386-
Sentry.getCurrentScope().setTag("a", "b");
387-
});
388-
389-
hub2.run((currentHub) => {
390-
// The `hub.run` method makes sure that `Sentry.getCurrentHub()` returns this hub during the callback
391-
currentHub.captureMessage("x");
392-
Sentry.getCurrentScope().setTag("c", "d");
393-
});
394-
```
395-
396287
## Third Party Promise Libraries
397288
398289
When you include and configure Sentry, our JavaScript SDK automatically attaches global handlers to _capture_ uncaught exceptions and unhandled promise rejections. You can disable this default behavior by changing the `onunhandledrejection` option to `false` in your GlobalHandlers integration and manually hook into each event handler, then call `Sentry.captureException` or `Sentry.captureMessage` directly.

src/middleware.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,18 @@ const REDIRECTS: {from: PathWithTrailingSlash; to: string}[] = [
24882488
from: '/product/sentry-basics/search/searchable-properties/session-replay/',
24892489
to: '/product/reference/search/searchable-properties/session-replay/',
24902490
},
2491+
{
2492+
from: '/platforms/javascript/configuration/micro-frontend-support/',
2493+
to: '/platforms/javascript/best-practices/micro-frontends/',
2494+
},
2495+
{
2496+
from: '/platforms/javascript/configuration/sentry-testkit/',
2497+
to: '/platforms/javascript/best-practices/sentry-testkit/',
2498+
},
2499+
{
2500+
from: 'platforms/javascript/configuration/webworkers/',
2501+
to: '/platforms/javascript/best-practices/web-workers/',
2502+
},
24912503
];
24922504

24932505
const redirectMap = new Map(REDIRECTS.map(r => [r.from as string, r.to]));

vercel.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,18 @@
734734
"source": "/platforms/javascript/sourcemaps/tools/",
735735
"destination": "/platforms/javascript/sourcemaps/"
736736
},
737+
{
738+
"source": "/platforms/javascript/guides/([^/]*)/configuration/micro-frontend-support/",
739+
"destination": "/platforms/javascript/guides/$1/best-practices/micro-frontends/"
740+
},
741+
{
742+
"source": "/platforms/javascript/guides/([^/]*)/configuration/sentry-testkit/",
743+
"destination": "/platforms/javascript/guides/$1/best-practices/sentry-testkit/"
744+
},
745+
{
746+
"source": "/platforms/javascript/guides/([^/]*)/configuration/webworkers/",
747+
"destination": "/platforms/javascript/guides/$1/best-practices/web-workers/"
748+
},
737749
{
738750
"source": "/platforms/apple/guides/([^/]*)/configuration/integrations/([^/]*)/",
739751
"destination": "/platforms/apple/guides/$1/integrations/$2/"

0 commit comments

Comments
 (0)