Skip to content

Commit

Permalink
feat: extended nextjs config and sentry
Browse files Browse the repository at this point in the history
  • Loading branch information
lotyp committed Dec 29, 2022
1 parent f261b56 commit f0be583
Show file tree
Hide file tree
Showing 8 changed files with 374 additions and 42 deletions.
20 changes: 18 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,21 @@ PROJECT_SERVICES_NAMESPACE=wod
COMPOSE_PROJECT_NAME=nextjs-${APP_NAME}

# Sentry Settings
NEXT_SENTRY_DSN=
NEXT_SENTRY_TRACING=
NEXT_DISABLE_SENTRY=true
NEXT_SENTRY_DEBUG=false
NEXT_SENTRY_TRACING=false

# Attempts a dry run (useful for dev environments).
# Defaults to false, but may be automatically set to true in development environments
# by some framework integrations (Next.JS, possibly others).
NEXT_SENTRY_UPLOAD_DRY_RUN=true

SENTRY_DSN=https://[email protected]/0
SENTRY_ORG=wayofdev
SENTRY_PROJECT=next-starter-tpl
SENTRY_AUTH_TOKEN=
SENTRY_LOG_LEVEL=debug

# Development variables
NEXT_IGNORE_ESLINT=false
NEXT_IGNORE_TYPE_CHECK=false
38 changes: 0 additions & 38 deletions apps/web/next.config.js

This file was deleted.

214 changes: 214 additions & 0 deletions apps/web/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
// This file sets a custom webpack configuration to use your Next.js app
// with Sentry.
// @link https://nextjs.org/docs/api-reference/next.config.js/introduction
// @link https://docs.sentry.io/platforms/javascript/guides/nextjs/

import { readFileSync } from 'node:fs'
import withBundleAnalyzer from '@next/bundle-analyzer'
import { withSentryConfig } from '@sentry/nextjs' // https://docs.sentry.io/platforms/javascript/guides/nextjs/
import pc from 'picocolors'

/**
* Once supported replace by node / eslint / ts and out of experimental, replace by
* `import packageJson from './package.json' assert { type: 'json' };`
* @type {import('type-fest').PackageJson}
*/
const packageJson = JSON.parse(
readFileSync(new URL('./package.json', import.meta.url)).toString('utf-8')
)

const trueEnv = ['true', '1', 'yes']
const isProd = process.env.NODE_ENV === 'production'
const isCI = trueEnv.includes(process.env?.CI ?? 'false')

const NEXT_IGNORE_TYPE_CHECK = trueEnv.includes(process.env?.NEXT_IGNORE_TYPE_CHECK ?? 'false')
const NEXT_IGNORE_ESLINT = trueEnv.includes(process.env?.NEXT_IGNORE_ESLINT ?? 'false')

const NEXT_SENTRY_UPLOAD_DRY_RUN = trueEnv.includes(
process.env?.NEXT_SENTRY_UPLOAD_DRY_RUN ?? 'false'
)
const NEXT_DISABLE_SENTRY = trueEnv.includes(process.env?.NEXT_DISABLE_SENTRY ?? 'false')
const NEXT_SENTRY_DEBUG = trueEnv.includes(process.env?.NEXT_SENTRY_DEBUG ?? 'false')
const NEXT_SENTRY_TRACING = trueEnv.includes(process.env?.NEXT_SENTRY_TRACING ?? 'false')

/**
* A way to allow CI optimization when the build done there is not used
* to deliver an image or deploy the files.
* @link https://nextjs.org/docs/advanced-features/source-maps
*/
const disableSourceMaps = trueEnv.includes(process.env?.NEXT_DISABLE_SOURCEMAPS ?? 'false')

if (disableSourceMaps) {
console.log(
`${pc.green(
'notice'
)}- Sourcemaps generation have been disabled through NEXT_DISABLE_SOURCEMAPS`
)
}

/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
reactStrictMode: true,
productionBrowserSourceMaps: !disableSourceMaps,
optimizeFonts: true,

// @link https://beta.nextjs.org/docs/api-reference/next.config.js#transpilepackages
transpilePackages: ['@wayofdev/ui'],

onDemandEntries: {
// period (in ms) where the server will keep pages in the buffer
maxInactiveAge: (isCI ? 3600 : 25) * 1000,
},

// @link https://nextjs.org/docs/advanced-features/compiler#minification
// Sometimes buggy so enable/disable when debugging.
swcMinify: true,

compiler: {
// emotion: true,
},

// Standalone build
// @link https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files-experimental
output: 'standalone',

// Optional build-time configuration options
sentry: {
// See the sections below for information on the following options:
// 'Configure Source Maps':
// - disableServerWebpackPlugin
// - disableClientWebpackPlugin
// - hideSourceMaps
// - widenClientFileUpload
// 'Configure Legacy Browser Support':
// - transpileClientSDK
// 'Configure Serverside Auto-instrumentation':
// - autoInstrumentServerFunctions
// - excludeServerRoutes
// 'Configure Tunneling to avoid Ad-Blockers':
// - tunnelRoute
//
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
// for client-side builds. (This will be the default starting in
// `@sentry/nextjs` version 8.0.0.) See
// https://webpack.js.org/configuration/devtool/ and
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
// for more information.
hideSourceMaps: true,
},

typescript: {
ignoreBuildErrors: NEXT_IGNORE_TYPE_CHECK,
},

