@sentry/wizard 3.25.2 → 3.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/lib/Steps/OpenSentry.js +1 -1
- package/dist/lib/Steps/OpenSentry.js.map +1 -1
- package/dist/package.json +2 -1
- package/dist/src/nextjs/nextjs-wizard.d.ts +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +194 -99
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +7 -3
- package/dist/src/nextjs/templates.js +27 -14
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/run.js +1 -1
- package/dist/src/run.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/telemetry.js +10 -3
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +4 -1
- package/dist/src/utils/clack-utils.js +81 -11
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +5 -2
- package/dist/src/utils/package-manager.js +44 -56
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/src/utils/types.d.ts +6 -0
- package/dist/src/utils/types.js.map +1 -1
- package/dist/src/utils/url.js +7 -2
- package/dist/src/utils/url.js.map +1 -1
- package/dist/test/nextjs/templates.test.js +79 -1
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/dist/test/sourcemaps/tools/sentry-cli.test.js +2 -1
- package/dist/test/sourcemaps/tools/sentry-cli.test.js.map +1 -1
- package/lib/Steps/OpenSentry.ts +1 -1
- package/package.json +2 -1
- package/src/nextjs/nextjs-wizard.ts +209 -101
- package/src/nextjs/templates.ts +54 -26
- package/src/run.ts +1 -1
- package/src/sourcemaps/sourcemaps-wizard.ts +1 -1
- package/src/telemetry.ts +7 -1
- package/src/utils/clack-utils.ts +77 -7
- package/src/utils/package-manager.ts +43 -13
- package/src/utils/types.ts +7 -0
- package/src/utils/url.ts +6 -2
- package/test/nextjs/templates.test.ts +296 -2
- package/test/sourcemaps/tools/sentry-cli.test.ts +2 -1
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
confirmContinueIfNoOrDirtyGitRepo,
|
|
18
18
|
createNewConfigFile,
|
|
19
19
|
ensurePackageIsInstalled,
|
|
20
|
+
featureSelectionPrompt,
|
|
20
21
|
getOrAskForProjectData,
|
|
21
22
|
getPackageDotJson,
|
|
22
23
|
installPackage,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
printWelcome,
|
|
25
26
|
showCopyPasteInstructions,
|
|
26
27
|
} from '../utils/clack-utils';
|
|
27
|
-
import { SentryProjectData, WizardOptions } from '../utils/types';
|
|
28
|
+
import type { SentryProjectData, WizardOptions } from '../utils/types';
|
|
28
29
|
import {
|
|
29
30
|
getFullUnderscoreErrorCopyPasteSnippet,
|
|
30
31
|
getGlobalErrorCopyPasteSnippet,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
getSentryConfigContents,
|
|
37
38
|
getSentryDefaultGlobalErrorPage,
|
|
38
39
|
getSentryDefaultUnderscoreErrorPage,
|
|
39
|
-
|
|
40
|
+
getSentryExamplePagesDirApiRoute,
|
|
40
41
|
getSentryExampleAppDirApiRoute,
|
|
41
42
|
getSentryExamplePageContents,
|
|
42
43
|
getSimpleUnderscoreErrorCopyPasteSnippet,
|
|
@@ -93,9 +94,12 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
93
94
|
|
|
94
95
|
await traceStep('configure-sdk', async () => {
|
|
95
96
|
const tunnelRoute = await askShouldSetTunnelRoute();
|
|
97
|
+
const reactComponentAnnotation =
|
|
98
|
+
await askShouldEnableReactComponentAnnotation();
|
|
96
99
|
|
|
97
100
|
await createOrMergeNextJsFiles(selectedProject, selfHosted, sentryUrl, {
|
|
98
101
|
tunnelRoute,
|
|
102
|
+
reactComponentAnnotation,
|
|
99
103
|
});
|
|
100
104
|
});
|
|
101
105
|
|
|
@@ -321,6 +325,7 @@ ${chalk.dim(
|
|
|
321
325
|
|
|
322
326
|
type SDKConfigOptions = {
|
|
323
327
|
tunnelRoute: boolean;
|
|
328
|
+
reactComponentAnnotation: boolean;
|
|
324
329
|
};
|
|
325
330
|
|
|
326
331
|
async function createOrMergeNextJsFiles(
|
|
@@ -329,6 +334,23 @@ async function createOrMergeNextJsFiles(
|
|
|
329
334
|
sentryUrl: string,
|
|
330
335
|
sdkConfigOptions: SDKConfigOptions,
|
|
331
336
|
) {
|
|
337
|
+
const selectedFeatures = await featureSelectionPrompt([
|
|
338
|
+
{
|
|
339
|
+
id: 'performance',
|
|
340
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
341
|
+
'Tracing',
|
|
342
|
+
)} to track the performance of your application?`,
|
|
343
|
+
enabledHint: 'recommended',
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: 'replay',
|
|
347
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
348
|
+
'Sentry Session Replay',
|
|
349
|
+
)} to get reproduction of frontend errors via user sessions?`,
|
|
350
|
+
enabledHint: 'recommended, but increases bundle size',
|
|
351
|
+
},
|
|
352
|
+
] as const);
|
|
353
|
+
|
|
332
354
|
const typeScriptDetected = isUsingTypeScript();
|
|
333
355
|
|
|
334
356
|
const configVariants = ['server', 'client', 'edge'] as const;
|
|
@@ -386,6 +408,7 @@ async function createOrMergeNextJsFiles(
|
|
|
386
408
|
getSentryConfigContents(
|
|
387
409
|
selectedProject.keys[0].dsn.public,
|
|
388
410
|
configVariant,
|
|
411
|
+
selectedFeatures,
|
|
389
412
|
),
|
|
390
413
|
{ encoding: 'utf8', flag: 'w' },
|
|
391
414
|
);
|
|
@@ -400,60 +423,85 @@ async function createOrMergeNextJsFiles(
|
|
|
400
423
|
}
|
|
401
424
|
|
|
402
425
|
await traceStep('setup-instrumentation-hook', async () => {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
426
|
+
const hasRootAppDirectory = hasDirectoryPathFromRoot('app');
|
|
427
|
+
const hasRootPagesDirectory = hasDirectoryPathFromRoot('pages');
|
|
428
|
+
const hasSrcDirectory = hasDirectoryPathFromRoot('src');
|
|
429
|
+
|
|
430
|
+
let instrumentationHookLocation: 'src' | 'root' | 'does-not-exist';
|
|
431
|
+
|
|
409
432
|
const instrumentationTsExists = fs.existsSync(
|
|
410
433
|
path.join(process.cwd(), 'instrumentation.ts'),
|
|
411
434
|
);
|
|
412
435
|
const instrumentationJsExists = fs.existsSync(
|
|
413
436
|
path.join(process.cwd(), 'instrumentation.js'),
|
|
414
437
|
);
|
|
438
|
+
const srcInstrumentationTsExists = fs.existsSync(
|
|
439
|
+
path.join(process.cwd(), 'src', 'instrumentation.ts'),
|
|
440
|
+
);
|
|
441
|
+
const srcInstrumentationJsExists = fs.existsSync(
|
|
442
|
+
path.join(process.cwd(), 'src', 'instrumentation.js'),
|
|
443
|
+
);
|
|
415
444
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
445
|
+
// https://nextjs.org/docs/app/building-your-application/configuring/src-directory
|
|
446
|
+
// https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation
|
|
447
|
+
// The logic for where Next.js picks up the instrumentation file is as follows:
|
|
448
|
+
// - If there is either an `app` folder or a `pages` folder in the root directory of your Next.js app, Next.js looks
|
|
449
|
+
// for an `instrumentation.ts` file in the root of the Next.js app.
|
|
450
|
+
// - Otherwise, if there is neither an `app` folder or a `pages` folder in the rood directory of your Next.js app,
|
|
451
|
+
// AND if there is an `src` folder, Next.js will look for the `instrumentation.ts` file in the `src` folder.
|
|
452
|
+
if (hasRootPagesDirectory || hasRootAppDirectory) {
|
|
453
|
+
if (instrumentationJsExists || instrumentationTsExists) {
|
|
454
|
+
instrumentationHookLocation = 'root';
|
|
455
|
+
} else {
|
|
456
|
+
instrumentationHookLocation = 'does-not-exist';
|
|
457
|
+
}
|
|
421
458
|
} else {
|
|
422
|
-
|
|
459
|
+
if (srcInstrumentationTsExists || srcInstrumentationJsExists) {
|
|
460
|
+
instrumentationHookLocation = 'src';
|
|
461
|
+
} else {
|
|
462
|
+
instrumentationHookLocation = 'does-not-exist';
|
|
463
|
+
}
|
|
423
464
|
}
|
|
424
465
|
|
|
466
|
+
const newInstrumentationFileName = `instrumentation.${
|
|
467
|
+
typeScriptDetected ? 'ts' : 'js'
|
|
468
|
+
}`;
|
|
469
|
+
|
|
425
470
|
if (instrumentationHookLocation === 'does-not-exist') {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
471
|
+
let newInstrumentationHookLocation: 'root' | 'src';
|
|
472
|
+
if (hasRootPagesDirectory || hasRootAppDirectory) {
|
|
473
|
+
newInstrumentationHookLocation = 'root';
|
|
474
|
+
} else if (hasSrcDirectory) {
|
|
475
|
+
newInstrumentationHookLocation = 'src';
|
|
476
|
+
} else {
|
|
477
|
+
newInstrumentationHookLocation = 'root';
|
|
478
|
+
}
|
|
430
479
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
480
|
+
const newInstrumentationHookPath =
|
|
481
|
+
newInstrumentationHookLocation === 'root'
|
|
482
|
+
? path.join(process.cwd(), newInstrumentationFileName)
|
|
483
|
+
: path.join(process.cwd(), 'src', newInstrumentationFileName);
|
|
434
484
|
|
|
435
485
|
const successfullyCreated = await createNewConfigFile(
|
|
436
|
-
|
|
437
|
-
getInstrumentationHookContent(
|
|
486
|
+
newInstrumentationHookPath,
|
|
487
|
+
getInstrumentationHookContent(newInstrumentationHookLocation),
|
|
438
488
|
);
|
|
439
489
|
|
|
440
490
|
if (!successfullyCreated) {
|
|
441
491
|
await showCopyPasteInstructions(
|
|
442
492
|
newInstrumentationFileName,
|
|
443
493
|
getInstrumentationHookCopyPasteSnippet(
|
|
444
|
-
|
|
494
|
+
newInstrumentationHookLocation,
|
|
445
495
|
),
|
|
446
496
|
);
|
|
447
497
|
}
|
|
448
498
|
} else {
|
|
449
499
|
await showCopyPasteInstructions(
|
|
450
|
-
srcInstrumentationTsExists
|
|
500
|
+
srcInstrumentationTsExists || instrumentationTsExists
|
|
451
501
|
? 'instrumentation.ts'
|
|
452
|
-
: srcInstrumentationJsExists
|
|
502
|
+
: srcInstrumentationJsExists || instrumentationJsExists
|
|
453
503
|
? 'instrumentation.js'
|
|
454
|
-
:
|
|
455
|
-
? 'instrumentation.ts'
|
|
456
|
-
: 'instrumentation.js',
|
|
504
|
+
: newInstrumentationFileName,
|
|
457
505
|
getInstrumentationHookCopyPasteSnippet(instrumentationHookLocation),
|
|
458
506
|
);
|
|
459
507
|
}
|
|
@@ -466,23 +514,28 @@ async function createOrMergeNextJsFiles(
|
|
|
466
514
|
selfHosted,
|
|
467
515
|
sentryUrl,
|
|
468
516
|
tunnelRoute: sdkConfigOptions.tunnelRoute,
|
|
517
|
+
reactComponentAnnotation: sdkConfigOptions.reactComponentAnnotation,
|
|
469
518
|
});
|
|
470
519
|
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
520
|
+
const nextConfigPossibleFilesMap = {
|
|
521
|
+
js: 'next.config.js',
|
|
522
|
+
mjs: 'next.config.mjs',
|
|
523
|
+
cjs: 'next.config.cjs',
|
|
524
|
+
ts: 'next.config.ts',
|
|
525
|
+
mts: 'next.config.mts',
|
|
526
|
+
cts: 'next.config.cts',
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const foundNextConfigFile = Object.entries(nextConfigPossibleFilesMap).find(
|
|
530
|
+
([, fileName]) => fs.existsSync(path.join(process.cwd(), fileName)),
|
|
479
531
|
);
|
|
480
532
|
|
|
481
|
-
if (!
|
|
533
|
+
if (!foundNextConfigFile) {
|
|
482
534
|
Sentry.setTag('next-config-strategy', 'create');
|
|
483
535
|
|
|
484
536
|
await fs.promises.writeFile(
|
|
485
|
-
|
|
537
|
+
// We are creating a `next.config.js` file by default as it is supported by the most Next.js versions
|
|
538
|
+
path.join(process.cwd(), nextConfigPossibleFilesMap.js),
|
|
486
539
|
getNextjsConfigCjsTemplate(withSentryConfigOptionsTemplate),
|
|
487
540
|
{ encoding: 'utf8', flag: 'w' },
|
|
488
541
|
);
|
|
@@ -490,19 +543,24 @@ async function createOrMergeNextJsFiles(
|
|
|
490
543
|
clack.log.success(
|
|
491
544
|
`Created ${chalk.cyan('next.config.js')} with Sentry configuration.`,
|
|
492
545
|
);
|
|
546
|
+
|
|
547
|
+
return;
|
|
493
548
|
}
|
|
494
549
|
|
|
495
|
-
|
|
550
|
+
const [foundNextConfigFileType, foundNextConfigFileFilename] =
|
|
551
|
+
foundNextConfigFile;
|
|
552
|
+
|
|
553
|
+
if (foundNextConfigFileType === 'js' || foundNextConfigFileType === 'cjs') {
|
|
496
554
|
Sentry.setTag('next-config-strategy', 'modify');
|
|
497
555
|
|
|
498
|
-
const
|
|
499
|
-
path.join(process.cwd(),
|
|
556
|
+
const nextConfigCjsContent = fs.readFileSync(
|
|
557
|
+
path.join(process.cwd(), foundNextConfigFileFilename),
|
|
500
558
|
'utf8',
|
|
501
559
|
);
|
|
502
560
|
|
|
503
561
|
const probablyIncludesSdk =
|
|
504
|
-
|
|
505
|
-
|
|
562
|
+
nextConfigCjsContent.includes('@sentry/nextjs') &&
|
|
563
|
+
nextConfigCjsContent.includes('withSentryConfig');
|
|
506
564
|
|
|
507
565
|
let shouldInject = true;
|
|
508
566
|
|
|
@@ -510,7 +568,7 @@ async function createOrMergeNextJsFiles(
|
|
|
510
568
|
const injectAnyhow = await abortIfCancelled(
|
|
511
569
|
clack.confirm({
|
|
512
570
|
message: `${chalk.cyan(
|
|
513
|
-
|
|
571
|
+
foundNextConfigFileFilename,
|
|
514
572
|
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
515
573
|
}),
|
|
516
574
|
);
|
|
@@ -520,14 +578,14 @@ async function createOrMergeNextJsFiles(
|
|
|
520
578
|
|
|
521
579
|
if (shouldInject) {
|
|
522
580
|
await fs.promises.appendFile(
|
|
523
|
-
path.join(process.cwd(),
|
|
581
|
+
path.join(process.cwd(), foundNextConfigFileFilename),
|
|
524
582
|
getNextjsConfigCjsAppendix(withSentryConfigOptionsTemplate),
|
|
525
583
|
'utf8',
|
|
526
584
|
);
|
|
527
585
|
|
|
528
586
|
clack.log.success(
|
|
529
587
|
`Added Sentry configuration to ${chalk.cyan(
|
|
530
|
-
|
|
588
|
+
foundNextConfigFileFilename,
|
|
531
589
|
)}. ${chalk.dim('(you probably want to clean this up a bit!)')}`,
|
|
532
590
|
);
|
|
533
591
|
}
|
|
@@ -535,9 +593,14 @@ async function createOrMergeNextJsFiles(
|
|
|
535
593
|
Sentry.setTag('next-config-mod-result', 'success');
|
|
536
594
|
}
|
|
537
595
|
|
|
538
|
-
if (
|
|
596
|
+
if (
|
|
597
|
+
foundNextConfigFileType === 'mjs' ||
|
|
598
|
+
foundNextConfigFileType === 'mts' ||
|
|
599
|
+
foundNextConfigFileType === 'cts' ||
|
|
600
|
+
foundNextConfigFileType === 'ts'
|
|
601
|
+
) {
|
|
539
602
|
const nextConfigMjsContent = fs.readFileSync(
|
|
540
|
-
path.join(process.cwd(),
|
|
603
|
+
path.join(process.cwd(), foundNextConfigFileFilename),
|
|
541
604
|
'utf8',
|
|
542
605
|
);
|
|
543
606
|
|
|
@@ -551,7 +614,7 @@ async function createOrMergeNextJsFiles(
|
|
|
551
614
|
const injectAnyhow = await abortIfCancelled(
|
|
552
615
|
clack.confirm({
|
|
553
616
|
message: `${chalk.cyan(
|
|
554
|
-
|
|
617
|
+
foundNextConfigFileFilename,
|
|
555
618
|
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
556
619
|
}),
|
|
557
620
|
);
|
|
@@ -577,7 +640,7 @@ async function createOrMergeNextJsFiles(
|
|
|
577
640
|
const newCode = mod.generate().code;
|
|
578
641
|
|
|
579
642
|
await fs.promises.writeFile(
|
|
580
|
-
path.join(process.cwd(),
|
|
643
|
+
path.join(process.cwd(), foundNextConfigFileFilename),
|
|
581
644
|
newCode,
|
|
582
645
|
{
|
|
583
646
|
encoding: 'utf8',
|
|
@@ -586,7 +649,7 @@ async function createOrMergeNextJsFiles(
|
|
|
586
649
|
);
|
|
587
650
|
clack.log.success(
|
|
588
651
|
`Added Sentry configuration to ${chalk.cyan(
|
|
589
|
-
|
|
652
|
+
foundNextConfigFileFilename,
|
|
590
653
|
)}. ${chalk.dim('(you probably want to clean this up a bit!)')}`,
|
|
591
654
|
);
|
|
592
655
|
|
|
@@ -596,12 +659,14 @@ async function createOrMergeNextJsFiles(
|
|
|
596
659
|
Sentry.setTag('next-config-mod-result', 'fail');
|
|
597
660
|
clack.log.warn(
|
|
598
661
|
chalk.yellow(
|
|
599
|
-
`Something went wrong writing to ${chalk.cyan(
|
|
662
|
+
`Something went wrong writing to ${chalk.cyan(
|
|
663
|
+
foundNextConfigFileFilename,
|
|
664
|
+
)}.`,
|
|
600
665
|
),
|
|
601
666
|
);
|
|
602
667
|
clack.log.info(
|
|
603
668
|
`Please put the following code snippet into ${chalk.cyan(
|
|
604
|
-
|
|
669
|
+
foundNextConfigFileFilename,
|
|
605
670
|
)}: ${chalk.dim('You probably have to clean it up a bit.')}\n`,
|
|
606
671
|
);
|
|
607
672
|
|
|
@@ -613,7 +678,7 @@ async function createOrMergeNextJsFiles(
|
|
|
613
678
|
const shouldContinue = await abortIfCancelled(
|
|
614
679
|
clack.confirm({
|
|
615
680
|
message: `Are you done putting the snippet above into ${chalk.cyan(
|
|
616
|
-
|
|
681
|
+
foundNextConfigFileFilename,
|
|
617
682
|
)}?`,
|
|
618
683
|
active: 'Yes',
|
|
619
684
|
inactive: 'No, get me out of here',
|
|
@@ -628,50 +693,58 @@ async function createOrMergeNextJsFiles(
|
|
|
628
693
|
});
|
|
629
694
|
}
|
|
630
695
|
|
|
696
|
+
function hasDirectoryPathFromRoot(dirnameOrDirs: string | string[]): boolean {
|
|
697
|
+
const dirPath = Array.isArray(dirnameOrDirs)
|
|
698
|
+
? path.join(process.cwd(), ...dirnameOrDirs)
|
|
699
|
+
: path.join(process.cwd(), dirnameOrDirs);
|
|
700
|
+
|
|
701
|
+
return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
|
|
702
|
+
}
|
|
703
|
+
|
|
631
704
|
async function createExamplePage(
|
|
632
705
|
selfHosted: boolean,
|
|
633
706
|
selectedProject: SentryProjectData,
|
|
634
707
|
sentryUrl: string,
|
|
635
708
|
): Promise<void> {
|
|
636
|
-
const
|
|
637
|
-
const
|
|
638
|
-
const
|
|
639
|
-
const
|
|
640
|
-
const
|
|
709
|
+
const hasSrcDirectory = hasDirectoryPathFromRoot('src');
|
|
710
|
+
const hasRootAppDirectory = hasDirectoryPathFromRoot('app');
|
|
711
|
+
const hasRootPagesDirectory = hasDirectoryPathFromRoot('pages');
|
|
712
|
+
const hasSrcAppDirectory = hasDirectoryPathFromRoot(['src', 'app']);
|
|
713
|
+
const hasSrcPagesDirectory = hasDirectoryPathFromRoot(['src', 'pages']);
|
|
714
|
+
|
|
715
|
+
Sentry.setTag('nextjs-app-dir', hasRootAppDirectory || hasSrcAppDirectory);
|
|
641
716
|
|
|
642
717
|
const typeScriptDetected = isUsingTypeScript();
|
|
643
718
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
719
|
+
// If `pages` or an `app` directory exists in the root, we'll put the example page there.
|
|
720
|
+
// `app` directory takes priority over `pages` directory when they coexist, so we prioritize that.
|
|
721
|
+
// https://nextjs.org/docs/app/building-your-application/routing#the-app-router
|
|
722
|
+
|
|
723
|
+
const appFolderLocation = hasRootAppDirectory
|
|
724
|
+
? ['app']
|
|
725
|
+
: hasSrcAppDirectory
|
|
726
|
+
? ['src', 'app']
|
|
727
|
+
: undefined;
|
|
728
|
+
|
|
729
|
+
let pagesFolderLocation = hasRootPagesDirectory
|
|
730
|
+
? ['pages']
|
|
731
|
+
: hasSrcPagesDirectory
|
|
732
|
+
? ['src', 'pages']
|
|
733
|
+
: undefined;
|
|
734
|
+
|
|
735
|
+
// If the user has neither pages nor app directory we create a pages folder for them
|
|
736
|
+
if (!appFolderLocation && !pagesFolderLocation) {
|
|
737
|
+
const newPagesFolderLocation = hasSrcDirectory
|
|
650
738
|
? ['src', 'pages']
|
|
651
|
-
:
|
|
652
|
-
|
|
653
|
-
const appLocation =
|
|
654
|
-
fs.existsSync(maybeAppDirPath) &&
|
|
655
|
-
fs.lstatSync(maybeAppDirPath).isDirectory()
|
|
656
|
-
? ['app']
|
|
657
|
-
: fs.existsSync(maybeSrcAppDirPath) &&
|
|
658
|
-
fs.lstatSync(maybeSrcAppDirPath).isDirectory()
|
|
659
|
-
? ['src', 'app']
|
|
660
|
-
: undefined;
|
|
661
|
-
|
|
662
|
-
if (!pagesLocation && !appLocation) {
|
|
663
|
-
pagesLocation =
|
|
664
|
-
fs.existsSync(srcDir) && fs.lstatSync(srcDir).isDirectory()
|
|
665
|
-
? ['src', 'pages']
|
|
666
|
-
: ['pages'];
|
|
667
|
-
fs.mkdirSync(path.join(process.cwd(), ...pagesLocation), {
|
|
739
|
+
: ['pages'];
|
|
740
|
+
fs.mkdirSync(path.join(process.cwd(), ...newPagesFolderLocation), {
|
|
668
741
|
recursive: true,
|
|
669
742
|
});
|
|
670
|
-
}
|
|
671
743
|
|
|
672
|
-
|
|
744
|
+
pagesFolderLocation = newPagesFolderLocation;
|
|
745
|
+
}
|
|
673
746
|
|
|
674
|
-
if (
|
|
747
|
+
if (appFolderLocation) {
|
|
675
748
|
const examplePageContents = getSentryExamplePageContents({
|
|
676
749
|
selfHosted,
|
|
677
750
|
orgSlug: selectedProject.organization.slug,
|
|
@@ -681,7 +754,7 @@ async function createExamplePage(
|
|
|
681
754
|
});
|
|
682
755
|
|
|
683
756
|
fs.mkdirSync(
|
|
684
|
-
path.join(process.cwd(), ...
|
|
757
|
+
path.join(process.cwd(), ...appFolderLocation, 'sentry-example-page'),
|
|
685
758
|
{
|
|
686
759
|
recursive: true,
|
|
687
760
|
},
|
|
@@ -692,7 +765,7 @@ async function createExamplePage(
|
|
|
692
765
|
await fs.promises.writeFile(
|
|
693
766
|
path.join(
|
|
694
767
|
process.cwd(),
|
|
695
|
-
...
|
|
768
|
+
...appFolderLocation,
|
|
696
769
|
'sentry-example-page',
|
|
697
770
|
newPageFileName,
|
|
698
771
|
),
|
|
@@ -702,12 +775,17 @@ async function createExamplePage(
|
|
|
702
775
|
|
|
703
776
|
clack.log.success(
|
|
704
777
|
`Created ${chalk.cyan(
|
|
705
|
-
path.join(...
|
|
778
|
+
path.join(...appFolderLocation, 'sentry-example-page', newPageFileName),
|
|
706
779
|
)}.`,
|
|
707
780
|
);
|
|
708
781
|
|
|
709
782
|
fs.mkdirSync(
|
|
710
|
-
path.join(
|
|
783
|
+
path.join(
|
|
784
|
+
process.cwd(),
|
|
785
|
+
...appFolderLocation,
|
|
786
|
+
'api',
|
|
787
|
+
'sentry-example-api',
|
|
788
|
+
),
|
|
711
789
|
{
|
|
712
790
|
recursive: true,
|
|
713
791
|
},
|
|
@@ -718,7 +796,7 @@ async function createExamplePage(
|
|
|
718
796
|
await fs.promises.writeFile(
|
|
719
797
|
path.join(
|
|
720
798
|
process.cwd(),
|
|
721
|
-
...
|
|
799
|
+
...appFolderLocation,
|
|
722
800
|
'api',
|
|
723
801
|
'sentry-example-api',
|
|
724
802
|
newRouteFileName,
|
|
@@ -730,14 +808,14 @@ async function createExamplePage(
|
|
|
730
808
|
clack.log.success(
|
|
731
809
|
`Created ${chalk.cyan(
|
|
732
810
|
path.join(
|
|
733
|
-
...
|
|
811
|
+
...appFolderLocation,
|
|
734
812
|
'api',
|
|
735
813
|
'sentry-example-api',
|
|
736
814
|
newRouteFileName,
|
|
737
815
|
),
|
|
738
816
|
)}.`,
|
|
739
817
|
);
|
|
740
|
-
} else if (
|
|
818
|
+
} else if (pagesFolderLocation) {
|
|
741
819
|
const examplePageContents = getSentryExamplePageContents({
|
|
742
820
|
selfHosted,
|
|
743
821
|
orgSlug: selectedProject.organization.slug,
|
|
@@ -747,35 +825,39 @@ async function createExamplePage(
|
|
|
747
825
|
});
|
|
748
826
|
|
|
749
827
|
await fs.promises.writeFile(
|
|
750
|
-
path.join(
|
|
828
|
+
path.join(
|
|
829
|
+
process.cwd(),
|
|
830
|
+
...pagesFolderLocation,
|
|
831
|
+
'sentry-example-page.jsx',
|
|
832
|
+
),
|
|
751
833
|
examplePageContents,
|
|
752
834
|
{ encoding: 'utf8', flag: 'w' },
|
|
753
835
|
);
|
|
754
836
|
|
|
755
837
|
clack.log.success(
|
|
756
838
|
`Created ${chalk.cyan(
|
|
757
|
-
path.join(...
|
|
839
|
+
path.join(...pagesFolderLocation, 'sentry-example-page.js'),
|
|
758
840
|
)}.`,
|
|
759
841
|
);
|
|
760
842
|
|
|
761
|
-
fs.mkdirSync(path.join(process.cwd(), ...
|
|
843
|
+
fs.mkdirSync(path.join(process.cwd(), ...pagesFolderLocation, 'api'), {
|
|
762
844
|
recursive: true,
|
|
763
845
|
});
|
|
764
846
|
|
|
765
847
|
await fs.promises.writeFile(
|
|
766
848
|
path.join(
|
|
767
849
|
process.cwd(),
|
|
768
|
-
...
|
|
850
|
+
...pagesFolderLocation,
|
|
769
851
|
'api',
|
|
770
852
|
'sentry-example-api.js',
|
|
771
853
|
),
|
|
772
|
-
|
|
854
|
+
getSentryExamplePagesDirApiRoute(),
|
|
773
855
|
{ encoding: 'utf8', flag: 'w' },
|
|
774
856
|
);
|
|
775
857
|
|
|
776
858
|
clack.log.success(
|
|
777
859
|
`Created ${chalk.cyan(
|
|
778
|
-
path.join(...
|
|
860
|
+
path.join(...pagesFolderLocation, 'api', 'sentry-example-api.js'),
|
|
779
861
|
)}.`,
|
|
780
862
|
);
|
|
781
863
|
}
|
|
@@ -791,7 +873,7 @@ async function askShouldSetTunnelRoute() {
|
|
|
791
873
|
const shouldSetTunnelRoute = await abortIfCancelled(
|
|
792
874
|
clack.select({
|
|
793
875
|
message:
|
|
794
|
-
'Do you want to route Sentry requests in the browser through your
|
|
876
|
+
'Do you want to route Sentry requests in the browser through your Next.js server to avoid ad blockers?',
|
|
795
877
|
options: [
|
|
796
878
|
{
|
|
797
879
|
label: 'Yes',
|
|
@@ -804,7 +886,7 @@ async function askShouldSetTunnelRoute() {
|
|
|
804
886
|
hint: 'Browser errors and events might be blocked by ad blockers before being sent to Sentry',
|
|
805
887
|
},
|
|
806
888
|
],
|
|
807
|
-
initialValue:
|
|
889
|
+
initialValue: true,
|
|
808
890
|
}),
|
|
809
891
|
);
|
|
810
892
|
|
|
@@ -817,3 +899,29 @@ async function askShouldSetTunnelRoute() {
|
|
|
817
899
|
return shouldSetTunnelRoute;
|
|
818
900
|
});
|
|
819
901
|
}
|
|
902
|
+
|
|
903
|
+
async function askShouldEnableReactComponentAnnotation() {
|
|
904
|
+
return await traceStep('ask-react-component-annotation-option', async () => {
|
|
905
|
+
const shouldEnableReactComponentAnnotation = await abortIfCancelled(
|
|
906
|
+
clack.select({
|
|
907
|
+
message:
|
|
908
|
+
'Do you want to enable React component annotations to make breadcrumbs and session replays more readable?',
|
|
909
|
+
options: [
|
|
910
|
+
{
|
|
911
|
+
label: 'Yes',
|
|
912
|
+
value: true,
|
|
913
|
+
hint: 'Annotates React component names - increases bundle size',
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
label: 'No',
|
|
917
|
+
value: false,
|
|
918
|
+
hint: 'Continue without React component annotations',
|
|
919
|
+
},
|
|
920
|
+
],
|
|
921
|
+
initialValue: true,
|
|
922
|
+
}),
|
|
923
|
+
);
|
|
924
|
+
|
|
925
|
+
return shouldEnableReactComponentAnnotation;
|
|
926
|
+
});
|
|
927
|
+
}
|