nextjs.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import ExternalLink from 'sentry/components/links/externalLink';
  4. import List from 'sentry/components/list/';
  5. import ListItem from 'sentry/components/list/listItem';
  6. import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/crashReportCallout';
  7. import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
  8. import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
  9. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  10. import type {
  11. Docs,
  12. DocsParams,
  13. OnboardingConfig,
  14. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  15. import {
  16. getCrashReportJavaScriptInstallStep,
  17. getCrashReportModalConfigDescription,
  18. getCrashReportModalIntroduction,
  19. getFeedbackConfigureDescription,
  20. getFeedbackSDKSetupSnippet,
  21. } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
  22. import {getJSMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
  23. import {
  24. getReplayConfigureDescription,
  25. getReplaySDKSetupSnippet,
  26. getReplayVerifyStep,
  27. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  28. import TextCopyInput from 'sentry/components/textCopyInput';
  29. import {featureFlagOnboarding} from 'sentry/gettingStartedDocs/javascript/javascript';
  30. import {t, tct} from 'sentry/locale';
  31. import {space} from 'sentry/styles/space';
  32. import {trackAnalytics} from 'sentry/utils/analytics';
  33. type Params = DocsParams;
  34. const getInstallSnippet = ({isSelfHosted, organization, projectSlug}: Params) => {
  35. const urlParam = isSelfHosted ? '' : '--saas';
  36. return `npx @sentry/wizard@latest -i nextjs ${urlParam} --org ${organization.slug} --project ${projectSlug}`;
  37. };
  38. const getInstallConfig = (params: Params) => {
  39. return [
  40. {
  41. description: tct(
  42. 'Configure your app automatically by running the [wizardLink:Sentry wizard] in the root of your project.',
  43. {
  44. wizardLink: (
  45. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/#install" />
  46. ),
  47. }
  48. ),
  49. language: 'bash',
  50. code: getInstallSnippet(params),
  51. },
  52. ];
  53. };
  54. const getManualInstallConfig = () => [
  55. {
  56. language: 'bash',
  57. code: [
  58. {
  59. label: 'npm',
  60. value: 'npm',
  61. language: 'bash',
  62. code: 'npm install --save @sentry/nextjs',
  63. },
  64. {
  65. label: 'yarn',
  66. value: 'yarn',
  67. language: 'bash',
  68. code: 'yarn add @sentry/nextjs',
  69. },
  70. ],
  71. },
  72. ];
  73. const onboarding: OnboardingConfig = {
  74. install: (params: Params) => [
  75. {
  76. title: t('Automatic Configuration (Recommended)'),
  77. configurations: getInstallConfig(params),
  78. },
  79. ],
  80. configure: () => [
  81. {
  82. title: t('Manual Configuration'),
  83. collapsible: true,
  84. configurations: [
  85. {
  86. description: (
  87. <Fragment>
  88. <p>
  89. {tct(
  90. 'Alternatively, you can also [manualSetupLink:set up the SDK manually], by following these steps:',
  91. {
  92. manualSetupLink: (
  93. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/" />
  94. ),
  95. }
  96. )}
  97. </p>
  98. <List symbol="bullet">
  99. <ListItem>
  100. {tct(
  101. 'Create [code:sentry.server.config.js], [code:sentry.client.config.js] and [code:sentry.edge.config.js] with the default [code:Sentry.init].',
  102. {
  103. code: <code />,
  104. }
  105. )}
  106. </ListItem>
  107. <ListItem>
  108. {tct(
  109. 'Create or update the Next.js instrumentation file [instrumentationCode:instrumentation.ts] to initialize the SDK with the configuration files added in the previous step.',
  110. {
  111. instrumentationCode: <code />,
  112. }
  113. )}
  114. </ListItem>
  115. <ListItem>
  116. {tct(
  117. 'Create or update your Next.js config [nextConfig:next.config.js] with the default Sentry configuration.',
  118. {
  119. nextConfig: <code />,
  120. }
  121. )}
  122. </ListItem>
  123. <ListItem>
  124. {tct(
  125. 'Create a [bundlerPluginsEnv:.env.sentry-build-plugin] with an auth token (which is used to upload source maps when building the application).',
  126. {
  127. bundlerPluginsEnv: <code />,
  128. }
  129. )}
  130. </ListItem>
  131. <ListItem>
  132. {t('Add an example page to your app to verify your Sentry setup.')}
  133. </ListItem>
  134. </List>
  135. </Fragment>
  136. ),
  137. },
  138. ],
  139. },
  140. ],
  141. verify: (params: Params) => [
  142. {
  143. type: StepType.VERIFY,
  144. description: (
  145. <Fragment>
  146. <p>
  147. {tct(
  148. 'Start your development server and visit [code:/sentry-example-page] if you have set it up. Click the button to trigger a test error.',
  149. {
  150. code: <code />,
  151. }
  152. )}
  153. </p>
  154. <p>
  155. {t(
  156. 'Or, trigger a sample error by calling a function that does not exist somewhere in your application.'
  157. )}
  158. </p>
  159. </Fragment>
  160. ),
  161. configurations: [
  162. {
  163. code: [
  164. {
  165. label: 'Javascript',
  166. value: 'javascript',
  167. language: 'javascript',
  168. code: `myUndefinedFunction();`,
  169. },
  170. ],
  171. },
  172. ],
  173. additionalInfo: (
  174. <Fragment>
  175. <p>
  176. {t(
  177. 'If you see an issue in your Sentry dashboard, you have successfully set up Sentry with Next.js.'
  178. )}
  179. </p>
  180. <Divider />
  181. <DSNText>
  182. <p>
  183. {tct(
  184. "If you already have the configuration for Sentry in your application, and just need this project's ([projectSlug]) DSN, you can find it below:",
  185. {
  186. projectSlug: <code>{params.projectSlug}</code>,
  187. }
  188. )}
  189. </p>
  190. </DSNText>
  191. {params.organization && (
  192. <TextCopyInput
  193. onCopy={() =>
  194. trackAnalytics('onboarding.nextjs-dsn-copied', {
  195. organization: params.organization,
  196. })
  197. }
  198. >
  199. {params.dsn.public}
  200. </TextCopyInput>
  201. )}
  202. </Fragment>
  203. ),
  204. },
  205. ],
  206. };
  207. const replayOnboarding: OnboardingConfig = {
  208. install: (params: Params) => [
  209. {type: StepType.INSTALL, configurations: getInstallConfig(params)},
  210. ],
  211. configure: (params: Params) => [
  212. {
  213. type: StepType.CONFIGURE,
  214. description: getReplayConfigureDescription({
  215. link: 'https://docs.sentry.io/platforms/javascript/guides/nextjs/session-replay/',
  216. }),
  217. configurations: [
  218. {
  219. code: [
  220. {
  221. label: 'sentry.client.config.js',
  222. value: 'javascript',
  223. language: 'javascript',
  224. code: getReplaySDKSetupSnippet({
  225. importStatement: `import * as Sentry from "@sentry/nextjs";`,
  226. dsn: params.dsn.public,
  227. mask: params.replayOptions?.mask,
  228. block: params.replayOptions?.block,
  229. }),
  230. },
  231. ],
  232. },
  233. ],
  234. additionalInfo: (
  235. <Fragment>
  236. <TracePropagationMessage />
  237. {tct(
  238. 'Note: The Replay integration only needs to be added to your [code:sentry.client.config.js] file. Adding it to any server-side configuration files (like [code:instrumentation.ts]) will break your build because the Replay integration depends on Browser APIs.',
  239. {
  240. code: <code />,
  241. }
  242. )}
  243. </Fragment>
  244. ),
  245. },
  246. ],
  247. verify: getReplayVerifyStep(),
  248. nextSteps: () => [],
  249. };
  250. const feedbackOnboarding: OnboardingConfig = {
  251. install: (params: Params) => [
  252. {
  253. type: StepType.INSTALL,
  254. description: tct(
  255. 'For the User Feedback integration to work, you must have the Sentry browser SDK package, or an equivalent framework SDK (e.g. [code:@sentry/nextjs]) installed, minimum version 7.85.0.',
  256. {
  257. code: <code />,
  258. }
  259. ),
  260. configurations: getInstallConfig(params),
  261. },
  262. ],
  263. configure: (params: Params) => [
  264. {
  265. type: StepType.CONFIGURE,
  266. description: getFeedbackConfigureDescription({
  267. linkConfig:
  268. 'https://docs.sentry.io/platforms/javascript/guides/nextjs/user-feedback/configuration/',
  269. linkButton:
  270. 'https://docs.sentry.io/platforms/javascript/guides/nextjs/user-feedback/configuration/#bring-your-own-button',
  271. }),
  272. configurations: [
  273. {
  274. code: [
  275. {
  276. label: 'sentry.client.config.js',
  277. value: 'javascript',
  278. language: 'javascript',
  279. code: getFeedbackSDKSetupSnippet({
  280. importStatement: `import * as Sentry from "@sentry/nextjs";`,
  281. dsn: params.dsn.public,
  282. feedbackOptions: params.feedbackOptions,
  283. }),
  284. },
  285. ],
  286. },
  287. ],
  288. additionalInfo: (
  289. <AdditionalInfoWrapper>
  290. <div>
  291. {tct(
  292. 'Note: The User Feedback integration only needs to be added to your [code:sentry.client.config.js] file. Adding it to any server-side configuration files (like [code:instrumentation.ts]) will break your build because the Replay integration depends on Browser APIs.',
  293. {
  294. code: <code />,
  295. }
  296. )}
  297. </div>
  298. <div>
  299. {crashReportCallout({
  300. link: 'https://docs.sentry.io/platforms/javascript/guides/nextjs/user-feedback/#crash-report-modal',
  301. })}
  302. </div>
  303. </AdditionalInfoWrapper>
  304. ),
  305. },
  306. ],
  307. verify: () => [],
  308. nextSteps: () => [],
  309. };
  310. const crashReportOnboarding: OnboardingConfig = {
  311. introduction: () => getCrashReportModalIntroduction(),
  312. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  313. configure: () => [
  314. {
  315. type: StepType.CONFIGURE,
  316. description: getCrashReportModalConfigDescription({
  317. link: 'https://docs.sentry.io/platforms/javascript/guides/nextjs/user-feedback/configuration/#crash-report-modal',
  318. }),
  319. additionalInfo: widgetCallout({
  320. link: 'https://docs.sentry.io/platforms/javascript/guides/nextjs/user-feedback/#user-feedback-widget',
  321. }),
  322. },
  323. ],
  324. verify: () => [],
  325. nextSteps: () => [],
  326. };
  327. const performanceOnboarding: OnboardingConfig = {
  328. introduction: () =>
  329. t(
  330. "Adding Performance to your React project is simple. Make sure you've got these basics down."
  331. ),
  332. install: params => [
  333. {
  334. type: StepType.INSTALL,
  335. description: t('Install the Next.js SDK using our installation wizard:'),
  336. configurations: [
  337. {
  338. language: 'bash',
  339. code: getInstallSnippet(params),
  340. },
  341. ],
  342. },
  343. ],
  344. configure: params => [
  345. {
  346. type: StepType.CONFIGURE,
  347. description: tct(
  348. 'To configure, set [code:tracesSampleRate] in your config files, [code:sentry.server.config.js], [code:sentry.client.config.js], and [code:sentry.edge.config.js]:',
  349. {code: <code />}
  350. ),
  351. configurations: [
  352. {
  353. language: 'javascript',
  354. code: `
  355. import * as Sentry from "@sentry/nextjs";
  356. Sentry.init({
  357. dsn: "${params.dsn.public}",
  358. // Set tracesSampleRate to 1.0 to capture 100%
  359. // of transactions for performance monitoring.
  360. // We recommend adjusting this value in production
  361. tracesSampleRate: 1.0,
  362. });
  363. `,
  364. additionalInfo: tct(
  365. '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 [linkSampleTransactions:sample transactions].',
  366. {
  367. code: <code />,
  368. linkTracingOptions: (
  369. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#tracing-options" />
  370. ),
  371. linkTracesSampler: (
  372. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/sampling/" />
  373. ),
  374. linkSampleTransactions: (
  375. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/sampling/" />
  376. ),
  377. }
  378. ),
  379. },
  380. ],
  381. },
  382. ],
  383. verify: () => [
  384. {
  385. type: StepType.VERIFY,
  386. description: tct(
  387. 'Verify that performance monitoring is working correctly with our [link:automatic instrumentation] by simply using your NextJS application.',
  388. {
  389. link: (
  390. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/tracing/instrumentation/automatic-instrumentation/" />
  391. ),
  392. }
  393. ),
  394. additionalInfo: tct(
  395. 'You have the option to manually construct a transaction using [link:custom instrumentation].',
  396. {
  397. link: (
  398. <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/tracing/instrumentation/custom-instrumentation/" />
  399. ),
  400. }
  401. ),
  402. },
  403. ],
  404. nextSteps: () => [],
  405. };
  406. const docs: Docs = {
  407. onboarding,
  408. feedbackOnboardingNpm: feedbackOnboarding,
  409. replayOnboarding,
  410. customMetricsOnboarding: getJSMetricsOnboarding({
  411. getInstallConfig: getManualInstallConfig,
  412. }),
  413. performanceOnboarding,
  414. crashReportOnboarding,
  415. featureFlagOnboarding: featureFlagOnboarding,
  416. };
  417. export default docs;
  418. const DSNText = styled('div')`
  419. margin-bottom: ${space(0.5)};
  420. `;
  421. const AdditionalInfoWrapper = styled('div')`
  422. display: flex;
  423. flex-direction: column;
  424. gap: ${space(2)};
  425. `;
  426. const Divider = styled('hr')`
  427. height: 1px;
  428. width: 100%;
  429. background: ${p => p.theme.border};
  430. border: none;
  431. margin-top: ${space(1)};
  432. margin-bottom: ${space(2)};
  433. `;