@sentry/wizard 3.22.1 → 3.22.3
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 +17 -3
- package/dist/package.json +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +67 -18
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +11 -6
- package/dist/src/nextjs/templates.js +24 -17
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/sourcemaps/tools/nextjs.js +1 -1
- package/dist/src/sourcemaps/tools/nextjs.js.map +1 -1
- package/dist/src/utils/clack-utils.js +2 -2
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/package.json +1 -1
- package/src/nextjs/nextjs-wizard.ts +77 -32
- package/src/nextjs/templates.ts +67 -36
- package/src/sourcemaps/tools/nextjs.ts +5 -2
- package/src/utils/clack-utils.ts +2 -2
|
@@ -12,25 +12,27 @@ import * as Sentry from '@sentry/node';
|
|
|
12
12
|
import {
|
|
13
13
|
abort,
|
|
14
14
|
abortIfCancelled,
|
|
15
|
-
|
|
15
|
+
addDotEnvSentryBuildPluginFile,
|
|
16
16
|
askShouldCreateExamplePage,
|
|
17
17
|
confirmContinueIfNoOrDirtyGitRepo,
|
|
18
|
+
createNewConfigFile,
|
|
18
19
|
ensurePackageIsInstalled,
|
|
19
20
|
getOrAskForProjectData,
|
|
20
21
|
getPackageDotJson,
|
|
21
22
|
installPackage,
|
|
22
23
|
isUsingTypeScript,
|
|
23
24
|
printWelcome,
|
|
25
|
+
showCopyPasteInstructions,
|
|
24
26
|
} from '../utils/clack-utils';
|
|
25
27
|
import { SentryProjectData, WizardOptions } from '../utils/types';
|
|
26
28
|
import {
|
|
27
29
|
getFullUnderscoreErrorCopyPasteSnippet,
|
|
28
30
|
getGlobalErrorCopyPasteSnippet,
|
|
31
|
+
getInstrumentationHookContent,
|
|
32
|
+
getInstrumentationHookCopyPasteSnippet,
|
|
29
33
|
getNextjsConfigCjsAppendix,
|
|
30
34
|
getNextjsConfigCjsTemplate,
|
|
31
35
|
getNextjsConfigEsmCopyPasteSnippet,
|
|
32
|
-
getNextjsSentryBuildOptionsTemplate,
|
|
33
|
-
getNextjsWebpackPluginOptionsTemplate,
|
|
34
36
|
getSentryConfigContents,
|
|
35
37
|
getSentryDefaultGlobalErrorPage,
|
|
36
38
|
getSentryDefaultUnderscoreErrorPage,
|
|
@@ -38,6 +40,7 @@ import {
|
|
|
38
40
|
getSentryExampleAppDirApiRoute,
|
|
39
41
|
getSentryExamplePageContents,
|
|
40
42
|
getSimpleUnderscoreErrorCopyPasteSnippet,
|
|
43
|
+
getWithSentryConfigOptionsTemplate,
|
|
41
44
|
} from './templates';
|
|
42
45
|
import { traceStep, withTelemetry } from '../telemetry';
|
|
43
46
|
import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
|
|
@@ -82,7 +85,7 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
82
85
|
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
83
86
|
|
|
84
87
|
await installPackage({
|
|
85
|
-
packageName: '@sentry/nextjs@^
|
|
88
|
+
packageName: '@sentry/nextjs@^8',
|
|
86
89
|
alreadyInstalled: !!packageJson?.dependencies?.['@sentry/nextjs'],
|
|
87
90
|
});
|
|
88
91
|
|
|
@@ -248,7 +251,7 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
248
251
|
clack.log.info(
|
|
249
252
|
`It seems like you already have a custom error page for your app directory.\n\nPlease add the following code to your custom error page\nat ${chalk.cyan(
|
|
250
253
|
path.join(...appDirLocation, globalErrorPageFile),
|
|
251
|
-
)}
|
|
254
|
+
)}:\n`,
|
|
252
255
|
);
|
|
253
256
|
|
|
254
257
|
// eslint-disable-next-line no-console
|
|
@@ -282,7 +285,7 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
282
285
|
);
|
|
283
286
|
}
|
|
284
287
|
|
|
285
|
-
await
|
|
288
|
+
await addDotEnvSentryBuildPluginFile(authToken);
|
|
286
289
|
|
|
287
290
|
const mightBeUsingVercel = fs.existsSync(
|
|
288
291
|
path.join(process.cwd(), 'vercel.json'),
|
|
@@ -390,23 +393,75 @@ async function createOrMergeNextJsFiles(
|
|
|
390
393
|
});
|
|
391
394
|
}
|
|
392
395
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
396
|
+
await traceStep('setup-instrumentation-hook', async () => {
|
|
397
|
+
const srcInstrumentationTsExists = fs.existsSync(
|
|
398
|
+
path.join(process.cwd(), 'src', 'instrumentation.ts'),
|
|
399
|
+
);
|
|
400
|
+
const srcInstrumentationJsExists = fs.existsSync(
|
|
401
|
+
path.join(process.cwd(), 'src', 'instrumentation.js'),
|
|
402
|
+
);
|
|
403
|
+
const instrumentationTsExists = fs.existsSync(
|
|
404
|
+
path.join(process.cwd(), 'instrumentation.ts'),
|
|
405
|
+
);
|
|
406
|
+
const instrumentationJsExists = fs.existsSync(
|
|
407
|
+
path.join(process.cwd(), 'instrumentation.js'),
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
let instrumentationHookLocation: 'src' | 'root' | 'does-not-exist';
|
|
411
|
+
if (srcInstrumentationTsExists || srcInstrumentationJsExists) {
|
|
412
|
+
instrumentationHookLocation = 'src';
|
|
413
|
+
} else if (instrumentationTsExists || instrumentationJsExists) {
|
|
414
|
+
instrumentationHookLocation = 'root';
|
|
415
|
+
} else {
|
|
416
|
+
instrumentationHookLocation = 'does-not-exist';
|
|
417
|
+
}
|
|
399
418
|
|
|
400
|
-
|
|
419
|
+
if (instrumentationHookLocation === 'does-not-exist') {
|
|
420
|
+
const srcFolderExists = fs.existsSync(path.join(process.cwd(), 'src'));
|
|
401
421
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
422
|
+
const instrumentationHookPath = srcFolderExists
|
|
423
|
+
? path.join(process.cwd(), 'src', 'instrumentation.ts')
|
|
424
|
+
: path.join(process.cwd(), 'instrumentation.ts');
|
|
405
425
|
|
|
406
|
-
|
|
407
|
-
|
|
426
|
+
const successfullyCreated = await createNewConfigFile(
|
|
427
|
+
instrumentationHookPath,
|
|
428
|
+
getInstrumentationHookContent(srcFolderExists ? 'src' : 'root'),
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
if (!successfullyCreated) {
|
|
432
|
+
await showCopyPasteInstructions(
|
|
433
|
+
'instrumentation.ts',
|
|
434
|
+
getInstrumentationHookCopyPasteSnippet(
|
|
435
|
+
srcFolderExists ? 'src' : 'root',
|
|
436
|
+
),
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
await showCopyPasteInstructions(
|
|
441
|
+
srcInstrumentationTsExists
|
|
442
|
+
? 'instrumentation.ts'
|
|
443
|
+
: srcInstrumentationJsExists
|
|
444
|
+
? 'instrumentation.js'
|
|
445
|
+
: instrumentationTsExists
|
|
446
|
+
? 'instrumentation.ts'
|
|
447
|
+
: 'instrumentation.js',
|
|
448
|
+
getInstrumentationHookCopyPasteSnippet(instrumentationHookLocation),
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
408
452
|
|
|
409
453
|
await traceStep('setup-next-config', async () => {
|
|
454
|
+
const withSentryConfigOptionsTemplate = getWithSentryConfigOptionsTemplate({
|
|
455
|
+
orgSlug: selectedProject.organization.slug,
|
|
456
|
+
projectSlug: selectedProject.slug,
|
|
457
|
+
selfHosted,
|
|
458
|
+
url: sentryUrl,
|
|
459
|
+
tunnelRoute: sdkConfigOptions.tunnelRoute,
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const nextConfigJs = 'next.config.js';
|
|
463
|
+
const nextConfigMjs = 'next.config.mjs';
|
|
464
|
+
|
|
410
465
|
const nextConfigJsExists = fs.existsSync(
|
|
411
466
|
path.join(process.cwd(), nextConfigJs),
|
|
412
467
|
);
|
|
@@ -419,10 +474,7 @@ async function createOrMergeNextJsFiles(
|
|
|
419
474
|
|
|
420
475
|
await fs.promises.writeFile(
|
|
421
476
|
path.join(process.cwd(), nextConfigJs),
|
|
422
|
-
getNextjsConfigCjsTemplate(
|
|
423
|
-
sentryWebpackOptionsTemplate,
|
|
424
|
-
sentryBuildOptionsTemplate,
|
|
425
|
-
),
|
|
477
|
+
getNextjsConfigCjsTemplate(withSentryConfigOptionsTemplate),
|
|
426
478
|
{ encoding: 'utf8', flag: 'w' },
|
|
427
479
|
);
|
|
428
480
|
|
|
@@ -460,10 +512,7 @@ async function createOrMergeNextJsFiles(
|
|
|
460
512
|
if (shouldInject) {
|
|
461
513
|
await fs.promises.appendFile(
|
|
462
514
|
path.join(process.cwd(), nextConfigJs),
|
|
463
|
-
getNextjsConfigCjsAppendix(
|
|
464
|
-
sentryWebpackOptionsTemplate,
|
|
465
|
-
sentryBuildOptionsTemplate,
|
|
466
|
-
),
|
|
515
|
+
getNextjsConfigCjsAppendix(withSentryConfigOptionsTemplate),
|
|
467
516
|
'utf8',
|
|
468
517
|
);
|
|
469
518
|
|
|
@@ -514,8 +563,7 @@ async function createOrMergeNextJsFiles(
|
|
|
514
563
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
515
564
|
mod.exports.default = builders.raw(`withSentryConfig(
|
|
516
565
|
${expressionToWrap},
|
|
517
|
-
${
|
|
518
|
-
${sentryBuildOptionsTemplate}
|
|
566
|
+
${withSentryConfigOptionsTemplate}
|
|
519
567
|
)`);
|
|
520
568
|
const newCode = mod.generate().code;
|
|
521
569
|
|
|
@@ -550,10 +598,7 @@ async function createOrMergeNextJsFiles(
|
|
|
550
598
|
|
|
551
599
|
// eslint-disable-next-line no-console
|
|
552
600
|
console.log(
|
|
553
|
-
getNextjsConfigEsmCopyPasteSnippet(
|
|
554
|
-
sentryWebpackOptionsTemplate,
|
|
555
|
-
sentryBuildOptionsTemplate,
|
|
556
|
-
),
|
|
601
|
+
getNextjsConfigEsmCopyPasteSnippet(withSentryConfigOptionsTemplate),
|
|
557
602
|
);
|
|
558
603
|
|
|
559
604
|
const shouldContinue = await abortIfCancelled(
|
package/src/nextjs/templates.ts
CHANGED
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { makeCodeSnippet } from '../utils/clack-utils';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
orgSlug: string
|
|
5
|
-
projectSlug: string
|
|
6
|
-
selfHosted: boolean
|
|
7
|
-
url: string
|
|
8
|
-
|
|
4
|
+
type WithSentryConfigOptions = {
|
|
5
|
+
orgSlug: string;
|
|
6
|
+
projectSlug: string;
|
|
7
|
+
selfHosted: boolean;
|
|
8
|
+
url: string;
|
|
9
|
+
tunnelRoute: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function getWithSentryConfigOptionsTemplate({
|
|
13
|
+
orgSlug,
|
|
14
|
+
projectSlug,
|
|
15
|
+
selfHosted,
|
|
16
|
+
tunnelRoute,
|
|
17
|
+
url,
|
|
18
|
+
}: WithSentryConfigOptions): string {
|
|
9
19
|
return `{
|
|
10
20
|
// For all available options, see:
|
|
11
21
|
// https://github.com/getsentry/sentry-webpack-plugin#options
|
|
12
22
|
|
|
13
|
-
// Suppresses source map uploading logs during build
|
|
14
|
-
silent: true,
|
|
15
23
|
org: "${orgSlug}",
|
|
16
24
|
project: "${projectSlug}",${selfHosted ? `\n url: "${url}"` : ''}
|
|
17
|
-
}`;
|
|
18
|
-
}
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
26
|
+
// Only print logs for uploading source maps in CI
|
|
27
|
+
silent: !process.env.CI,
|
|
23
28
|
|
|
24
|
-
export function getNextjsSentryBuildOptionsTemplate({
|
|
25
|
-
tunnelRoute,
|
|
26
|
-
}: SentryNextjsBuildOptions): string {
|
|
27
|
-
return `{
|
|
28
29
|
// For all available options, see:
|
|
29
30
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
|
30
31
|
|
|
31
32
|
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
|
32
33
|
widenClientFileUpload: true,
|
|
33
34
|
|
|
34
|
-
// Transpiles SDK to be compatible with IE11 (increases bundle size)
|
|
35
|
-
transpileClientSDK: true,
|
|
36
|
-
|
|
37
35
|
// ${
|
|
38
36
|
tunnelRoute ? 'Route' : 'Uncomment to route'
|
|
39
37
|
} browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
|
@@ -48,7 +46,7 @@ export function getNextjsSentryBuildOptionsTemplate({
|
|
|
48
46
|
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
|
49
47
|
disableLogger: true,
|
|
50
48
|
|
|
51
|
-
// Enables automatic instrumentation of Vercel Cron Monitors.
|
|
49
|
+
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
|
|
52
50
|
// See the following for more information:
|
|
53
51
|
// https://docs.sentry.io/product/crons/
|
|
54
52
|
// https://vercel.com/docs/cron-jobs
|
|
@@ -57,8 +55,7 @@ export function getNextjsSentryBuildOptionsTemplate({
|
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
export function getNextjsConfigCjsTemplate(
|
|
60
|
-
|
|
61
|
-
sentryBuildOptionsTemplate: string,
|
|
58
|
+
withSentryConfigOptionsTemplate: string,
|
|
62
59
|
): string {
|
|
63
60
|
return `const { withSentryConfig } = require("@sentry/nextjs");
|
|
64
61
|
|
|
@@ -67,15 +64,13 @@ const nextConfig = {};
|
|
|
67
64
|
|
|
68
65
|
module.exports = withSentryConfig(
|
|
69
66
|
nextConfig,
|
|
70
|
-
${
|
|
71
|
-
${sentryBuildOptionsTemplate}
|
|
67
|
+
${withSentryConfigOptionsTemplate}
|
|
72
68
|
);
|
|
73
69
|
`;
|
|
74
70
|
}
|
|
75
71
|
|
|
76
72
|
export function getNextjsConfigCjsAppendix(
|
|
77
|
-
|
|
78
|
-
sentryBuildOptionsTemplate: string,
|
|
73
|
+
withSentryConfigOptionsTemplate: string,
|
|
79
74
|
): string {
|
|
80
75
|
return `
|
|
81
76
|
|
|
@@ -85,15 +80,13 @@ const { withSentryConfig } = require("@sentry/nextjs");
|
|
|
85
80
|
|
|
86
81
|
module.exports = withSentryConfig(
|
|
87
82
|
module.exports,
|
|
88
|
-
${
|
|
89
|
-
${sentryBuildOptionsTemplate}
|
|
83
|
+
${withSentryConfigOptionsTemplate}
|
|
90
84
|
);
|
|
91
85
|
`;
|
|
92
86
|
}
|
|
93
87
|
|
|
94
88
|
export function getNextjsConfigEsmCopyPasteSnippet(
|
|
95
|
-
|
|
96
|
-
sentryBuildOptionsTemplate: string,
|
|
89
|
+
withSentryConfigOptionsTemplate: string,
|
|
97
90
|
): string {
|
|
98
91
|
return `
|
|
99
92
|
|
|
@@ -102,8 +95,7 @@ import { withSentryConfig } from "@sentry/nextjs";
|
|
|
102
95
|
|
|
103
96
|
export default withSentryConfig(
|
|
104
97
|
yourNextConfig,
|
|
105
|
-
${
|
|
106
|
-
${sentryBuildOptionsTemplate}
|
|
98
|
+
${withSentryConfigOptionsTemplate}
|
|
107
99
|
);
|
|
108
100
|
`;
|
|
109
101
|
}
|
|
@@ -152,7 +144,7 @@ export function getSentryConfigContents(
|
|
|
152
144
|
if (config === 'server') {
|
|
153
145
|
spotlightOption = `
|
|
154
146
|
|
|
155
|
-
//
|
|
147
|
+
// Uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
|
156
148
|
// spotlight: process.env.NODE_ENV === 'development',
|
|
157
149
|
`;
|
|
158
150
|
}
|
|
@@ -235,8 +227,8 @@ export default function Page() {
|
|
|
235
227
|
fontSize: "14px",
|
|
236
228
|
margin: "18px",
|
|
237
229
|
}}
|
|
238
|
-
onClick={() => {
|
|
239
|
-
Sentry.startSpan({
|
|
230
|
+
onClick={async () => {
|
|
231
|
+
await Sentry.startSpan({
|
|
240
232
|
name: 'Example Frontend Span',
|
|
241
233
|
op: 'test'
|
|
242
234
|
}, async () => {
|
|
@@ -344,6 +336,45 @@ YourCustomErrorComponent.getInitialProps = async (contextData${
|
|
|
344
336
|
`;
|
|
345
337
|
}
|
|
346
338
|
|
|
339
|
+
export function getInstrumentationHookContent(
|
|
340
|
+
instrumentationHookLocation: 'src' | 'root',
|
|
341
|
+
) {
|
|
342
|
+
return `export async function register() {
|
|
343
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
344
|
+
await import('${
|
|
345
|
+
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
346
|
+
}/sentry.server.config');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (process.env.NEXT_RUNTIME === 'edge') {
|
|
350
|
+
await import('${
|
|
351
|
+
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
352
|
+
}/sentry.edge.config');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function getInstrumentationHookCopyPasteSnippet(
|
|
359
|
+
instrumentationHookLocation: 'src' | 'root',
|
|
360
|
+
) {
|
|
361
|
+
return makeCodeSnippet(true, (unchanged, plus) => {
|
|
362
|
+
return unchanged(`export ${plus('async')} function register() {
|
|
363
|
+
${plus(`if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
364
|
+
await import('${
|
|
365
|
+
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
366
|
+
}/sentry.server.config');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (process.env.NEXT_RUNTIME === 'edge') {
|
|
370
|
+
await import('${
|
|
371
|
+
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
372
|
+
}/sentry.edge.config');
|
|
373
|
+
}`)}
|
|
374
|
+
}`);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
347
378
|
export function getSentryDefaultGlobalErrorPage() {
|
|
348
379
|
return `"use client";
|
|
349
380
|
|
|
@@ -3,7 +3,10 @@ import * as clack from '@clack/prompts';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { runNextjsWizard } from '../../nextjs/nextjs-wizard';
|
|
5
5
|
import { traceStep } from '../../telemetry';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
abortIfCancelled,
|
|
8
|
+
addDotEnvSentryBuildPluginFile,
|
|
9
|
+
} from '../../utils/clack-utils';
|
|
7
10
|
import { WizardOptions } from '../../utils/types';
|
|
8
11
|
|
|
9
12
|
import { SourceMapUploadToolConfigurationOptions } from './types';
|
|
@@ -99,7 +102,7 @@ In case you already tried the wizard, we can also show you how to configure your
|
|
|
99
102
|
);
|
|
100
103
|
|
|
101
104
|
await traceStep('nextjs-manual-sentryclirc', () =>
|
|
102
|
-
|
|
105
|
+
addDotEnvSentryBuildPluginFile(options.authToken),
|
|
103
106
|
);
|
|
104
107
|
}
|
|
105
108
|
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -550,7 +550,7 @@ export async function addDotEnvSentryBuildPluginFile(
|
|
|
550
550
|
# The SENTRY_AUTH_TOKEN variable is picked up by the Sentry Build Plugin.
|
|
551
551
|
# It's used for authentication when uploading source maps.
|
|
552
552
|
# You can also set this env variable in your own \`.env\` files and remove this file.
|
|
553
|
-
SENTRY_AUTH_TOKEN
|
|
553
|
+
SENTRY_AUTH_TOKEN=${authToken}
|
|
554
554
|
`;
|
|
555
555
|
|
|
556
556
|
const dotEnvFilePath = path.join(process.cwd(), SENTRY_DOT_ENV_FILE);
|
|
@@ -800,7 +800,7 @@ ${chalk.cyan('https://github.com/getsentry/sentry-wizard/issues')}`);
|
|
|
800
800
|
clack.log.info(`In the meantime, we'll add a dummy auth token (${chalk.cyan(
|
|
801
801
|
`"${DUMMY_AUTH_TOKEN}"`,
|
|
802
802
|
)}) for you to replace later.
|
|
803
|
-
Create your auth token here:
|
|
803
|
+
Create your auth token here:
|
|
804
804
|
${chalk.cyan(
|
|
805
805
|
selfHosted
|
|
806
806
|
? `${sentryUrl}organizations/${selectedProject.organization.slug}/settings/auth-tokens`
|