nextjs.tsx 13 KB

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