Skip to content

Commit

Permalink
feat(nextjs): Add support for Next.js 13 app router (#385)
Browse files Browse the repository at this point in the history
Co-authored-by: Mayank <[email protected]>
Co-authored-by: Luca Forstner <[email protected]>
  • Loading branch information
mayank1513 and lforst authored Sep 5, 2023
1 parent fbb98fe commit c359a96
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 15 deletions.
24 changes: 16 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ npx @sentry/wizard@latest -i android
brew install getsentry/tools/sentry-wizard && sentry-wizard -i android
```

- feat(craft): Add `brew` target for automatically publishing `sentry-wizard` to Sentry's custom Homebrew tap (#406)
- feat(craft): Add `brew` target for automatically publishing `sentry-wizard` to
Sentry's custom Homebrew tap (#406)

You can now install `sentry-wizard` via Homebrew:

Expand All @@ -24,7 +25,8 @@ brew install getsentry/tools/sentry-wizard
- feat: Add Bun package manager support (#417)
- feat(apple): Add option to choose between cocoapods when available and SPM (#423)
- feat(apple): Search App entry point by build files not directories (#420)
- feat(apple): Use ".sentryclirc" for auth instead of hard coding it (#422)
- feat(apple): Use ".sentryclirc" for auth instead of hard coding it (#422)
- feat(nextjs): Add support for Next.js 13 app router (#385)
- feat(sourcemaps): Provide exit path if there's no need to upload sourcemaps (#415)
- fix: Handle no projects available (#412)
- fix: Remove picocolor usage (#426)
Expand Down Expand Up @@ -52,18 +54,22 @@ npx @sentry/wizard@latest -i remix
## 3.9.1

- ref(sourcemaps): Handle no vite config found case (#391)
- ref(sourcemaps): Improve handling of vite config already having Sentry code (#392)
- ref(sourcemaps): Improve handling of vite config already having Sentry code
(#392)
- fix(apple): Don't remove other swift packages (#396)

## 3.9.0

- ref: Add debug logging to clack-based wizards (#381)
- fix: Pin minimum version to Node 14.18 (#383)
- feat(sourcemaps): Automatically insert Sentry Vite plugin in Vite config (#382)
- feat(sourcemaps): Automatically insert Sentry Vite plugin in Vite config
(#382)
- feat(reactnative): Use `with-environment.sh` in Xcode Build Phases (#329)
- fix(sveltekit): Bump `magicast` to handle vite configs declared as variables (#380)
- fix(sveltekit): Bump `magicast` to handle vite configs declared as variables
(#380)
- ref(sveltekit): Add vite plugin insertion fallback mechanism (#379)
- ref(sveltekit): Insert project config into vite config instead of `sentry.properties` (#378)
- ref(sveltekit): Insert project config into vite config instead of
`sentry.properties` (#378)

## 3.8.0

Expand All @@ -74,7 +80,8 @@ npx @sentry/wizard@latest -i remix
- feat(sourcemaps): Add option to add cli npm script to build command (#374)
- fix(login): Avoid repeatedly printing loading message (#368)
- fix(sveltekit): Abort the wizard when encountering an error (#376)
- ref(sourcemaps): Redirect to ReactNative wizard if RN project is detected (#369)
- ref(sourcemaps): Redirect to ReactNative wizard if RN project is detected
(#369)

## 3.7.1

Expand All @@ -91,7 +98,8 @@ fix(telemetry): Re-enable telemetry collection (#361)

- feat(apple): Add support for iOS (#334)
- feat(sourcemaps): Add CLI-based flow for Angular (#349)
- feat(sourcemaps): Detect SvelteKit and NextJS projects and redirect to dedicated wizards (#341)
- feat(sourcemaps): Detect SvelteKit and NextJS projects and redirect to
dedicated wizards (#341)
- feat(sourcemaps): Pre-select auto-detected build tool option (#354)
- ref(sourcemaps): Improve Outro message (#344)

Expand Down
74 changes: 69 additions & 5 deletions src/nextjs/nextjs-wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getNextjsWebpackPluginOptionsTemplate,
getSentryConfigContents,
getSentryExampleApiRoute,
getSentryExampleAppDirApiRoute,
getSentryExamplePageContents,
} from './templates';

Expand Down Expand Up @@ -279,8 +280,11 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
}
}

const srcDir = path.join(process.cwd(), 'src');
const maybePagesDirPath = path.join(process.cwd(), 'pages');
const maybeSrcPagesDirPath = path.join(process.cwd(), 'src', 'pages');
const maybeSrcPagesDirPath = path.join(srcDir, 'pages');
const maybeAppDirPath = path.join(process.cwd(), 'app');
const maybeSrcAppDirPath = path.join(srcDir, 'app');

let pagesLocation =
fs.existsSync(maybePagesDirPath) &&
Expand All @@ -291,23 +295,83 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
? ['src', 'pages']
: undefined;

if (!pagesLocation) {
pagesLocation = ['pages'];
const appLocation =
fs.existsSync(maybeAppDirPath) &&
fs.lstatSync(maybeAppDirPath).isDirectory()
? ['app']
: fs.existsSync(maybeSrcAppDirPath) &&
fs.lstatSync(maybeSrcAppDirPath).isDirectory()
? ['src', 'app']
: undefined;

if (!pagesLocation && !appLocation) {
pagesLocation =
fs.existsSync(srcDir) && fs.lstatSync(srcDir).isDirectory()
? ['src', 'pages']
: ['pages'];
fs.mkdirSync(path.join(process.cwd(), ...pagesLocation), {
recursive: true,
});
}

if (pagesLocation) {
if (appLocation) {
const examplePageContents = getSentryExamplePageContents({
selfHosted,
orgSlug: selectedProject.organization.slug,
projectId: selectedProject.id,
url: sentryUrl,
useClient: true,
});

await fs.promises.writeFile(
path.join(
process.cwd(),
...appLocation,
'sentry-example-page',
'page.jsx',
),
examplePageContents,
{ encoding: 'utf8', flag: 'w' },
);

clack.log.success(
`Created ${chalk.bold(
path.join(...appLocation, 'sentry-example-page', 'page.jsx'),
)}.`,
);

fs.mkdirSync(path.join(process.cwd(), ...appLocation, 'api'), {
recursive: true,
});

await fs.promises.writeFile(
path.join(
process.cwd(),
...appLocation,
'api',
'sentry-example-api',
'route.js',
),
getSentryExampleAppDirApiRoute(),
{ encoding: 'utf8', flag: 'w' },
);

clack.log.success(
`Created ${chalk.bold(
path.join(...appLocation, 'api', 'sentry-example-api', 'route.js'),
)}.`,
);
} else if (pagesLocation) {
const examplePageContents = getSentryExamplePageContents({
selfHosted,
orgSlug: selectedProject.organization.slug,
projectId: selectedProject.id,
url: sentryUrl,
useClient: false,
});

await fs.promises.writeFile(
path.join(process.cwd(), ...pagesLocation, 'sentry-example-page.js'),
path.join(process.cwd(), ...pagesLocation, 'sentry-example-page.jsx'),
examplePageContents,
{ encoding: 'utf8', flag: 'w' },
);
Expand Down
18 changes: 16 additions & 2 deletions src/nextjs/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,18 @@ export function getSentryExamplePageContents(options: {
url: string;
orgSlug: string;
projectId: string;
useClient: boolean;
}): string {
const issuesPageLink = options.selfHosted
? `${options.url}organizations/${options.orgSlug}/issues/?project=${options.projectId}`
: `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;

return `import Head from "next/head";
return `${
options.useClient ? '"use client";\n\n' : ''
}import Head from "next/head";
import * as Sentry from "@sentry/nextjs";
export default function Home() {
export default function Page() {
return (
<div>
<Head>
Expand Down Expand Up @@ -250,3 +253,14 @@ export default function handler(_req, res) {
}
`;
}

export function getSentryExampleAppDirApiRoute() {
return `import { NextResponse } from "next/server";
// A faulty API route to test Sentry's error monitoring
export function GET() {
throw new Error("Sentry Example API Route Error");
return NextResponse.json({ data: "Testing Sentry Error..." });
}
`;
}

0 comments on commit c359a96

Please sign in to comment.