eslint: {
ignoreDuringBuilds: NEXT_IGNORE_ESLINT,
// dirs: [`${__dirname}/src`],
},

// @link https://nextjs.org/docs/api-reference/next.config.js/rewrites
async rewrites() {
return [
/*
{
source: `/about-us`,
destination: '/about',
},
*/
]
},

webpack: (config, { webpack, isServer }) => {
if (!isServer) {
// Fixes npm packages that depend on `fs` module
// @link https://github.com/vercel/next.js/issues/36514#issuecomment-1112074589
config.resolve.fallback = { ...config.resolve.fallback, fs: false }
}

// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/tree-shaking/
config.plugins.push(
new webpack.DefinePlugin({
__SENTRY_DEBUG__: NEXT_SENTRY_DEBUG,
__SENTRY_TRACING__: NEXT_SENTRY_TRACING,
})
)

config.module.rules.push({
test: /\.svg$/,
issuer: /\.(js|ts)x?$/,
use: [
{
loader: '@svgr/webpack',
// https://react-svgr.com/docs/webpack/#passing-options
options: {
svgo: true,
// @link https://github.com/svg/svgo#configuration
svgoConfig: {
multipass: false,
datauri: 'base64',
js2svg: {
indent: 2,
pretty: false,
},
},
},
},
],
})

return config
},
env: {
APP_NAME: process.env.APP_NAME ?? 'APP_NAME-ENV-not-found',
APP_VERSION: packageJson.version ?? 'not-in-package.json',
BUILD_TIME: new Date().toISOString(),
},
}

let config = nextConfig

if (!NEXT_DISABLE_SENTRY) {
config = withSentryConfig(config, {
// Additional config options for the Sentry Webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, org, project, authToken, configFile, stripPrefix,
// urlPrefix, include, ignore
// For all available options, see:
// @link https://github.com/getsentry/sentry-webpack-plugin#options.

// Attempts a dry run (useful for dev environments).
// Defaults to false, but may be automatically set to true in development environments
// by some framework integrations (Next.JS, possibly others).
dryRun: NEXT_SENTRY_UPLOAD_DRY_RUN,

// Suppresses all logs (useful for --json option). Defaults to false.
silent: isProd,

// release: '',
// url: '',
// org: '',
// project: '',
// authToken: '',
// configFile: '',
// stripPrefix: '',
// urlPrefix: '',
// include: '',
// ignore: '',
})
} else {
const { sentry, ...rest } = config
config = rest
}

if (process.env.ANALYZE === 'true') {
config = withBundleAnalyzer({
enabled: true,
})(config)
}

// Make sure adding Sentry options is the last code to run before exporting, to
// ensure that your source maps include changes from all other Webpack plugins
export default config
5 changes: 4 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"tailwindcss": "^3.2.4"
},
"devDependencies": {
"@next/bundle-analyzer": "13.1.1",
"@types/jest": "^29.2.4",
"jest": "^29.3.1",
"jest-config": "workspace:*",
Expand All @@ -38,6 +39,8 @@
"postcss-preset-env": "^7.8.3",
"postcss-reporter": "^7.0.5",
"browserslist": "^4.21.4",
"@sentry/nextjs": "^7.28.1"
"@sentry/nextjs": "^7.28.1",
"@sentry/react": "^7.28.1",
"picocolors": "1.0.0"
}
}
2 changes: 1 addition & 1 deletion apps/web/sentry.client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { init as sentryInit } from '@sentry/nextjs'

sentryInit({
dsn: process.env.NEXT_SENTRY_DSN,
dsn: process.env.SENTRY_DSN || process.env.NEXT_SENTRY_DSN,

// Adjust this value in production, or use tracesSampler for greater control
// @see https://develop.sentry.dev/sdk/performance/
Expand Down
38 changes: 38 additions & 0 deletions apps/web/src/pages/_error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* NOTE: This requires `@sentry/nextjs` version 7.3.0 or higher.
*
* This page is loaded by Nextjs:
* - on the server, when data-fetching methods throw or reject
* - on the client, when `getInitialProps` throws or rejects
* - on the client, when a React lifecycle method throws or rejects, and it's
* caught by the built-in Nextjs error boundary
*
* See:
* - https://nextjs.org/docs/basic-features/data-fetching/overview
* - https://nextjs.org/docs/api-reference/data-fetching/get-initial-props
* - https://reactjs.org/docs/error-boundaries.html
*/

import * as Sentry from '@sentry/nextjs'
import type { NextPage } from 'next'
import type { ErrorProps } from 'next/error'
import NextErrorComponent from 'next/error'

const CustomErrorComponent: NextPage<ErrorProps> = properties => {
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
// compensate for https://github.com/vercel/next.js/issues/8592
// Sentry.captureUnderscoreErrorException(props);

return <NextErrorComponent statusCode={properties.statusCode} />
}

CustomErrorComponent.getInitialProps = async contextData => {
// In case this is running in a serverless function, await this in order to give Sentry
// time to send the error before the lambda exits
await Sentry.captureUnderscoreErrorException(contextData)

// This will contain the status code of the response
return NextErrorComponent.getInitialProps(contextData)
}

export default CustomErrorComponent
8 changes: 8 additions & 0 deletions apps/web/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export default function Web() {
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Boop
</button>
<button
type="button"
onClick={() => {
throw new Error('Sentry Frontend Error')
}}
>
Throw error
</button>
</>
)
}
Loading

0 comments on commit f0be583

Please sign in to comment.