angular.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. import {Fragment} from 'react';
  2. import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/crashReportCallout';
  3. import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
  4. import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
  5. import {
  6. type Configuration,
  7. StepType,
  8. } 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 {getJSMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
  24. import {
  25. getProfilingDocumentHeaderConfigurationStep,
  26. MaybeBrowserProfilingBetaWarning,
  27. } from 'sentry/components/onboarding/gettingStartedDoc/utils/profilingOnboarding';
  28. import {
  29. getReplayConfigOptions,
  30. getReplayConfigureDescription,
  31. getReplayVerifyStep,
  32. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  33. import {t, tct} from 'sentry/locale';
  34. export enum AngularConfigType {
  35. APP = 'standalone',
  36. MODULE = 'module',
  37. }
  38. const platformOptions = {
  39. configType: {
  40. label: t('Config Type'),
  41. defaultValue: AngularConfigType.APP,
  42. items: [
  43. {
  44. label: 'App Config',
  45. value: AngularConfigType.APP,
  46. },
  47. {
  48. label: 'NGModule Config',
  49. value: AngularConfigType.MODULE,
  50. },
  51. ],
  52. },
  53. } satisfies BasePlatformOptions;
  54. type PlatformOptions = typeof platformOptions;
  55. type Params = DocsParams<PlatformOptions>;
  56. function isModuleConfig(params: Params) {
  57. return params.platformOptions.configType === AngularConfigType.MODULE;
  58. }
  59. function getSdkSetupSnippet(params: Params) {
  60. const imports = isModuleConfig(params)
  61. ? `
  62. import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
  63. import * as Sentry from "@sentry/angular";
  64. import { AppModule } from "./app/app.module";`
  65. : `
  66. import { bootstrapApplication } from '@angular/platform-browser';
  67. import * as Sentry from "@sentry/angular";
  68. import { appConfig } from './app/app.config';
  69. import { AppComponent } from './app/app.component';
  70. `;
  71. const appInit = isModuleConfig(params)
  72. ? `
  73. platformBrowserDynamic()
  74. .bootstrapModule(AppModule)
  75. .catch((err) => console.error(err));`
  76. : `
  77. bootstrapApplication(appConfig, AppComponent)
  78. .catch((err) => console.error(err));`;
  79. return `${imports.trim()}
  80. Sentry.init({
  81. dsn: "${params.dsn.public}",
  82. integrations: [${
  83. params.isPerformanceSelected
  84. ? `
  85. Sentry.browserTracingIntegration(),`
  86. : ''
  87. }${
  88. params.isProfilingSelected
  89. ? `
  90. Sentry.browserProfilingIntegration(),`
  91. : ''
  92. }${
  93. params.isFeedbackSelected
  94. ? `
  95. Sentry.feedbackIntegration({
  96. // Additional SDK configuration goes in here, for example:
  97. colorScheme: "system",
  98. ${getFeedbackConfigOptions(params.feedbackOptions)}}),`
  99. : ''
  100. }${
  101. params.isReplaySelected
  102. ? `
  103. Sentry.replayIntegration(${getReplayConfigOptions(params.replayOptions)}),`
  104. : ''
  105. }
  106. ],${
  107. params.isPerformanceSelected
  108. ? `
  109. // Tracing
  110. tracesSampleRate: 1.0, // Capture 100% of the transactions
  111. // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
  112. tracePropagationTargets: ["localhost", /^https:\\/\\/yourserver\\.io\\/api/],`
  113. : ''
  114. }${
  115. params.isReplaySelected
  116. ? `
  117. // Session Replay
  118. 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.
  119. replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.`
  120. : ''
  121. }${
  122. params.isProfilingSelected
  123. ? `
  124. // Set profilesSampleRate to 1.0 to profile every transaction.
  125. // Since profilesSampleRate is relative to tracesSampleRate,
  126. // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  127. // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  128. // results in 25% of transactions being profiled (0.5*0.5=0.25)
  129. profilesSampleRate: 1.0,`
  130. : ''
  131. }
  132. });
  133. ${appInit.trim()}`;
  134. }
  135. const getConfigureAppModuleSnippet = () => `
  136. import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
  137. import { Router } from "@angular/router";
  138. import * as Sentry from "@sentry/angular";
  139. @NgModule({
  140. // ...
  141. providers: [
  142. {
  143. provide: ErrorHandler,
  144. useValue: Sentry.createErrorHandler({
  145. showDialog: true,
  146. }),
  147. }, {
  148. provide: Sentry.TraceService,
  149. deps: [Router],
  150. },
  151. {
  152. provide: APP_INITIALIZER,
  153. useFactory: () => () => {},
  154. deps: [Sentry.TraceService],
  155. multi: true,
  156. },
  157. ],
  158. })
  159. export class AppModule {}
  160. `;
  161. const getConfigureAppConfigSnippet = () => `
  162. import { APP_INITIALIZER, ApplicationConfig, ErrorHandler } from '@angular/core';
  163. import { Router } from '@angular/router';
  164. import * as Sentry from "@sentry/angular";
  165. export const appConfig: ApplicationConfig = {
  166. providers: [
  167. // ...
  168. {
  169. provide: ErrorHandler,
  170. useValue: Sentry.createErrorHandler(),
  171. },
  172. {
  173. provide: Sentry.TraceService,
  174. deps: [Router],
  175. },
  176. {
  177. provide: APP_INITIALIZER,
  178. useFactory: () => () => {},
  179. deps: [Sentry.TraceService],
  180. multi: true,
  181. },
  182. ]
  183. };
  184. `;
  185. const getVerifySnippetTemplate = () => `
  186. <button (click)="throwTestError()">Test Sentry Error</button>
  187. `;
  188. const getVerifySnippetComponent = () => `
  189. public throwTestError(): void {
  190. throw new Error("Sentry Test Error");
  191. }`;
  192. function getVerifyConfiguration(): Configuration {
  193. return {
  194. description: t(
  195. 'To verify that everything is working as expected, you can trigger a test error in your app. As an example we will add a button that throws an error when being clicked to your main app component.'
  196. ),
  197. configurations: [
  198. {
  199. description: tct(
  200. 'First add the button element to your [code:app.component.html]:',
  201. {code: <code />}
  202. ),
  203. code: [
  204. {
  205. label: 'HTML',
  206. value: 'html',
  207. language: 'html',
  208. filename: 'app.component.html',
  209. code: getVerifySnippetTemplate(),
  210. },
  211. ],
  212. },
  213. {
  214. description: tct('Then, in your [code:app.component.ts] add the event handler:', {
  215. code: <code />,
  216. }),
  217. code: [
  218. {
  219. label: 'TypeScript',
  220. value: 'typescript',
  221. language: 'typescript',
  222. filename: 'app.component.ts',
  223. code: getVerifySnippetComponent(),
  224. },
  225. ],
  226. },
  227. ],
  228. };
  229. }
  230. const getInstallConfig = () => [
  231. {
  232. language: 'bash',
  233. code: [
  234. {
  235. label: 'npm',
  236. value: 'npm',
  237. language: 'bash',
  238. code: `npm install --save @sentry/angular`,
  239. },
  240. {
  241. label: 'yarn',
  242. value: 'yarn',
  243. language: 'bash',
  244. code: `yarn add @sentry/angular`,
  245. },
  246. {
  247. label: 'pnpm',
  248. value: 'pnpm',
  249. language: 'bash',
  250. code: `pnpm install @sentry/angular`,
  251. },
  252. ],
  253. },
  254. ];
  255. const onboarding: OnboardingConfig<PlatformOptions> = {
  256. introduction: params => (
  257. <Fragment>
  258. <MaybeBrowserProfilingBetaWarning {...params} />
  259. <p>
  260. {tct(
  261. 'In this quick guide you’ll use [strong:npm], [strong:yarn] or [strong:pnpm] to set up:',
  262. {
  263. strong: <strong />,
  264. }
  265. )}
  266. </p>
  267. </Fragment>
  268. ),
  269. install: () => [
  270. {
  271. type: StepType.INSTALL,
  272. description: tct(
  273. 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn] or [code:pnpm]:',
  274. {code: <code />}
  275. ),
  276. configurations: getInstallConfig(),
  277. },
  278. ],
  279. configure: (params: Params) => [
  280. {
  281. type: StepType.CONFIGURE,
  282. configurations: [
  283. {
  284. description: tct(
  285. `Initialize the Sentry Angular SDK in your [code:main.ts] file as early as possible, before initializing Angular:`,
  286. {
  287. code: <code />,
  288. }
  289. ),
  290. language: 'javascript',
  291. code: getSdkSetupSnippet(params),
  292. },
  293. {
  294. description: isModuleConfig(params)
  295. ? tct(
  296. "Register the Sentry Angular SDK's ErrorHandler and Tracing providers in your [code:app.module.ts] file:",
  297. {code: <code />}
  298. )
  299. : tct(
  300. "Register the Sentry Angular SDK's ErrorHandler and Tracing providers in your [code:app.config.ts] file:",
  301. {code: <code />}
  302. ),
  303. language: 'javascript',
  304. code: isModuleConfig(params)
  305. ? getConfigureAppModuleSnippet()
  306. : getConfigureAppConfigSnippet(),
  307. },
  308. ...(params.isProfilingSelected
  309. ? [getProfilingDocumentHeaderConfigurationStep()]
  310. : []),
  311. ],
  312. },
  313. getUploadSourceMapsStep({
  314. guideLink: 'https://docs.sentry.io/platforms/javascript/guides/angular/sourcemaps/',
  315. ...params,
  316. }),
  317. ],
  318. verify: () => [
  319. {
  320. type: StepType.VERIFY,
  321. configurations: [
  322. getVerifyConfiguration(),
  323. {
  324. description: t(
  325. "After clicking the button, you should see the error on Sentry's Issues page."
  326. ),
  327. },
  328. ],
  329. },
  330. ],
  331. nextSteps: () => [
  332. {
  333. id: 'angular-features',
  334. name: t('Angular Features'),
  335. description: t(
  336. 'Learn about our first class integration with the Angular framework.'
  337. ),
  338. link: 'https://docs.sentry.io/platforms/javascript/guides/angular/features/',
  339. },
  340. ],
  341. };
  342. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  343. install: () => [
  344. {
  345. type: StepType.INSTALL,
  346. description: tct(
  347. 'In order to use Session Replay, you will need version 7.27.0 of [code:@sentry/angular] at minimum. You do not need to install any additional packages.',
  348. {
  349. code: <code />,
  350. }
  351. ),
  352. configurations: getInstallConfig(),
  353. },
  354. ],
  355. configure: (params: Params) => [
  356. {
  357. type: StepType.CONFIGURE,
  358. description: getReplayConfigureDescription({
  359. link: 'https://docs.sentry.io/platforms/javascript/guides/angular/session-replay/',
  360. }),
  361. configurations: [
  362. {
  363. code: [
  364. {
  365. label: 'JavaScript',
  366. value: 'javascript',
  367. language: 'javascript',
  368. code: getSdkSetupSnippet(params),
  369. },
  370. ],
  371. },
  372. ],
  373. additionalInfo: <TracePropagationMessage />,
  374. },
  375. ],
  376. verify: getReplayVerifyStep(),
  377. nextSteps: () => [],
  378. };
  379. const feedbackOnboarding: OnboardingConfig<PlatformOptions> = {
  380. install: () => [
  381. {
  382. type: StepType.INSTALL,
  383. description: tct(
  384. 'For the User Feedback integration to work, you must have the Sentry browser SDK package, or an equivalent framework SDK (e.g. [code:@sentry/angular]) installed, minimum version 7.85.0.',
  385. {
  386. code: <code />,
  387. }
  388. ),
  389. configurations: getInstallConfig(),
  390. },
  391. ],
  392. configure: (params: Params) => [
  393. {
  394. type: StepType.CONFIGURE,
  395. description: getFeedbackConfigureDescription({
  396. linkConfig:
  397. 'https://docs.sentry.io/platforms/javascript/guides/angular/user-feedback/configuration/',
  398. linkButton:
  399. 'https://docs.sentry.io/platforms/javascript/guides/angular/user-feedback/configuration/#bring-your-own-button',
  400. }),
  401. configurations: [
  402. {
  403. code: [
  404. {
  405. label: 'JavaScript',
  406. value: 'javascript',
  407. language: 'javascript',
  408. code: getSdkSetupSnippet(params),
  409. },
  410. ],
  411. },
  412. ],
  413. additionalInfo: crashReportCallout({
  414. link: 'https://docs.sentry.io/platforms/javascript/guides/angular/user-feedback/#crash-report-modal',
  415. }),
  416. },
  417. ],
  418. verify: () => [],
  419. nextSteps: () => [],
  420. };
  421. const crashReportOnboarding: OnboardingConfig<PlatformOptions> = {
  422. introduction: () => getCrashReportModalIntroduction(),
  423. install: (params: Params) => getCrashReportJavaScriptInstallStep(params),
  424. configure: () => [
  425. {
  426. type: StepType.CONFIGURE,
  427. description: getCrashReportModalConfigDescription({
  428. link: 'https://docs.sentry.io/platforms/javascript/guides/angular/user-feedback/configuration/#crash-report-modal',
  429. }),
  430. additionalInfo: widgetCallout({
  431. link: 'https://docs.sentry.io/platforms/javascript/guides/angular/user-feedback/#user-feedback-widget',
  432. }),
  433. },
  434. ],
  435. verify: () => [],
  436. nextSteps: () => [],
  437. };
  438. const profilingOnboarding: OnboardingConfig<PlatformOptions> = {
  439. ...onboarding,
  440. introduction: params => <MaybeBrowserProfilingBetaWarning {...params} />,
  441. };
  442. const docs: Docs<PlatformOptions> = {
  443. onboarding,
  444. feedbackOnboardingNpm: feedbackOnboarding,
  445. replayOnboarding,
  446. customMetricsOnboarding: getJSMetricsOnboarding({getInstallConfig}),
  447. crashReportOnboarding,
  448. platformOptions,
  449. profilingOnboarding,
  450. };
  451. export default docs;