javascript.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. import {css} from '@emotion/react';
  2. import {SdkProviderEnum as FeatureFlagProviderEnum} from 'sentry/components/events/featureFlags/utils';
  3. import ExternalLink from 'sentry/components/links/externalLink';
  4. import {buildSdkConfig} from 'sentry/components/onboarding/gettingStartedDoc/buildSdkConfig';
  5. import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/crashReportCallout';
  6. import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
  7. import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
  8. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  9. import type {
  10. BasePlatformOptions,
  11. Docs,
  12. DocsParams,
  13. OnboardingConfig,
  14. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  15. import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
  16. import {
  17. getCrashReportJavaScriptInstallStep,
  18. getCrashReportModalConfigDescription,
  19. getCrashReportModalIntroduction,
  20. getFeedbackConfigOptions,
  21. getFeedbackConfigureDescription,
  22. } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
  23. import {
  24. getProfilingDocumentHeaderConfigurationStep,
  25. MaybeBrowserProfilingBetaWarning,
  26. } from 'sentry/components/onboarding/gettingStartedDoc/utils/profilingOnboarding';
  27. import {
  28. getReplayConfigOptions,
  29. getReplayConfigureDescription,
  30. getReplayVerifyStep,
  31. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  32. import {
  33. feedbackOnboardingJsLoader,
  34. replayOnboardingJsLoader,
  35. } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader';
  36. import {t, tct} from 'sentry/locale';
  37. import {space} from 'sentry/styles/space';
  38. import {trackAnalytics} from 'sentry/utils/analytics';
  39. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  40. import {updateDynamicSdkLoaderOptions} from './jsLoader/updateDynamicSdkLoaderOptions';
  41. export enum InstallationMode {
  42. AUTO = 'auto',
  43. MANUAL = 'manual',
  44. }
  45. const platformOptions = {
  46. installationMode: {
  47. label: t('Installation Mode'),
  48. items: [
  49. {
  50. label: t('Loader Script'),
  51. value: InstallationMode.AUTO,
  52. },
  53. {
  54. label: t('Npm/Yarn'),
  55. value: InstallationMode.MANUAL,
  56. },
  57. ],
  58. defaultValue: InstallationMode.AUTO,
  59. },
  60. } satisfies BasePlatformOptions;
  61. type PlatformOptions = typeof platformOptions;
  62. type Params = DocsParams<PlatformOptions>;
  63. type FeatureFlagConfiguration = {
  64. integrationName: string;
  65. makeConfigureCode: (dsn: string) => string;
  66. makeVerifyCode: () => string;
  67. packageName: string;
  68. };
  69. const FEATURE_FLAG_CONFIGURATION_MAP: Record<
  70. FeatureFlagProviderEnum,
  71. FeatureFlagConfiguration
  72. > = {
  73. [FeatureFlagProviderEnum.GENERIC]: {
  74. integrationName: `featureFlagsIntegration`,
  75. packageName: '',
  76. makeConfigureCode: (dsn: string) => `import * as Sentry from "@sentry/browser";
  77. Sentry.init({
  78. dsn: "${dsn}",
  79. integrations: [Sentry.featureFlagsIntegration()],
  80. });`,
  81. makeVerifyCode:
  82. () => `const flagsIntegration = Sentry.getClient()?.getIntegrationByName<Sentry.FeatureFlagsIntegration>("FeatureFlags");
  83. if (flagsIntegration) {
  84. flagsIntegration.addFeatureFlag("test-flag", false);
  85. } else {
  86. // Something went wrong, check your DSN and/or integrations
  87. }
  88. Sentry.captureException(new Error("Something went wrong!"));`,
  89. },
  90. [FeatureFlagProviderEnum.LAUNCHDARKLY]: {
  91. integrationName: `launchDarklyIntegration`,
  92. packageName: 'launchdarkly-js-client-sdk',
  93. makeConfigureCode: (dsn: string) => `import * as Sentry from "@sentry/browser";
  94. import * as LaunchDarkly from "launchdarkly-js-client-sdk";
  95. Sentry.init({
  96. dsn: "${dsn}",
  97. integrations: [Sentry.launchDarklyIntegration()],
  98. });
  99. const ldClient = LaunchDarkly.initialize(
  100. "my-client-ID",
  101. { kind: "user", key: "my-user-context-key" },
  102. { inspectors: [Sentry.buildLaunchDarklyFlagUsedHandler()] },
  103. );`,
  104. makeVerifyCode: () => `// You may have to wait for your client to initialize first.
  105. ldClient?.variation("test-flag", false);
  106. Sentry.captureException(new Error("Something went wrong!"));`,
  107. },
  108. [FeatureFlagProviderEnum.OPENFEATURE]: {
  109. integrationName: `openFeatureIntegration`,
  110. packageName: '@openfeature/web-sdk',
  111. makeConfigureCode: (dsn: string) => `import * as Sentry from "@sentry/browser";
  112. import { OpenFeature } from "@openfeature/web-sdk";
  113. Sentry.init({
  114. dsn: "${dsn}",
  115. integrations: [Sentry.openFeatureIntegration()],
  116. });
  117. OpenFeature.setProvider(new MyProviderOfChoice());
  118. OpenFeature.addHooks(new Sentry.OpenFeatureIntegrationHook());`,
  119. makeVerifyCode: () => `const client = OpenFeature.getClient();
  120. const result = client.getBooleanValue("test-flag", false);
  121. Sentry.captureException(new Error("Something went wrong!"));`,
  122. },
  123. [FeatureFlagProviderEnum.STATSIG]: {
  124. integrationName: `statsigIntegration`,
  125. packageName: '@statsig/js-client',
  126. makeConfigureCode: (dsn: string) => `import * as Sentry from "@sentry/browser";
  127. import { StatsigClient } from "@statsig/js-client";
  128. const statsigClient = new StatsigClient(
  129. YOUR_SDK_KEY,
  130. { userID: "my-user-id" },
  131. {},
  132. ); // see Statsig SDK reference.
  133. Sentry.init({
  134. dsn: "${dsn}",
  135. integrations: [
  136. Sentry.statsigIntegration({ featureFlagClient: statsigClient }),
  137. ],
  138. });`,
  139. makeVerifyCode:
  140. () => `await statsigClient.initializeAsync(); // or statsigClient.initializeSync();
  141. const result = statsigClient.checkGate("my-feature-gate");
  142. Sentry.captureException(new Error("something went wrong"));`,
  143. },
  144. [FeatureFlagProviderEnum.UNLEASH]: {
  145. integrationName: `unleashIntegration`,
  146. packageName: 'unleash-proxy-client',
  147. makeConfigureCode: (dsn: string) => `import * as Sentry from "@sentry/browser";
  148. import { UnleashClient } from "unleash-proxy-client";
  149. Sentry.init({
  150. dsn: "${dsn}",
  151. integrations: [
  152. Sentry.unleashIntegration({ featureFlagClientClass: UnleashClient }),
  153. ],
  154. });
  155. const unleash = new UnleashClient({
  156. url: "https://<your-unleash-instance>/api/frontend",
  157. clientKey: "<your-client-side-token>",
  158. appName: "my-webapp",
  159. });
  160. unleash.start();`,
  161. makeVerifyCode: () => `// You may have to wait for your client to synchronize first.
  162. unleash.isEnabled("test-flag");
  163. Sentry.captureException(new Error("Something went wrong!"));`,
  164. },
  165. };
  166. const isAutoInstall = (params: Params) =>
  167. params.platformOptions.installationMode === InstallationMode.AUTO;
  168. const getIntegrations = (params: Params): string[] => {
  169. const integrations = [];
  170. if (params.isPerformanceSelected) {
  171. integrations.push(`Sentry.browserTracingIntegration()`);
  172. }
  173. if (params.isProfilingSelected) {
  174. integrations.push(`Sentry.browserProfilingIntegration()`);
  175. }
  176. if (params.isReplaySelected) {
  177. integrations.push(
  178. `Sentry.replayIntegration(${getReplayConfigOptions(params.replayOptions)})`
  179. );
  180. }
  181. if (params.isFeedbackSelected) {
  182. integrations.push(`
  183. Sentry.feedbackIntegration({
  184. colorScheme: "system",
  185. ${getFeedbackConfigOptions(params.feedbackOptions)}
  186. }),`);
  187. }
  188. return integrations;
  189. };
  190. const getDynamicParts = (params: Params): string[] => {
  191. const dynamicParts: string[] = [];
  192. if (params.isPerformanceSelected) {
  193. dynamicParts.push(`
  194. // Tracing
  195. tracesSampleRate: 1.0, // Capture 100% of the transactions
  196. // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
  197. tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/]`);
  198. }
  199. if (params.isReplaySelected) {
  200. dynamicParts.push(`
  201. // Session Replay
  202. 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.
  203. replaysOnErrorSampleRate: 1.0 // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.`);
  204. }
  205. if (params.isProfilingSelected) {
  206. dynamicParts.push(`
  207. // Set profilesSampleRate to 1.0 to profile every transaction.
  208. // Since profilesSampleRate is relative to tracesSampleRate,
  209. // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  210. // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  211. // results in 25% of transactions being profiled (0.5*0.5=0.25)
  212. profilesSampleRate: 1.0`);
  213. }
  214. return dynamicParts;
  215. };
  216. const getSdkSetupSnippet = (params: Params) => {
  217. const config = buildSdkConfig({
  218. params,
  219. staticParts: [`dsn: "${params.dsn.public}"`],
  220. getIntegrations,
  221. getDynamicParts,
  222. });
  223. return `
  224. import * as Sentry from "@sentry/browser";
  225. Sentry.init({
  226. ${config}
  227. });
  228. `;
  229. };
  230. const getVerifyJSSnippet = () => `
  231. myUndefinedFunction();`;
  232. const getInstallConfig = () => [
  233. {
  234. language: 'bash',
  235. code: [
  236. {
  237. label: 'npm',
  238. value: 'npm',
  239. language: 'bash',
  240. code: 'npm install --save @sentry/browser',
  241. },
  242. {
  243. label: 'yarn',
  244. value: 'yarn',
  245. language: 'bash',
  246. code: 'yarn add @sentry/browser',
  247. },
  248. ],
  249. },
  250. ];
  251. const getVerifyConfig = () => [
  252. {
  253. type: StepType.VERIFY,
  254. description: t(
  255. "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
  256. ),
  257. configurations: [
  258. {
  259. code: [
  260. {
  261. label: 'Javascript',
  262. value: 'javascript',
  263. language: 'javascript',
  264. code: getVerifyJSSnippet(),
  265. },
  266. ],
  267. },
  268. ],
  269. },
  270. ];
  271. const loaderScriptOnboarding: OnboardingConfig<PlatformOptions> = {
  272. introduction: () =>
  273. tct('In this quick guide you’ll use our [strong: Loader Script] to set up:', {
  274. strong: <strong />,
  275. }),
  276. install: params => [
  277. {
  278. type: StepType.INSTALL,
  279. description: t('Add this script tag to the top of the page:'),
  280. configurations: [
  281. {
  282. language: 'html',
  283. code: [
  284. {
  285. label: 'HTML',
  286. value: 'html',
  287. language: 'html',
  288. code: `
  289. <script
  290. src="${params.dsn.cdn}"
  291. crossorigin="anonymous"
  292. ></script>`,
  293. },
  294. ],
  295. },
  296. ],
  297. },
  298. ],
  299. configure: params => [
  300. {
  301. title: t('Configure SDK (Optional)'),
  302. description: t(
  303. "Initialize Sentry as early as possible in your application's lifecycle."
  304. ),
  305. collapsible: true,
  306. configurations: [
  307. {
  308. language: 'html',
  309. code: [
  310. {
  311. label: 'HTML',
  312. value: 'html',
  313. language: 'html',
  314. code: `
  315. <script>
  316. Sentry.onLoad(function() {
  317. Sentry.init({${
  318. params.isPerformanceSelected || params.isReplaySelected
  319. ? ''
  320. : `
  321. // You can add any additional configuration here`
  322. }${
  323. params.isPerformanceSelected
  324. ? `
  325. // Tracing
  326. tracesSampleRate: 1.0, // Capture 100% of the transactions`
  327. : ''
  328. }${
  329. params.isReplaySelected
  330. ? `
  331. // Session Replay
  332. 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.
  333. replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.`
  334. : ''
  335. }
  336. });
  337. });
  338. </script>`,
  339. },
  340. ],
  341. },
  342. ],
  343. onOptionalToggleClick: showOptionalConfig => {
  344. if (showOptionalConfig) {
  345. trackAnalytics('onboarding.js_loader_npm_docs_optional_shown', {
  346. organization: params.organization,
  347. platform: params.platformKey,
  348. project_id: params.projectId,
  349. });
  350. }
  351. },
  352. },
  353. ],
  354. verify: getVerifyConfig,
  355. nextSteps: () => [
  356. {
  357. id: 'source-maps',
  358. name: t('Source Maps'),
  359. description: t('Learn how to enable readable stack traces in your Sentry errors.'),
  360. link: 'https://docs.sentry.io/platforms/javascript/sourcemaps/',
  361. },
  362. ],
  363. onPageLoad: params => {
  364. return () => {
  365. trackAnalytics('onboarding.setup_loader_docs_rendered', {
  366. organization: params.organization,
  367. platform: params.platformKey,
  368. project_id: params.projectId,
  369. });
  370. };
  371. },
  372. onPlatformOptionsChange: params => {
  373. return () => {
  374. trackAnalytics('onboarding.js_loader_npm_docs_shown', {
  375. organization: params.organization,
  376. platform: params.platformKey,
  377. project_id: params.projectId,
  378. });
  379. };
  380. },
  381. onProductSelectionChange: params => {
  382. return products => {
  383. updateDynamicSdkLoaderOptions({
  384. orgSlug: params.organization.slug,
  385. projectSlug: params.projectSlug,
  386. products,
  387. projectKey: params.projectKeyId,
  388. api: params.api,
  389. });
  390. };
  391. },
  392. onProductSelectionLoad: params => {
  393. return products => {
  394. updateDynamicSdkLoaderOptions({
  395. orgSlug: params.organization.slug,
  396. projectSlug: params.projectSlug,
  397. products,
  398. projectKey: params.projectKeyId,
  399. api: params.api,
  400. });
  401. };
  402. },
  403. };
  404. const packageManagerOnboarding: OnboardingConfig<PlatformOptions> = {
  405. introduction: () =>
  406. tct('In this quick guide you’ll use [strong:npm] or [strong:yarn] to set up:', {
  407. strong: <strong />,
  408. }),
  409. install: () => [
  410. {
  411. type: StepType.INSTALL,
  412. description: t(
  413. 'Sentry captures data by using an SDK within your application’s runtime.'
  414. ),
  415. configurations: getInstallConfig(),
  416. },
  417. ],
  418. configure: params => [
  419. {
  420. type: StepType.CONFIGURE,
  421. description: t(
  422. "Initialize Sentry as early as possible in your application's lifecycle."
  423. ),
  424. configurations: [
  425. {
  426. code: [
  427. {
  428. label: 'JavaScript',
  429. value: 'javascript',
  430. language: 'javascript',
  431. code: getSdkSetupSnippet(params),
  432. },
  433. ],
  434. },
  435. ...(params.isProfilingSelected
  436. ? [getProfilingDocumentHeaderConfigurationStep()]
  437. : []),
  438. ],
  439. },
  440. getUploadSourceMapsStep({
  441. guideLink: 'https://docs.sentry.io/platforms/javascript/sourcemaps/',
  442. ...params,
  443. }),
  444. ],
  445. verify: getVerifyConfig,
  446. nextSteps: () => [],
  447. onPageLoad: params => {
  448. return () => {
  449. trackAnalytics('onboarding.js_loader_npm_docs_shown', {
  450. organization: params.organization,
  451. platform: params.platformKey,
  452. project_id: params.projectId,
  453. });
  454. };
  455. },
  456. onProductSelectionChange: params => {
  457. return products => {
  458. updateDynamicSdkLoaderOptions({
  459. orgSlug: params.organization.slug,
  460. projectSlug: params.projectSlug,
  461. products,
  462. projectKey: params.projectKeyId,
  463. api: params.api,
  464. });
  465. };
  466. },
  467. onProductSelectionLoad: params => {
  468. return products => {
  469. updateDynamicSdkLoaderOptions({
  470. orgSlug: params.organization.slug,
  471. projectSlug: params.projectSlug,
  472. products,
  473. projectKey: params.projectKeyId,
  474. api: params.api,
  475. });
  476. };
  477. },
  478. onPlatformOptionsChange: params => {
  479. return () => {
  480. trackAnalytics('onboarding.setup_loader_docs_rendered', {
  481. organization: params.organization,
  482. platform: params.platformKey,
  483. project_id: params.projectId,
  484. });
  485. };
  486. },
  487. };
  488. const onboarding: OnboardingConfig<PlatformOptions> = {
  489. introduction: params => (
  490. <div
  491. css={css`
  492. display: flex;
  493. flex-direction: column;
  494. gap: ${space(1)};
  495. `}
  496. >
  497. <MaybeBrowserProfilingBetaWarning {...params} />
  498. <TextBlock noMargin>
  499. {isAutoInstall(params)
  500. ? loaderScriptOnboarding.introduction?.(params)
  501. : packageManagerOnboarding.introduction?.(params)}
  502. </TextBlock>
  503. </div>
  504. ),
  505. install: params =>
  506. isAutoInstall(params)
  507. ? loaderScriptOnboarding.install(params)
  508. : packageManagerOnboarding.install(params),
  509. configure: (params: Params) =>
  510. isAutoInstall(params)
  511. ? loaderScriptOnboarding.configure(params)
  512. : packageManagerOnboarding.configure(params),
  513. verify: params =>
  514. isAutoInstall(params)
  515. ? loaderScriptOnboarding.verify(params)
  516. : packageManagerOnboarding.verify(params),
  517. nextSteps: params =>
  518. isAutoInstall(params)
  519. ? loaderScriptOnboarding.nextSteps?.(params)
  520. : packageManagerOnboarding.nextSteps?.(params),
  521. onPageLoad: params =>
  522. isAutoInstall(params)
  523. ? loaderScriptOnboarding.onPageLoad?.(params)
  524. : packageManagerOnboarding.onPageLoad?.(params),
  525. onProductSelectionChange: params =>
  526. isAutoInstall(params)
  527. ? loaderScriptOnboarding.onProductSelectionChange?.(params)
  528. : packageManagerOnboarding.onProductSelectionChange?.(params),
  529. onPlatformOptionsChange: params =>
  530. isAutoInstall(params)
  531. ? loaderScriptOnboarding.onPlatformOptionsChange?.(params)
  532. : packageManagerOnboarding.onPlatformOptionsChange?.(params),
  533. onProductSelectionLoad: params =>
  534. isAutoInstall(params)
  535. ? loaderScriptOnboarding.onProductSelectionLoad?.(params)
  536. : packageManagerOnboarding.onProductSelectionLoad?.(params),
  537. };
  538. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  539. install: () => [
  540. {
  541. type: StepType.INSTALL,
  542. description: tct(
  543. 'For the Session Replay to work, you must have the Sentry browser SDK package, or an equivalent framework SDK (e.g. [code:@sentry/react]) installed, minimum version 7.27.0.',
  544. {
  545. code: <code />,
  546. }
  547. ),
  548. configurations: getInstallConfig(),
  549. },
  550. ],
  551. configure: (params: Params) => [
  552. {
  553. type: StepType.CONFIGURE,
  554. description: getReplayConfigureDescription({
  555. link: 'https://docs.sentry.io/platforms/javascript/session-replay/',
  556. }),
  557. configurations: [
  558. {
  559. code: [
  560. {
  561. label: 'JavaScript',
  562. value: 'javascript',
  563. language: 'javascript',
  564. code: getSdkSetupSnippet(params),
  565. },
  566. ],
  567. },
  568. ],
  569. additionalInfo: <TracePropagationMessage />,
  570. },
  571. ],
  572. verify: getReplayVerifyStep(),
  573. nextSteps: () => [],
  574. };
  575. const feedbackOnboarding: OnboardingConfig<PlatformOptions> = {
  576. install: () => [
  577. {
  578. type: StepType.INSTALL,
  579. description: tct(
  580. 'For the User Feedback integration to work, you must have the Sentry browser SDK package, or an equivalent framework SDK (e.g. [code:@sentry/react]) installed, minimum version 7.85.0.',
  581. {
  582. code: <code />,
  583. }
  584. ),
  585. configurations: getInstallConfig(),
  586. },
  587. ],
  588. configure: (params: Params) => [
  589. {
  590. type: StepType.CONFIGURE,
  591. description: getFeedbackConfigureDescription({
  592. linkConfig:
  593. 'https://docs.sentry.io/platforms/javascript/user-feedback/configuration/',
  594. linkButton:
  595. 'https://docs.sentry.io/platforms/javascript/user-feedback/configuration/#bring-your-own-button',
  596. }),
  597. configurations: [
  598. {
  599. code: [
  600. {
  601. label: 'JavaScript',
  602. value: 'javascript',
  603. language: 'javascript',
  604. code: getSdkSetupSnippet(params),
  605. },
  606. ],
  607. },
  608. ],
  609. additionalInfo: crashReportCallout({
  610. link: 'https://docs.sentry.io/platforms/javascript/user-feedback/#crash-report-modal',
  611. }),
  612. },
  613. ],
  614. verify: () => [],
  615. nextSteps: () => [],
  616. };
  617. const crashReportOnboarding: OnboardingConfig<PlatformOptions> = {
  618. introduction: () => getCrashReportModalIntroduction(),
  619. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  620. configure: () => [
  621. {
  622. type: StepType.CONFIGURE,
  623. description: getCrashReportModalConfigDescription({
  624. link: 'https://docs.sentry.io/platforms/javascript/user-feedback/configuration/#crash-report-modal',
  625. }),
  626. additionalInfo: widgetCallout({
  627. link: 'https://docs.sentry.io/platforms/javascript/user-feedback/#user-feedback-widget',
  628. }),
  629. },
  630. ],
  631. verify: () => [],
  632. nextSteps: () => [],
  633. };
  634. const performanceOnboarding: OnboardingConfig<PlatformOptions> = {
  635. introduction: () =>
  636. t(
  637. "Adding Performance to your Browser JavaScript project is simple. Make sure you've got these basics down."
  638. ),
  639. install: () => [
  640. {
  641. type: StepType.INSTALL,
  642. description: tct(
  643. 'Install our JavaScript browser SDK using either [code:yarn] or [code:npm]:',
  644. {code: <code />}
  645. ),
  646. configurations: getInstallConfig(),
  647. },
  648. ],
  649. configure: params => [
  650. {
  651. type: StepType.CONFIGURE,
  652. configurations: [
  653. {
  654. language: 'javascript',
  655. description: t(
  656. "Configuration should happen as early as possible in your application's lifecycle."
  657. ),
  658. code: `
  659. import * as Sentry from "@sentry/browser";
  660. Sentry.init({
  661. dsn: "${params.dsn.public}",
  662. integrations: [Sentry.browserTracingIntegration()],
  663. // Set tracesSampleRate to 1.0 to capture 100%
  664. // of transactions for performance monitoring.
  665. // We recommend adjusting this value in production
  666. tracesSampleRate: 1.0,
  667. // Set \`tracePropagationTargets\` to control for which URLs distributed tracing should be enabled
  668. tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
  669. });
  670. `,
  671. additionalInfo: tct(
  672. 'We recommend adjusting the value of [code:tracesSampleRate] in production. Learn more about tracing [linkTracingOptions:options], how to use the [linkTracesSampler:traces_sampler] function, or how to do [linkSampleTransactions:sampling].',
  673. {
  674. code: <code />,
  675. linkTracingOptions: (
  676. <ExternalLink href="https://docs.sentry.io/platforms/javascript/configuration/options/#tracing-options" />
  677. ),
  678. linkTracesSampler: (
  679. <ExternalLink href="https://docs.sentry.io/platforms/javascript/configuration/sampling/" />
  680. ),
  681. linkSampleTransactions: (
  682. <ExternalLink href="https://docs.sentry.io/platforms/javascript/configuration/sampling/" />
  683. ),
  684. }
  685. ),
  686. },
  687. {
  688. language: 'javascript',
  689. description: tct(
  690. "If you're using the current version of our JavaScript SDK and have enabled the [code: BrowserTracing] integration, distributed tracing will work out of the box. To get around possible [link:Browser CORS] issues, define your [code:tracePropagationTargets].",
  691. {
  692. code: <code />,
  693. link: (
  694. <ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" />
  695. ),
  696. }
  697. ),
  698. code: `
  699. Sentry.init({
  700. dsn: "${params.dsn.public}",
  701. integrations: [Sentry.browserTracingIntegration()],
  702. tracePropagationTargets: ["https://myproject.org", /^\/api\//],
  703. });
  704. `,
  705. },
  706. ],
  707. },
  708. ],
  709. verify: () => [
  710. {
  711. type: StepType.VERIFY,
  712. description: tct(
  713. 'Verify that performance monitoring is working correctly with our [link:automatic instrumentation] by simply using your JavaScript application.',
  714. {
  715. link: (
  716. <ExternalLink href="https://docs.sentry.io/platforms/javascript/tracing/instrumentation/automatic-instrumentation/" />
  717. ),
  718. }
  719. ),
  720. },
  721. ],
  722. nextSteps: () => [],
  723. };
  724. const profilingOnboarding: OnboardingConfig<PlatformOptions> = {
  725. ...onboarding,
  726. introduction: params => <MaybeBrowserProfilingBetaWarning {...params} />,
  727. };
  728. export const featureFlagOnboarding: OnboardingConfig = {
  729. install: () => [],
  730. configure: ({featureFlagOptions = {integration: ''}, dsn}) => {
  731. const {integrationName, makeConfigureCode, makeVerifyCode, packageName} =
  732. FEATURE_FLAG_CONFIGURATION_MAP[
  733. featureFlagOptions.integration as keyof typeof FEATURE_FLAG_CONFIGURATION_MAP
  734. ]!;
  735. const installConfig = [
  736. {
  737. language: 'bash',
  738. code: [
  739. {
  740. label: 'npm',
  741. value: 'npm',
  742. language: 'bash',
  743. code: `npm install --save @sentry/browser ${packageName}`,
  744. },
  745. {
  746. label: 'yarn',
  747. value: 'yarn',
  748. language: 'bash',
  749. code: `yarn add @sentry/browser ${packageName}`,
  750. },
  751. ],
  752. },
  753. ];
  754. return [
  755. {
  756. type: StepType.INSTALL,
  757. description: t('Install Sentry and the selected feature flag SDK.'),
  758. configurations: installConfig,
  759. },
  760. {
  761. type: StepType.CONFIGURE,
  762. description: tct(
  763. 'Add [name] to your integrations list, and initialize your feature flag SDK.',
  764. {
  765. name: <code>{integrationName}</code>,
  766. }
  767. ),
  768. configurations: [
  769. {
  770. language: 'JavaScript',
  771. code: makeConfigureCode(dsn.public),
  772. },
  773. ],
  774. },
  775. {
  776. type: StepType.VERIFY,
  777. description: t(
  778. 'Test your setup by evaluating a flag, then capturing an exception. Check the Feature Flags table in Issue Details to confirm that your error event has recorded the flag and its result.'
  779. ),
  780. configurations: [
  781. {
  782. language: 'JavaScript',
  783. code: makeVerifyCode(),
  784. },
  785. ],
  786. },
  787. ];
  788. },
  789. verify: () => [],
  790. nextSteps: () => [],
  791. };
  792. const docs: Docs<PlatformOptions> = {
  793. onboarding,
  794. feedbackOnboardingNpm: feedbackOnboarding,
  795. feedbackOnboardingJsLoader,
  796. replayOnboarding,
  797. replayOnboardingJsLoader,
  798. performanceOnboarding,
  799. crashReportOnboarding,
  800. platformOptions,
  801. profilingOnboarding,
  802. featureFlagOnboarding,
  803. };
  804. export default docs;