solidstart.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. import {Fragment} from 'react';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import {buildSdkConfig} from 'sentry/components/onboarding/gettingStartedDoc/buildSdkConfig';
  4. import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/crashReportCallout';
  5. import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
  6. import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
  7. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  8. import type {
  9. Docs,
  10. DocsParams,
  11. OnboardingConfig,
  12. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  13. import {
  14. getCrashReportJavaScriptInstallStep,
  15. getCrashReportModalConfigDescription,
  16. getCrashReportModalIntroduction,
  17. getFeedbackConfigOptions,
  18. getFeedbackConfigureDescription,
  19. } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
  20. import {
  21. getProfilingDocumentHeaderConfigurationStep,
  22. MaybeBrowserProfilingBetaWarning,
  23. } from 'sentry/components/onboarding/gettingStartedDoc/utils/profilingOnboarding';
  24. import {
  25. getReplayConfigOptions,
  26. getReplayConfigureDescription,
  27. getReplayVerifyStep,
  28. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  29. import {featureFlagOnboarding} from 'sentry/gettingStartedDocs/javascript/javascript';
  30. import {t, tct} from 'sentry/locale';
  31. type Params = DocsParams;
  32. const getIntegrations = (params: Params): string[] => {
  33. const integrations = [];
  34. if (params.isPerformanceSelected) {
  35. integrations.push(`solidRouterBrowserTracingIntegration()`);
  36. }
  37. if (params.isProfilingSelected) {
  38. integrations.push(`Sentry.browserProfilingIntegration()`);
  39. }
  40. if (params.isReplaySelected) {
  41. integrations.push(
  42. `Sentry.replayIntegration(${getReplayConfigOptions(params.replayOptions)})`
  43. );
  44. }
  45. if (params.isFeedbackSelected) {
  46. integrations.push(
  47. `
  48. Sentry.feedbackIntegration({
  49. // Additional SDK configuration goes in here, for example:
  50. colorScheme: "system",
  51. ${getFeedbackConfigOptions(params.feedbackOptions)}
  52. })`
  53. );
  54. }
  55. return integrations;
  56. };
  57. const getDynamicParts = (params: Params): string[] => {
  58. const dynamicParts: string[] = [];
  59. if (params.isPerformanceSelected) {
  60. dynamicParts.push(`
  61. // Tracing
  62. tracesSampleRate: 1.0, // Capture 100% of the transactions
  63. // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
  64. tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/]`);
  65. }
  66. if (params.isReplaySelected) {
  67. dynamicParts.push(`
  68. // Session Replay
  69. replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
  70. replaysOnErrorSampleRate: 1.0 // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.`);
  71. }
  72. if (params.isProfilingSelected) {
  73. dynamicParts.push(`
  74. // Set profilesSampleRate to 1.0 to profile every transaction.
  75. // Since profilesSampleRate is relative to tracesSampleRate,
  76. // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  77. // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  78. // results in 25% of transactions being profiled (0.5*0.5=0.25)
  79. profilesSampleRate: 1.0`);
  80. }
  81. return dynamicParts;
  82. };
  83. const getSdkClientSetupSnippet = (params: Params) => {
  84. const config = buildSdkConfig({
  85. params,
  86. staticParts: [`dsn: "${params.dsn.public}"`],
  87. getIntegrations,
  88. getDynamicParts,
  89. });
  90. return `
  91. import * as Sentry from "@sentry/solidstart";
  92. ${params.isPerformanceSelected ? 'import { solidRouterBrowserTracingIntegration } from "@sentry/solidstart/solidrouter";' : ''}
  93. import { mount, StartClient } from "@solidjs/start/client";
  94. Sentry.init({
  95. ${config}
  96. });
  97. mount(() => <StartClient />, document.getElementById("app"));
  98. `;
  99. };
  100. const getSdkServerSetupSnippet = (params: Params) => `
  101. import * as Sentry from "@sentry/solidstart";
  102. Sentry.init({
  103. dsn: "${params.dsn.public}",
  104. ${
  105. params.isPerformanceSelected
  106. ? `
  107. // Performance Monitoring
  108. tracesSampleRate: 1.0, // Capture 100% of the transactions
  109. // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
  110. tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/],`
  111. : ''
  112. }${
  113. params.isProfilingSelected
  114. ? `
  115. // Set profilesSampleRate to 1.0 to profile every transaction.
  116. // Since profilesSampleRate is relative to tracesSampleRate,
  117. // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  118. // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  119. // results in 25% of transactions being profiled (0.5*0.5=0.25)
  120. profilesSampleRate: 1.0,`
  121. : ''
  122. }
  123. });
  124. `;
  125. const getSdkMiddlewareSetup = () => `
  126. import { sentryBeforeResponseMiddleware } from '@sentry/solidstart/middleware';
  127. import { createMiddleware } from '@solidjs/start/middleware';
  128. export default createMiddleware({
  129. onBeforeResponse: [
  130. sentryBeforeResponseMiddleware(),
  131. // Add your other middleware handlers after \`sentryBeforeResponseMiddleware\`
  132. ],
  133. });
  134. `;
  135. const getSdkMiddlewareLinkSetup = () => `
  136. import { defineConfig } from "@solidjs/start/config";
  137. export default defineConfig({
  138. middleware: "./src/middleware.ts"
  139. // Other configuration options
  140. // ...
  141. });
  142. `;
  143. const getSdkRouterWrappingSetup = () => `
  144. import { Router } from "@solidjs/router";
  145. import { FileRoutes } from "@solidjs/start/router";
  146. import { withSentryRouterRouting } from "@sentry/solidstart/solidrouter";
  147. const SentryRouter = withSentryRouterRouting(Router);
  148. export default function App() {
  149. return (
  150. <SentryRouter>
  151. <FileRoutes />
  152. </SentryRouter>
  153. );
  154. }
  155. `;
  156. const getSdkRun = () => `
  157. {
  158. "scripts": {
  159. "start": "NODE_OPTIONS='--import ./public/instrument.server.mjs' vinxi start"
  160. }
  161. }
  162. `;
  163. const getVerifySnippet = () => `
  164. <button
  165. type="button"
  166. onClick={() => {
  167. throw new Error("Sentry Frontend Error");
  168. }}
  169. >
  170. Throw error
  171. </button>`;
  172. const getInstallConfig = () => [
  173. {
  174. language: 'bash',
  175. code: [
  176. {
  177. label: 'npm',
  178. value: 'npm',
  179. language: 'bash',
  180. code: 'npm install --save @sentry/solidstart',
  181. },
  182. {
  183. label: 'yarn',
  184. value: 'yarn',
  185. language: 'bash',
  186. code: 'yarn add @sentry/solidstart',
  187. },
  188. {
  189. label: 'pnpm',
  190. value: 'pnpm',
  191. language: 'bash',
  192. code: `pnpm add @sentry/solidstart`,
  193. },
  194. ],
  195. },
  196. ];
  197. const onboarding: OnboardingConfig = {
  198. introduction: params => (
  199. <Fragment>
  200. <MaybeBrowserProfilingBetaWarning {...params} />
  201. <p>
  202. {tct(
  203. 'In this quick guide you’ll use [strong:npm], [strong:yarn] or [strong:pnpm] to set up:',
  204. {
  205. strong: <strong />,
  206. }
  207. )}
  208. </p>
  209. </Fragment>
  210. ),
  211. install: () => [
  212. {
  213. type: StepType.INSTALL,
  214. description: tct(
  215. 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn] or [code:pnpm]:',
  216. {
  217. code: <code />,
  218. }
  219. ),
  220. configurations: getInstallConfig(),
  221. },
  222. ],
  223. configure: (params: Params) => [
  224. {
  225. type: StepType.CONFIGURE,
  226. description: t(
  227. "Initialize Sentry as early as possible in your application's lifecycle."
  228. ),
  229. configurations: [
  230. {
  231. description: tct(
  232. 'For the client, initialize the Sentry SDK in your [code:src/entry-client.tsx] file',
  233. {code: <code />}
  234. ),
  235. code: [
  236. {
  237. label: 'TypeScript',
  238. // value and language are in JS to get consistent syntax highlighting
  239. // we aren't using any Typescript specific code in these snippets but
  240. // want a typescript ending.
  241. value: 'javascript',
  242. language: 'javascript',
  243. code: getSdkClientSetupSnippet(params),
  244. },
  245. ],
  246. },
  247. {
  248. description: tct(
  249. 'For the server, create an instrument file [code:instrument.server.mjs], initialize the Sentry SDK and deploy it alongside your application. For example by placing it in the [code:public] folder.',
  250. {code: <code />}
  251. ),
  252. code: [
  253. {
  254. label: 'JavaScript',
  255. value: 'javascript',
  256. language: 'javascript',
  257. code: getSdkServerSetupSnippet(params),
  258. },
  259. ],
  260. additionalInfo: tct(
  261. 'Note: Placing [code:instrument.server.mjs] inside the [code:public] folder makes it accessible to the outside world. Consider blocking requests to this file or finding a more appropriate location which your backend can access.',
  262. {code: <code />}
  263. ),
  264. },
  265. ...(params.isPerformanceSelected
  266. ? [
  267. {
  268. description: tct(
  269. 'Complete the setup by adding the Sentry [solidStartMiddlewareLink: middleware] to your [code:src/middleware.ts] file',
  270. {
  271. code: <code />,
  272. solidStartMiddlewareLink: (
  273. <ExternalLink href="https://docs.solidjs.com/solid-start/advanced/middleware" />
  274. ),
  275. }
  276. ),
  277. code: [
  278. {
  279. label: 'TypeScript',
  280. // value and language are in JS to get consistent syntax highlighting
  281. // we aren't using any Typescript specific code in these snippets but
  282. // want a typescript ending.
  283. value: 'javascript',
  284. language: 'javascript',
  285. code: getSdkMiddlewareSetup(),
  286. },
  287. ],
  288. },
  289. {
  290. description: tct('And including it in the [code:app.config.ts] file', {
  291. code: <code />,
  292. }),
  293. code: [
  294. {
  295. label: 'TypeScript',
  296. value: 'javascript',
  297. language: 'javascript',
  298. code: getSdkMiddlewareLinkSetup(),
  299. },
  300. ],
  301. },
  302. {
  303. description: tct(
  304. "If you're using [solidRouterLink:Solid Router], wrap your [code:Router] with [code:withSentryRouterRouting]. This creates a higher order component, which will enable Sentry to collect navigation spans.",
  305. {
  306. code: <code />,
  307. solidRouterLink: (
  308. <ExternalLink href="https://docs.solidjs.com/solid-router" />
  309. ),
  310. }
  311. ),
  312. code: [
  313. {
  314. label: 'TypeScript',
  315. value: 'typescript',
  316. language: 'typescript',
  317. code: getSdkRouterWrappingSetup(),
  318. },
  319. ],
  320. },
  321. ]
  322. : []),
  323. ...(params.isProfilingSelected
  324. ? [getProfilingDocumentHeaderConfigurationStep()]
  325. : []),
  326. {
  327. description: tct(
  328. 'Add an [code:--import] flag to the [code:NODE_OPTIONS] environment variable wherever you run your application to import [code:public/instrument.server.mjs]. For example, update your [code:scripts] entry in [code:package.json]',
  329. {
  330. code: <code />,
  331. }
  332. ),
  333. code: [
  334. {
  335. label: 'JSON',
  336. value: 'json',
  337. language: 'json',
  338. code: getSdkRun(),
  339. },
  340. ],
  341. },
  342. ],
  343. },
  344. {
  345. title: t('Upload Source Maps'),
  346. description: tct(
  347. 'To upload source maps to Sentry, follow the [link:instructions in our documentation].',
  348. {
  349. link: (
  350. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/solidstart/#add-readable-stack-traces-to-errors" />
  351. ),
  352. }
  353. ),
  354. },
  355. ],
  356. verify: () => [
  357. {
  358. type: StepType.VERIFY,
  359. description: t(
  360. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  361. ),
  362. configurations: [
  363. {
  364. code: [
  365. {
  366. label: 'JavaScript',
  367. value: 'javascript',
  368. language: 'javascript',
  369. code: getVerifySnippet(),
  370. },
  371. ],
  372. },
  373. ],
  374. },
  375. ],
  376. nextSteps: () => [
  377. {
  378. id: 'solid-features',
  379. name: t('Solid Features'),
  380. description: t('Learn about our first class integration with the Solid framework.'),
  381. link: 'https://docs.sentry.io/platforms/javascript/guides/solid/features/',
  382. },
  383. ],
  384. };
  385. const replayOnboarding: OnboardingConfig = {
  386. install: () => [
  387. {
  388. type: StepType.INSTALL,
  389. description: tct(
  390. 'You need a minimum version 8.9.1 of [code:@sentry/solid] in order to use Session Replay. You do not need to install any additional packages.',
  391. {
  392. code: <code />,
  393. }
  394. ),
  395. configurations: getInstallConfig(),
  396. },
  397. ],
  398. configure: (params: Params) => [
  399. {
  400. type: StepType.CONFIGURE,
  401. description: getReplayConfigureDescription({
  402. link: 'https://docs.sentry.io/platforms/javascript/guides/solid/session-replay/',
  403. }),
  404. configurations: [
  405. {
  406. code: [
  407. {
  408. label: 'JavaScript',
  409. value: 'javascript',
  410. language: 'javascript',
  411. code: getSdkClientSetupSnippet(params),
  412. },
  413. ],
  414. additionalInfo: <TracePropagationMessage />,
  415. },
  416. ],
  417. },
  418. ],
  419. verify: getReplayVerifyStep(),
  420. nextSteps: () => [],
  421. };
  422. const feedbackOnboarding: OnboardingConfig = {
  423. install: () => [
  424. {
  425. type: StepType.INSTALL,
  426. description: tct(
  427. 'For the User Feedback integration to work, you must have the Sentry browser SDK package, or an equivalent framework SDK (e.g. [code:@sentry/solid]) installed, minimum version 7.85.0.',
  428. {
  429. code: <code />,
  430. }
  431. ),
  432. configurations: getInstallConfig(),
  433. },
  434. ],
  435. configure: (params: Params) => [
  436. {
  437. type: StepType.CONFIGURE,
  438. description: getFeedbackConfigureDescription({
  439. linkConfig:
  440. 'https://docs.sentry.io/platforms/javascript/guides/solid/user-feedback/configuration/',
  441. linkButton:
  442. 'https://docs.sentry.io/platforms/javascript/guides/solid/user-feedback/configuration/#bring-your-own-button',
  443. }),
  444. configurations: [
  445. {
  446. code: [
  447. {
  448. label: 'JavaScript',
  449. value: 'javascript',
  450. language: 'javascript',
  451. code: getSdkClientSetupSnippet(params),
  452. },
  453. ],
  454. },
  455. ],
  456. additionalInfo: crashReportCallout({
  457. link: 'https://docs.sentry.io/platforms/javascript/guides/solid/user-feedback/#crash-report-modal',
  458. }),
  459. },
  460. ],
  461. verify: () => [],
  462. nextSteps: () => [],
  463. };
  464. const crashReportOnboarding: OnboardingConfig = {
  465. introduction: () => getCrashReportModalIntroduction(),
  466. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  467. configure: () => [
  468. {
  469. type: StepType.CONFIGURE,
  470. description: getCrashReportModalConfigDescription({
  471. link: 'https://docs.sentry.io/platforms/javascript/guides/solid/user-feedback/configuration/#crash-report-modal',
  472. }),
  473. additionalInfo: widgetCallout({
  474. link: 'https://docs.sentry.io/platforms/javascript/guides/solid/user-feedback/#user-feedback-widget',
  475. }),
  476. },
  477. ],
  478. verify: () => [],
  479. nextSteps: () => [],
  480. };
  481. const profilingOnboarding: OnboardingConfig = {
  482. ...onboarding,
  483. introduction: params => <MaybeBrowserProfilingBetaWarning {...params} />,
  484. };
  485. const docs: Docs = {
  486. onboarding,
  487. feedbackOnboardingNpm: feedbackOnboarding,
  488. replayOnboarding,
  489. crashReportOnboarding,
  490. profilingOnboarding,
  491. featureFlagOnboarding,
  492. };
  493. export default docs;