Skip to content

Commit

Permalink
feat(nextjs): Add instructions on how to add a global-error page to…
Browse files Browse the repository at this point in the history
… Next.js App Router
  • Loading branch information
lforst committed Nov 29, 2023
1 parent 109f599 commit 4140711
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/nextjs/nextjs-wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import {
import { SentryProjectData, WizardOptions } from '../utils/types';
import {
getFullUnderscoreErrorCopyPasteSnippet,
getGlobalErrorCopyPasteSnippet,
getNextjsConfigCjsAppendix,
getNextjsConfigCjsTemplate,
getNextjsConfigEsmCopyPasteSnippet,
getNextjsSentryBuildOptionsTemplate,
getNextjsWebpackPluginOptionsTemplate,
getSentryConfigContents,
getSentryDefaultGlobalErrorPage,
getSentryDefaultUnderscoreErrorPage,
getSentryExampleApiRoute,
getSentryExampleAppDirApiRoute,
Expand Down Expand Up @@ -189,6 +191,84 @@ export async function runNextjsWizardWithTelemetry(
}
});

await traceStep('create-global-error-page', async () => {
const maybeAppDirPath = path.join(process.cwd(), 'pages');
const maybeSrcAppDirPath = path.join(process.cwd(), 'src', 'pages');

const appDirLocation =
fs.existsSync(maybeAppDirPath) &&
fs.lstatSync(maybeAppDirPath).isDirectory()
? ['app']
: fs.existsSync(maybeSrcAppDirPath) &&
fs.lstatSync(maybeSrcAppDirPath).isDirectory()
? ['src', 'app']
: undefined;

if (!appDirLocation) {
return;
}

const globalErrorPageFile = fs.existsSync(
path.join(process.cwd(), ...appDirLocation, 'global-error.tsx'),
)
? 'global-error.tsx'
: fs.existsSync(
path.join(process.cwd(), ...appDirLocation, 'global-error.ts'),
)
? 'global-error.ts'
: fs.existsSync(
path.join(process.cwd(), ...appDirLocation, 'global-error.jsx'),
)
? 'global-error.jsx'
: fs.existsSync(
path.join(process.cwd(), ...appDirLocation, 'global-error.js'),
)
? 'global-error.js'
: undefined;

if (!globalErrorPageFile) {
await fs.promises.writeFile(
path.join(process.cwd(), ...appDirLocation, 'global-error.jsx'),
getSentryDefaultGlobalErrorPage(),
{ encoding: 'utf8', flag: 'w' },
);

clack.log.success(
`Created ${chalk.bold(
path.join(...appDirLocation, 'global-error.jsx'),
)}.`,
);
} else {
clack.log.info(
`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.bold(
path.join(...appDirLocation, globalErrorPageFile),
)}:`,
);

// eslint-disable-next-line no-console
console.log(
getGlobalErrorCopyPasteSnippet(
globalErrorPageFile === 'global-error.ts' ||
globalErrorPageFile === 'global-error.tsx',
),
);

const shouldContinue = await abortIfCancelled(
clack.confirm({
message: `Did add the code to your ${chalk.bold(
path.join(...appDirLocation, globalErrorPageFile),
)} file as described above?`,
active: 'Yes',
inactive: 'No, get me out of here',
}),
);

if (!shouldContinue) {
await abort();
}
}
});

await traceStep('create-example-page', async () =>
createExamplePage(selfHosted, selectedProject, sentryUrl),
);
Expand Down
71 changes: 71 additions & 0 deletions src/nextjs/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,74 @@ YourCustomErrorComponent.getInitialProps = async (contextData${
};
`;
}

export function getSentryDefaultGlobalErrorPage() {
return `"use client";
import * as Sentry from "@sentry/nextjs";
import Error from "next/error";
import { useEffect } from "react";
export default function GlobalError({ error }) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<Error />
</body>
</html>
);
}
`;
}

export function getGlobalErrorCopyPasteSnippet(isTs: boolean) {
if (isTs) {
return `"use client";
${chalk.green('import * as Sentry from "@sentry/nextjs";')}
${chalk.green('import Error from "next/error";')}
${chalk.green('import { useEffect } from "react";')}
export default function GlobalError(${chalk.green(
'{ error }: { error: Error }',
)}) {
${chalk.green(`useEffect(() => {
Sentry.captureException(error);
}, [error]);`)}
return (
<html>
<body>
{/* Your Error component here... */}
</body>
</html>
);
}
`;
} else {
return `"use client";
${chalk.green('import * as Sentry from "@sentry/nextjs";')}
${chalk.green('import Error from "next/error";')}
${chalk.green('import { useEffect } from "react";')}
export default function GlobalError(${chalk.green('{ error }')}) {
${chalk.green(`useEffect(() => {
Sentry.captureException(error);
}, [error]);`)}
return (
<html>
<body>
{/* Your Error component here... */}
</body>
</html>
);
}
`;
}
}

0 comments on commit 4140711

Please sign in to comment.