@sentry/wizard 3.12.0 → 3.14.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 +19 -0
- package/dist/lib/Steps/ChooseIntegration.js +1 -0
- package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
- package/dist/package.json +2 -2
- package/dist/src/android/android-wizard.js +8 -8
- package/dist/src/android/android-wizard.js.map +1 -1
- package/dist/src/apple/apple-wizard.js +1 -1
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.d.ts +1 -0
- package/dist/src/nextjs/nextjs-wizard.js +257 -163
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +1 -1
- package/dist/src/nextjs/templates.js +2 -2
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/nextjs/utils.d.ts +1 -0
- package/dist/src/nextjs/utils.js +25 -0
- package/dist/src/nextjs/utils.js.map +1 -0
- package/dist/src/remix/remix-wizard.js +13 -11
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-setup.d.ts +5 -1
- package/dist/src/remix/sdk-setup.js +13 -6
- package/dist/src/remix/sdk-setup.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/sourcemaps/tools/sentry-cli.d.ts +9 -0
- package/dist/src/sourcemaps/tools/sentry-cli.js +26 -22
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/tsc.d.ts +6 -0
- package/dist/src/sourcemaps/tools/tsc.js +98 -17
- package/dist/src/sourcemaps/tools/tsc.js.map +1 -1
- package/dist/src/sourcemaps/tools/vite.js +3 -13
- package/dist/src/sourcemaps/tools/vite.js.map +1 -1
- package/dist/src/sourcemaps/tools/webpack.js +3 -13
- package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup.js +122 -48
- package/dist/src/sveltekit/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.d.ts +1 -0
- package/dist/src/sveltekit/sveltekit-wizard.js +113 -42
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/sveltekit/utils.d.ts +2 -0
- package/dist/src/sveltekit/utils.js +48 -0
- package/dist/src/sveltekit/utils.js.map +1 -0
- package/dist/src/telemetry.d.ts +1 -0
- package/dist/src/telemetry.js +27 -12
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/ast-utils.d.ts +70 -0
- package/dist/src/utils/ast-utils.js +152 -1
- package/dist/src/utils/ast-utils.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +49 -7
- package/dist/src/utils/clack-utils.js +238 -168
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +5 -0
- package/dist/src/utils/package-manager.js +23 -14
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/test/sourcemaps/tools/sentry-cli.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/sentry-cli.test.js +112 -0
- package/dist/test/sourcemaps/tools/sentry-cli.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/tsc.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/tsc.test.js +121 -0
- package/dist/test/sourcemaps/tools/tsc.test.js.map +1 -0
- package/dist/test/utils/ast-utils.test.js +157 -26
- package/dist/test/utils/ast-utils.test.js.map +1 -1
- package/lib/Steps/ChooseIntegration.ts +1 -0
- package/package.json +2 -2
- package/src/android/android-wizard.ts +12 -10
- package/src/apple/apple-wizard.ts +2 -2
- package/src/nextjs/nextjs-wizard.ts +277 -198
- package/src/nextjs/templates.ts +3 -2
- package/src/nextjs/utils.ts +21 -0
- package/src/remix/remix-wizard.ts +15 -20
- package/src/remix/sdk-setup.ts +20 -5
- package/src/sourcemaps/sourcemaps-wizard.ts +2 -2
- package/src/sourcemaps/tools/sentry-cli.ts +16 -9
- package/src/sourcemaps/tools/tsc.ts +133 -28
- package/src/sourcemaps/tools/vite.ts +15 -39
- package/src/sourcemaps/tools/webpack.ts +16 -39
- package/src/sveltekit/sdk-setup.ts +109 -37
- package/src/sveltekit/sveltekit-wizard.ts +86 -21
- package/src/sveltekit/utils.ts +50 -0
- package/src/telemetry.ts +22 -11
- package/src/utils/ast-utils.ts +180 -0
- package/src/utils/clack-utils.ts +238 -149
- package/src/utils/package-manager.ts +24 -12
- package/test/sourcemaps/tools/sentry-cli.test.ts +51 -0
- package/test/sourcemaps/tools/tsc.test.ts +181 -0
- package/test/utils/ast-utils.test.ts +233 -32
|
@@ -7,11 +7,13 @@ import * as fs from 'fs';
|
|
|
7
7
|
import { builders, generateCode, parseModule } from 'magicast';
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
|
|
10
|
+
import * as Sentry from '@sentry/node';
|
|
11
|
+
|
|
10
12
|
import {
|
|
11
13
|
abort,
|
|
12
14
|
abortIfCancelled,
|
|
13
15
|
addSentryCliConfig,
|
|
14
|
-
|
|
16
|
+
confirmContinueIfNoOrDirtyGitRepo,
|
|
15
17
|
ensurePackageIsInstalled,
|
|
16
18
|
getOrAskForProjectData,
|
|
17
19
|
getPackageDotJson,
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
isUsingTypeScript,
|
|
20
22
|
printWelcome,
|
|
21
23
|
} from '../utils/clack-utils';
|
|
22
|
-
import { WizardOptions } from '../utils/types';
|
|
24
|
+
import { SentryProjectData, WizardOptions } from '../utils/types';
|
|
23
25
|
import {
|
|
24
26
|
getNextjsConfigCjsAppendix,
|
|
25
27
|
getNextjsConfigCjsTemplate,
|
|
@@ -31,255 +33,344 @@ import {
|
|
|
31
33
|
getSentryExampleAppDirApiRoute,
|
|
32
34
|
getSentryExamplePageContents,
|
|
33
35
|
} from './templates';
|
|
36
|
+
import { traceStep, withTelemetry } from '../telemetry';
|
|
37
|
+
import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
|
|
38
|
+
import { getNextJsVersionBucket } from './utils';
|
|
39
|
+
|
|
40
|
+
export function runNextjsWizard(options: WizardOptions) {
|
|
41
|
+
return withTelemetry(
|
|
42
|
+
{
|
|
43
|
+
enabled: options.telemetryEnabled,
|
|
44
|
+
integration: 'nextjs',
|
|
45
|
+
},
|
|
46
|
+
() => runNextjsWizardWithTelemetry(options),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
export async function runNextjsWizardWithTelemetry(
|
|
51
|
+
options: WizardOptions,
|
|
52
|
+
): Promise<void> {
|
|
37
53
|
printWelcome({
|
|
38
54
|
wizardName: 'Sentry Next.js Wizard',
|
|
39
55
|
promoCode: options.promoCode,
|
|
56
|
+
telemetryEnabled: options.telemetryEnabled,
|
|
40
57
|
});
|
|
41
58
|
|
|
42
|
-
await
|
|
59
|
+
await confirmContinueIfNoOrDirtyGitRepo();
|
|
43
60
|
|
|
44
61
|
const packageJson = await getPackageDotJson();
|
|
62
|
+
|
|
45
63
|
await ensurePackageIsInstalled(packageJson, 'next', 'Next.js');
|
|
46
64
|
|
|
65
|
+
const nextVersion = getPackageVersion('next', packageJson);
|
|
66
|
+
Sentry.setTag('nextjs-version', getNextJsVersionBucket(nextVersion));
|
|
67
|
+
|
|
47
68
|
const { selectedProject, authToken, selfHosted, sentryUrl } =
|
|
48
69
|
await getOrAskForProjectData(options, 'javascript-nextjs');
|
|
49
70
|
|
|
71
|
+
const sdkAlreadyInstalled = hasPackageInstalled(
|
|
72
|
+
'@sentry/nextjs',
|
|
73
|
+
packageJson,
|
|
74
|
+
);
|
|
75
|
+
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
76
|
+
|
|
50
77
|
await installPackage({
|
|
51
78
|
packageName: '@sentry/nextjs',
|
|
52
79
|
alreadyInstalled: !!packageJson?.dependencies?.['@sentry/nextjs'],
|
|
53
80
|
});
|
|
54
81
|
|
|
55
|
-
|
|
82
|
+
await traceStep('configure-sdk', async () =>
|
|
83
|
+
createOrMergeNextJsFiles(selectedProject, selfHosted, sentryUrl),
|
|
84
|
+
);
|
|
56
85
|
|
|
57
|
-
|
|
86
|
+
await traceStep('create-example-page', async () =>
|
|
87
|
+
createExamplePage(selfHosted, selectedProject, sentryUrl),
|
|
88
|
+
);
|
|
58
89
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
90
|
+
await addSentryCliConfig(authToken);
|
|
91
|
+
|
|
92
|
+
const mightBeUsingVercel = fs.existsSync(
|
|
93
|
+
path.join(process.cwd(), 'vercel.json'),
|
|
94
|
+
);
|
|
62
95
|
|
|
63
|
-
|
|
64
|
-
|
|
96
|
+
clack.outro(
|
|
97
|
+
`${chalk.green('Everything is set up!')}
|
|
98
|
+
|
|
99
|
+
${chalk.cyan(
|
|
100
|
+
'You can validate your setup by starting your dev environment (`next dev`) and visiting "/sentry-example-page".',
|
|
101
|
+
)}
|
|
102
|
+
${
|
|
103
|
+
mightBeUsingVercel
|
|
104
|
+
? `
|
|
105
|
+
▲ It seems like you're using Vercel. We recommend using the Sentry Vercel integration: https://vercel.com/integrations/sentry
|
|
106
|
+
`
|
|
107
|
+
: ''
|
|
108
|
+
}
|
|
109
|
+
${chalk.dim(
|
|
110
|
+
'If you encounter any issues, let us know here: https://github.com/getsentry/sentry-javascript/issues',
|
|
111
|
+
)}`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
65
114
|
|
|
66
|
-
|
|
115
|
+
async function createOrMergeNextJsFiles(
|
|
116
|
+
selectedProject: SentryProjectData,
|
|
117
|
+
selfHosted: boolean,
|
|
118
|
+
sentryUrl: string,
|
|
119
|
+
) {
|
|
120
|
+
const typeScriptDetected = isUsingTypeScript();
|
|
67
121
|
|
|
68
|
-
|
|
69
|
-
const existingConfigs = [];
|
|
122
|
+
const configVariants = ['server', 'client', 'edge'] as const;
|
|
70
123
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
124
|
+
for (const configVariant of configVariants) {
|
|
125
|
+
await traceStep(`create-sentry-${configVariant}-config`, async () => {
|
|
126
|
+
const jsConfig = `sentry.${configVariant}.config.js`;
|
|
127
|
+
const tsConfig = `sentry.${configVariant}.config.ts`;
|
|
74
128
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
129
|
+
const jsConfigExists = fs.existsSync(path.join(process.cwd(), jsConfig));
|
|
130
|
+
const tsConfigExists = fs.existsSync(path.join(process.cwd(), tsConfig));
|
|
78
131
|
|
|
79
|
-
|
|
80
|
-
clack.confirm({
|
|
81
|
-
message: `Found existing Sentry ${configVariant} config (${existingConfigs.join(
|
|
82
|
-
', ',
|
|
83
|
-
)}). Overwrite ${existingConfigs.length > 1 ? 'them' : 'it'}?`,
|
|
84
|
-
}),
|
|
85
|
-
);
|
|
132
|
+
let shouldWriteFile = true;
|
|
86
133
|
|
|
87
|
-
|
|
134
|
+
if (jsConfigExists || tsConfigExists) {
|
|
135
|
+
const existingConfigs = [];
|
|
88
136
|
|
|
89
|
-
if (overwriteExistingConfigs) {
|
|
90
137
|
if (jsConfigExists) {
|
|
91
|
-
|
|
92
|
-
clack.log.warn(`Removed existing ${chalk.bold(jsConfig)}.`);
|
|
138
|
+
existingConfigs.push(jsConfig);
|
|
93
139
|
}
|
|
140
|
+
|
|
94
141
|
if (tsConfigExists) {
|
|
95
|
-
|
|
96
|
-
|
|
142
|
+
existingConfigs.push(tsConfig);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const overwriteExistingConfigs = await abortIfCancelled(
|
|
146
|
+
clack.confirm({
|
|
147
|
+
message: `Found existing Sentry ${configVariant} config (${existingConfigs.join(
|
|
148
|
+
', ',
|
|
149
|
+
)}). Overwrite ${existingConfigs.length > 1 ? 'them' : 'it'}?`,
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
Sentry.setTag(
|
|
153
|
+
`overwrite-${configVariant}-config`,
|
|
154
|
+
overwriteExistingConfigs,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
shouldWriteFile = overwriteExistingConfigs;
|
|
158
|
+
|
|
159
|
+
if (overwriteExistingConfigs) {
|
|
160
|
+
if (jsConfigExists) {
|
|
161
|
+
fs.unlinkSync(path.join(process.cwd(), jsConfig));
|
|
162
|
+
clack.log.warn(`Removed existing ${chalk.bold(jsConfig)}.`);
|
|
163
|
+
}
|
|
164
|
+
if (tsConfigExists) {
|
|
165
|
+
fs.unlinkSync(path.join(process.cwd(), tsConfig));
|
|
166
|
+
clack.log.warn(`Removed existing ${chalk.bold(tsConfig)}.`);
|
|
167
|
+
}
|
|
97
168
|
}
|
|
98
169
|
}
|
|
99
|
-
}
|
|
100
170
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
171
|
+
if (shouldWriteFile) {
|
|
172
|
+
await fs.promises.writeFile(
|
|
173
|
+
path.join(process.cwd(), typeScriptDetected ? tsConfig : jsConfig),
|
|
174
|
+
getSentryConfigContents(
|
|
175
|
+
selectedProject.keys[0].dsn.public,
|
|
176
|
+
configVariant,
|
|
177
|
+
),
|
|
178
|
+
{ encoding: 'utf8', flag: 'w' },
|
|
179
|
+
);
|
|
180
|
+
clack.log.success(
|
|
181
|
+
`Created fresh ${chalk.bold(
|
|
182
|
+
typeScriptDetected ? tsConfig : jsConfig,
|
|
183
|
+
)}.`,
|
|
184
|
+
);
|
|
185
|
+
Sentry.setTag(`created-${configVariant}-config`, true);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
116
188
|
}
|
|
117
189
|
|
|
118
190
|
const sentryWebpackOptionsTemplate = getNextjsWebpackPluginOptionsTemplate(
|
|
119
191
|
selectedProject.organization.slug,
|
|
120
192
|
selectedProject.slug,
|
|
193
|
+
selfHosted,
|
|
194
|
+
sentryUrl,
|
|
121
195
|
);
|
|
122
196
|
const sentryBuildOptionsTemplate = getNextjsSentryBuildOptionsTemplate();
|
|
123
197
|
|
|
124
198
|
const nextConfigJs = 'next.config.js';
|
|
125
199
|
const nextConfigMjs = 'next.config.mjs';
|
|
126
200
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
130
|
-
const nextConfigMjsExists = fs.existsSync(
|
|
131
|
-
path.join(process.cwd(), nextConfigMjs),
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
if (!nextConfigJsExists && !nextConfigMjsExists) {
|
|
135
|
-
await fs.promises.writeFile(
|
|
201
|
+
await traceStep('setup-next-config', async () => {
|
|
202
|
+
const nextConfigJsExists = fs.existsSync(
|
|
136
203
|
path.join(process.cwd(), nextConfigJs),
|
|
137
|
-
getNextjsConfigCjsTemplate(
|
|
138
|
-
sentryWebpackOptionsTemplate,
|
|
139
|
-
sentryBuildOptionsTemplate,
|
|
140
|
-
),
|
|
141
|
-
{ encoding: 'utf8', flag: 'w' },
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
clack.log.success(
|
|
145
|
-
`Created ${chalk.bold('next.config.js')} with Sentry configuration.`,
|
|
146
204
|
);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (nextConfigJsExists) {
|
|
150
|
-
const nextConfgiJsContent = fs.readFileSync(
|
|
151
|
-
path.join(process.cwd(), nextConfigJs),
|
|
152
|
-
'utf8',
|
|
205
|
+
const nextConfigMjsExists = fs.existsSync(
|
|
206
|
+
path.join(process.cwd(), nextConfigMjs),
|
|
153
207
|
);
|
|
154
208
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
nextConfgiJsContent.includes('withSentryConfig');
|
|
158
|
-
|
|
159
|
-
let shouldInject = true;
|
|
160
|
-
|
|
161
|
-
if (probablyIncludesSdk) {
|
|
162
|
-
const injectAnyhow = await abortIfCancelled(
|
|
163
|
-
clack.confirm({
|
|
164
|
-
message: `${chalk.bold(
|
|
165
|
-
nextConfigJs,
|
|
166
|
-
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
167
|
-
}),
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
shouldInject = injectAnyhow;
|
|
171
|
-
}
|
|
209
|
+
if (!nextConfigJsExists && !nextConfigMjsExists) {
|
|
210
|
+
Sentry.setTag('next-config-strategy', 'create');
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
await fs.promises.appendFile(
|
|
212
|
+
await fs.promises.writeFile(
|
|
175
213
|
path.join(process.cwd(), nextConfigJs),
|
|
176
|
-
|
|
214
|
+
getNextjsConfigCjsTemplate(
|
|
177
215
|
sentryWebpackOptionsTemplate,
|
|
178
216
|
sentryBuildOptionsTemplate,
|
|
179
217
|
),
|
|
180
|
-
'utf8',
|
|
218
|
+
{ encoding: 'utf8', flag: 'w' },
|
|
181
219
|
);
|
|
182
220
|
|
|
183
221
|
clack.log.success(
|
|
184
|
-
`
|
|
185
|
-
'(you probably want to clean this up a bit!)',
|
|
186
|
-
)}`,
|
|
222
|
+
`Created ${chalk.bold('next.config.js')} with Sentry configuration.`,
|
|
187
223
|
);
|
|
188
224
|
}
|
|
189
|
-
}
|
|
190
225
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
path.join(process.cwd(), nextConfigMjs),
|
|
194
|
-
'utf8',
|
|
195
|
-
);
|
|
226
|
+
if (nextConfigJsExists) {
|
|
227
|
+
Sentry.setTag('next-config-strategy', 'modify');
|
|
196
228
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
229
|
+
const nextConfgiJsContent = fs.readFileSync(
|
|
230
|
+
path.join(process.cwd(), nextConfigJs),
|
|
231
|
+
'utf8',
|
|
232
|
+
);
|
|
200
233
|
|
|
201
|
-
|
|
234
|
+
const probablyIncludesSdk =
|
|
235
|
+
nextConfgiJsContent.includes('@sentry/nextjs') &&
|
|
236
|
+
nextConfgiJsContent.includes('withSentryConfig');
|
|
202
237
|
|
|
203
|
-
|
|
204
|
-
const injectAnyhow = await abortIfCancelled(
|
|
205
|
-
clack.confirm({
|
|
206
|
-
message: `${chalk.bold(
|
|
207
|
-
nextConfigMjs,
|
|
208
|
-
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
209
|
-
}),
|
|
210
|
-
);
|
|
238
|
+
let shouldInject = true;
|
|
211
239
|
|
|
212
|
-
|
|
213
|
-
|
|
240
|
+
if (probablyIncludesSdk) {
|
|
241
|
+
const injectAnyhow = await abortIfCancelled(
|
|
242
|
+
clack.confirm({
|
|
243
|
+
message: `${chalk.bold(
|
|
244
|
+
nextConfigJs,
|
|
245
|
+
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
246
|
+
}),
|
|
247
|
+
);
|
|
214
248
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const mod = parseModule(nextConfgiMjsContent);
|
|
218
|
-
mod.imports.$add({
|
|
219
|
-
from: '@sentry/nextjs',
|
|
220
|
-
imported: 'withSentryConfig',
|
|
221
|
-
local: 'withSentryConfig',
|
|
222
|
-
});
|
|
223
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
224
|
-
const expressionToWrap = generateCode(mod.exports.default.$ast).code;
|
|
225
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
226
|
-
mod.exports.default = builders.raw(`withSentryConfig(
|
|
227
|
-
${expressionToWrap},
|
|
228
|
-
${sentryWebpackOptionsTemplate},
|
|
229
|
-
${sentryBuildOptionsTemplate}
|
|
230
|
-
)`);
|
|
231
|
-
const newCode = mod.generate().code;
|
|
249
|
+
shouldInject = injectAnyhow;
|
|
250
|
+
}
|
|
232
251
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
252
|
+
if (shouldInject) {
|
|
253
|
+
await fs.promises.appendFile(
|
|
254
|
+
path.join(process.cwd(), nextConfigJs),
|
|
255
|
+
getNextjsConfigCjsAppendix(
|
|
256
|
+
sentryWebpackOptionsTemplate,
|
|
257
|
+
sentryBuildOptionsTemplate,
|
|
258
|
+
),
|
|
259
|
+
'utf8',
|
|
240
260
|
);
|
|
261
|
+
|
|
241
262
|
clack.log.success(
|
|
242
263
|
`Added Sentry configuration to ${chalk.bold(
|
|
243
|
-
|
|
264
|
+
nextConfigJs,
|
|
244
265
|
)}. ${chalk.dim('(you probably want to clean this up a bit!)')}`,
|
|
245
266
|
);
|
|
246
267
|
}
|
|
247
|
-
} catch {
|
|
248
|
-
clack.log.warn(
|
|
249
|
-
chalk.yellow(
|
|
250
|
-
`Something went wrong writing to ${chalk.bold(nextConfigMjs)}`,
|
|
251
|
-
),
|
|
252
|
-
);
|
|
253
|
-
clack.log.info(
|
|
254
|
-
`Please put the following code snippet into ${chalk.bold(
|
|
255
|
-
nextConfigMjs,
|
|
256
|
-
)}: ${chalk.dim('You probably have to clean it up a bit.')}\n`,
|
|
257
|
-
);
|
|
258
268
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
),
|
|
269
|
+
Sentry.setTag('next-config-mod-result', 'success');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (nextConfigMjsExists) {
|
|
273
|
+
const nextConfgiMjsContent = fs.readFileSync(
|
|
274
|
+
path.join(process.cwd(), nextConfigMjs),
|
|
275
|
+
'utf8',
|
|
265
276
|
);
|
|
266
277
|
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
278
|
+
const probablyIncludesSdk =
|
|
279
|
+
nextConfgiMjsContent.includes('@sentry/nextjs') &&
|
|
280
|
+
nextConfgiMjsContent.includes('withSentryConfig');
|
|
281
|
+
|
|
282
|
+
let shouldInject = true;
|
|
283
|
+
|
|
284
|
+
if (probablyIncludesSdk) {
|
|
285
|
+
const injectAnyhow = await abortIfCancelled(
|
|
286
|
+
clack.confirm({
|
|
287
|
+
message: `${chalk.bold(
|
|
288
|
+
nextConfigMjs,
|
|
289
|
+
)} already contains Sentry SDK configuration. Should the wizard modify it anyways?`,
|
|
290
|
+
}),
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
shouldInject = injectAnyhow;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
if (shouldInject) {
|
|
298
|
+
const mod = parseModule(nextConfgiMjsContent);
|
|
299
|
+
mod.imports.$add({
|
|
300
|
+
from: '@sentry/nextjs',
|
|
301
|
+
imported: 'withSentryConfig',
|
|
302
|
+
local: 'withSentryConfig',
|
|
303
|
+
});
|
|
304
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
305
|
+
const expressionToWrap = generateCode(mod.exports.default.$ast).code;
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
307
|
+
mod.exports.default = builders.raw(`withSentryConfig(
|
|
308
|
+
${expressionToWrap},
|
|
309
|
+
${sentryWebpackOptionsTemplate},
|
|
310
|
+
${sentryBuildOptionsTemplate}
|
|
311
|
+
)`);
|
|
312
|
+
const newCode = mod.generate().code;
|
|
313
|
+
|
|
314
|
+
await fs.promises.writeFile(
|
|
315
|
+
path.join(process.cwd(), nextConfigMjs),
|
|
316
|
+
newCode,
|
|
317
|
+
{
|
|
318
|
+
encoding: 'utf8',
|
|
319
|
+
flag: 'w',
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
clack.log.success(
|
|
323
|
+
`Added Sentry configuration to ${chalk.bold(
|
|
324
|
+
nextConfigMjs,
|
|
325
|
+
)}. ${chalk.dim('(you probably want to clean this up a bit!)')}`,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
Sentry.setTag('next-config-mod-result', 'success');
|
|
329
|
+
}
|
|
330
|
+
} catch {
|
|
331
|
+
Sentry.setTag('next-config-mod-result', 'fail');
|
|
332
|
+
clack.log.warn(
|
|
333
|
+
chalk.yellow(
|
|
334
|
+
`Something went wrong writing to ${chalk.bold(nextConfigMjs)}`,
|
|
335
|
+
),
|
|
336
|
+
);
|
|
337
|
+
clack.log.info(
|
|
338
|
+
`Please put the following code snippet into ${chalk.bold(
|
|
270
339
|
nextConfigMjs,
|
|
271
|
-
)}
|
|
272
|
-
|
|
273
|
-
inactive: 'No, get me out of here',
|
|
274
|
-
}),
|
|
275
|
-
);
|
|
340
|
+
)}: ${chalk.dim('You probably have to clean it up a bit.')}\n`,
|
|
341
|
+
);
|
|
276
342
|
|
|
277
|
-
|
|
278
|
-
|
|
343
|
+
// eslint-disable-next-line no-console
|
|
344
|
+
console.log(
|
|
345
|
+
getNextjsConfigEsmCopyPasteSnippet(
|
|
346
|
+
sentryWebpackOptionsTemplate,
|
|
347
|
+
sentryBuildOptionsTemplate,
|
|
348
|
+
),
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
const shouldContinue = await abortIfCancelled(
|
|
352
|
+
clack.confirm({
|
|
353
|
+
message: `Are you done putting the snippet above into ${chalk.bold(
|
|
354
|
+
nextConfigMjs,
|
|
355
|
+
)}?`,
|
|
356
|
+
active: 'Yes',
|
|
357
|
+
inactive: 'No, get me out of here',
|
|
358
|
+
}),
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
if (!shouldContinue) {
|
|
362
|
+
await abort();
|
|
363
|
+
}
|
|
279
364
|
}
|
|
280
365
|
}
|
|
281
|
-
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
282
368
|
|
|
369
|
+
async function createExamplePage(
|
|
370
|
+
selfHosted: boolean,
|
|
371
|
+
selectedProject: SentryProjectData,
|
|
372
|
+
sentryUrl: string,
|
|
373
|
+
): Promise<void> {
|
|
283
374
|
const srcDir = path.join(process.cwd(), 'src');
|
|
284
375
|
const maybePagesDirPath = path.join(process.cwd(), 'pages');
|
|
285
376
|
const maybeSrcPagesDirPath = path.join(srcDir, 'pages');
|
|
@@ -314,6 +405,8 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
|
|
|
314
405
|
});
|
|
315
406
|
}
|
|
316
407
|
|
|
408
|
+
Sentry.setTag('nextjs-app-dir', !!appLocation);
|
|
409
|
+
|
|
317
410
|
if (appLocation) {
|
|
318
411
|
const examplePageContents = getSentryExamplePageContents({
|
|
319
412
|
selfHosted,
|
|
@@ -323,6 +416,13 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
|
|
|
323
416
|
useClient: true,
|
|
324
417
|
});
|
|
325
418
|
|
|
419
|
+
fs.mkdirSync(
|
|
420
|
+
path.join(process.cwd(), ...appLocation, 'sentry-example-page'),
|
|
421
|
+
{
|
|
422
|
+
recursive: true,
|
|
423
|
+
},
|
|
424
|
+
);
|
|
425
|
+
|
|
326
426
|
await fs.promises.writeFile(
|
|
327
427
|
path.join(
|
|
328
428
|
process.cwd(),
|
|
@@ -340,9 +440,12 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
|
|
|
340
440
|
)}.`,
|
|
341
441
|
);
|
|
342
442
|
|
|
343
|
-
fs.mkdirSync(
|
|
344
|
-
|
|
345
|
-
|
|
443
|
+
fs.mkdirSync(
|
|
444
|
+
path.join(process.cwd(), ...appLocation, 'api', 'sentry-example-api'),
|
|
445
|
+
{
|
|
446
|
+
recursive: true,
|
|
447
|
+
},
|
|
448
|
+
);
|
|
346
449
|
|
|
347
450
|
await fs.promises.writeFile(
|
|
348
451
|
path.join(
|
|
@@ -403,28 +506,4 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
|
|
|
403
506
|
)}.`,
|
|
404
507
|
);
|
|
405
508
|
}
|
|
406
|
-
|
|
407
|
-
await addSentryCliConfig(authToken);
|
|
408
|
-
|
|
409
|
-
const mightBeUsingVercel = fs.existsSync(
|
|
410
|
-
path.join(process.cwd(), 'vercel.json'),
|
|
411
|
-
);
|
|
412
|
-
|
|
413
|
-
clack.outro(
|
|
414
|
-
`${chalk.green('Everything is set up!')}
|
|
415
|
-
|
|
416
|
-
${chalk.cyan(
|
|
417
|
-
'You can validate your setup by starting your dev environment (`next dev`) and visiting "/sentry-example-page".',
|
|
418
|
-
)}
|
|
419
|
-
${
|
|
420
|
-
mightBeUsingVercel
|
|
421
|
-
? `
|
|
422
|
-
▲ It seems like you're using Vercel. We recommend using the Sentry Vercel integration: https://vercel.com/integrations/sentry
|
|
423
|
-
`
|
|
424
|
-
: ''
|
|
425
|
-
}
|
|
426
|
-
${chalk.dim(
|
|
427
|
-
'If you encounter any issues, let us know here: https://github.com/getsentry/sentry-javascript/issues',
|
|
428
|
-
)}`,
|
|
429
|
-
);
|
|
430
509
|
}
|
package/src/nextjs/templates.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export function getNextjsWebpackPluginOptionsTemplate(
|
|
2
2
|
orgSlug: string,
|
|
3
3
|
projectSlug: string,
|
|
4
|
+
selfHosted: boolean,
|
|
5
|
+
url: string,
|
|
4
6
|
): string {
|
|
5
7
|
return `{
|
|
6
8
|
// For all available options, see:
|
|
@@ -8,9 +10,8 @@ export function getNextjsWebpackPluginOptionsTemplate(
|
|
|
8
10
|
|
|
9
11
|
// Suppresses source map uploading logs during build
|
|
10
12
|
silent: true,
|
|
11
|
-
|
|
12
13
|
org: "${orgSlug}",
|
|
13
|
-
project: "${projectSlug}"
|
|
14
|
+
project: "${projectSlug}",${selfHosted ? `\n url: "${url}"` : ''}
|
|
14
15
|
}`;
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { major, minVersion } from 'semver';
|
|
2
|
+
|
|
3
|
+
export function getNextJsVersionBucket(version: string | undefined) {
|
|
4
|
+
if (!version) {
|
|
5
|
+
return 'none';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const minVer = minVersion(version);
|
|
10
|
+
if (!minVer) {
|
|
11
|
+
return 'invalid';
|
|
12
|
+
}
|
|
13
|
+
const majorVersion = major(minVer);
|
|
14
|
+
if (majorVersion >= 11) {
|
|
15
|
+
return `${majorVersion}.x`;
|
|
16
|
+
}
|
|
17
|
+
return '<11.0.0';
|
|
18
|
+
} catch {
|
|
19
|
+
return 'unknown';
|
|
20
|
+
}
|
|
21
|
+
}
|