nextjs.tsx 14 KB

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