Example update: with-sentry-simple (#8684)
* Update to capture server exceptions and more - Adds test cases for several server and client-side exceptions - Allows capturing more server-side exceptions by overriding _error.js and using Sentry.captureException() within - Use @sentry/node on the server - Rely on Next.js's React Error Boundary instead of creating our own in _app.js * Update test notes Found some differences while testing in production * Remove accidental mount throw on test 8 * Add note about server-side source maps * Linting fixes
This commit is contained in:
parent
aa98323ed0
commit
dc28e5b706
19 changed files with 445 additions and 94 deletions
|
@ -49,11 +49,19 @@ now
|
|||
|
||||
This is a simple example showing how to use [Sentry](https://sentry.io) to catch & report errors on both client + server side.
|
||||
|
||||
- `_document.js` is _server-side only_ and is used to change the initial server-side rendered document markup. We listen at the node process level to capture exceptions.
|
||||
- `_app.js` is client-side only and is used to initialize pages. We use the `componentDidCatch` lifecycle method to catch uncaught exceptions.
|
||||
- `_app.js` renders on both the server and client. It initializes Sentry to catch any unhandled exceptions
|
||||
- `_error.js` is rendered by Next.js while handling certain types of exceptions for you. It is overriden so those exceptions can be passed along to Sentry
|
||||
- `next.config.js` enables source maps in production for Sentry and swaps out `@sentry/node` for `@sentry/browser` when building the client bundle
|
||||
|
||||
**Note**: Source maps will not be sent to Sentry when running locally. It's also possible you will see duplicate errors sent when testing
|
||||
locally due to hot reloading. For a more accurate simulation, please deploy to Now.
|
||||
**Note**: Source maps will not be sent to Sentry when running locally (because Sentry cannot access your `localhost`). To accurately test client-side source maps, please deploy to Now.
|
||||
|
||||
**Note**: Server-side source maps will not work unless you [manually upload them to Sentry](https://docs.sentry.io/platforms/node/sourcemaps/#making-source-maps-available-to-sentry).
|
||||
|
||||
**Note**: Error handling [works differently in production](https://nextjs.org/docs#custom-error-handling). Some exceptions will not be sent to Sentry in development mode (i.e. `npm run dev`).
|
||||
|
||||
**Note**: The build output will contain warning about unhandled Promise rejections. This caused by the test pages, and is expected.
|
||||
|
||||
**Note**: The version of `@zeit/next-source-maps` (`0.0.4-canary.1`) is important and must be specified since it is not yet the default. Otherwise [source maps will not be generated for the server](https://github.com/zeit/next-plugins/issues/377).
|
||||
|
||||
### Configuration
|
||||
|
||||
|
@ -67,4 +75,29 @@ Sentry.init({
|
|||
})
|
||||
```
|
||||
|
||||
_Note: Committing environment variables is not secure and is done here only for demonstration purposes. See the [`with-dotenv`](../with-dotenv) or [`with-now-env`](../with-now-env) for examples of how to set environment variables safely._
|
||||
### Disabling Sentry during development
|
||||
|
||||
An easy way to disable Sentry while developing is to set its `enabled` flag based off of the `NODE_ENV` environment variable, which is [properly configured by the `next` subcommands](https://nextjs.org/docs#production-deployment).
|
||||
|
||||
```js
|
||||
Sentry.init({
|
||||
dsn: 'PUT_YOUR_SENTRY_DSN_HERE',
|
||||
enabled: process.env.NODE_ENV === 'production'
|
||||
})
|
||||
```
|
||||
|
||||
### Hosting source maps vs. uploading them to Sentry
|
||||
|
||||
This example shows how to generate your own source maps, which are hosted alongside your JavaScript bundles in production. But that has the potential for innaccurate results in Sentry.
|
||||
|
||||
Sentry will attempt to [fetch the source map](https://docs.sentry.io/platforms/javascript/sourcemaps/#hosting--uploading) when it is processing an exception, as long as the "Enable JavaScript source fetching" setting is turned on for your Sentry project.
|
||||
|
||||
However, there are some disadvantages with this approach. Sentry has written a blog post about them here: https://blog.sentry.io/2018/07/17/source-code-fetching
|
||||
|
||||
If you decide that uploading source maps to Sentry would be better, one approach is to define a custom `now-build` script in your `package.json`. Zeit Now's `@now/next` builder will [call this script](https://github.com/zeit/now/blob/canary/packages/now-next/src/index.ts#L270) for you. You can define what to do after a build there:
|
||||
|
||||
```
|
||||
"now-build": "next build && node ./post-build.js"
|
||||
```
|
||||
|
||||
In `./post-build.js` you can `require('@sentry/cli')` and go through the process of creating a Sentry release and [uploading source maps](https://docs.sentry.io/cli/releases/#sentry-cli-sourcemaps), and optionally deleting the `.js.map` files so they are not made public.
|
||||
|
|
|
@ -1,7 +1,25 @@
|
|||
const withSourceMaps = require('@zeit/next-source-maps')()
|
||||
|
||||
module.exports = withSourceMaps({
|
||||
webpack (config, _options) {
|
||||
webpack: (config, options) => {
|
||||
// In `pages/_app.js`, Sentry is imported from @sentry/node. While
|
||||
// @sentry/browser will run in a Node.js environment, @sentry/node will use
|
||||
// Node.js-only APIs to catch even more unhandled exceptions.
|
||||
//
|
||||
// This works well when Next.js is SSRing your page on a server with
|
||||
// Node.js, but it is not what we want when your client-side bundle is being
|
||||
// executed by a browser.
|
||||
//
|
||||
// Luckily, Next.js will call this webpack function twice, once for the
|
||||
// server and once for the client. Read more:
|
||||
// https://nextjs.org/docs#customizing-webpack-config
|
||||
//
|
||||
// So ask Webpack to replace @sentry/node imports with @sentry/browser when
|
||||
// building the browser's bundle
|
||||
if (!options.isServer) {
|
||||
config.resolve.alias['@sentry/node'] = '@sentry/browser'
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
})
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "^5.1.0",
|
||||
"@sentry/node": "^5.6.2",
|
||||
"next": "latest",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
|
|
@ -1,28 +1,21 @@
|
|||
import React from 'react'
|
||||
import App from 'next/app'
|
||||
import * as Sentry from '@sentry/browser'
|
||||
import * as Sentry from '@sentry/node'
|
||||
|
||||
Sentry.init({
|
||||
dsn: 'ENTER_YOUR_SENTRY_DSN_HERE'
|
||||
// Replace with your project's Sentry DSN
|
||||
dsn: 'https://00000000000000000000000000000000@sentry.io/1111111'
|
||||
})
|
||||
|
||||
class MyApp extends App {
|
||||
componentDidCatch (error, errorInfo) {
|
||||
Sentry.withScope(scope => {
|
||||
Object.keys(errorInfo).forEach(key => {
|
||||
scope.setExtra(key, errorInfo[key])
|
||||
})
|
||||
|
||||
Sentry.captureException(error)
|
||||
})
|
||||
|
||||
super.componentDidCatch(error, errorInfo)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { Component, pageProps } = this.props
|
||||
|
||||
return <Component {...pageProps} />
|
||||
// Workaround for https://github.com/zeit/next.js/issues/8592
|
||||
const { err } = this.props
|
||||
const modifiedPageProps = { ...pageProps, err }
|
||||
|
||||
return <Component {...modifiedPageProps} />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import * as Sentry from '@sentry/browser'
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
Sentry.captureException(err)
|
||||
})
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
Sentry.captureException(err)
|
||||
})
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps (ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
64
examples/with-sentry-simple/pages/_error.js
Normal file
64
examples/with-sentry-simple/pages/_error.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import React from 'react'
|
||||
import Error from 'next/error'
|
||||
import * as Sentry from '@sentry/node'
|
||||
|
||||
const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
|
||||
if (!hasGetInitialPropsRun && err) {
|
||||
// getInitialProps is not called in case of
|
||||
// https://github.com/zeit/next.js/issues/8592. As a workaround, we pass
|
||||
// err via _app.js so it can be captured
|
||||
Sentry.captureException(err)
|
||||
}
|
||||
|
||||
return <Error statusCode={statusCode} />
|
||||
}
|
||||
|
||||
MyError.getInitialProps = async ({ res, err, asPath }) => {
|
||||
const errorInitialProps = await Error.getInitialProps({ res, err })
|
||||
|
||||
// Workaround for https://github.com/zeit/next.js/issues/8592, mark when
|
||||
// getInitialProps has run
|
||||
errorInitialProps.hasGetInitialPropsRun = true
|
||||
|
||||
if (res) {
|
||||
// Running on the server, the response object is available.
|
||||
//
|
||||
// Next.js will pass an err on the server if a page's `getInitialProps`
|
||||
// threw or returned a Promise that rejected
|
||||
|
||||
if (res.statusCode === 404) {
|
||||
// Opinionated: do not record an exception in Sentry for 404
|
||||
return { statusCode: 404 }
|
||||
}
|
||||
|
||||
if (err) {
|
||||
Sentry.captureException(err)
|
||||
|
||||
return errorInitialProps
|
||||
}
|
||||
} else {
|
||||
// Running on the client (browser).
|
||||
//
|
||||
// Next.js will provide an err if:
|
||||
//
|
||||
// - a page's `getInitialProps` threw or returned a Promise that rejected
|
||||
// - an exception was thrown somewhere in the React lifecycle (render,
|
||||
// componentDidMount, etc) that was caught by Next.js's React Error
|
||||
// Boundary. Read more about what types of exceptions are caught by Error
|
||||
// Boundaries: https://reactjs.org/docs/error-boundaries.html
|
||||
if (err) {
|
||||
Sentry.captureException(err)
|
||||
|
||||
return errorInitialProps
|
||||
}
|
||||
}
|
||||
|
||||
// If this point is reached, getInitialProps was called without any
|
||||
// information about what the error might be. This is unexpected and may
|
||||
// indicate a bug introduced in Next.js, so record it in Sentry
|
||||
Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`))
|
||||
|
||||
return errorInitialProps
|
||||
}
|
||||
|
||||
export default MyError
|
9
examples/with-sentry-simple/pages/client/test1.js
Normal file
9
examples/with-sentry-simple/pages/client/test1.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test1 = () => <h1>Client Test 1</h1>
|
||||
|
||||
Test1.getInitialProps = () => {
|
||||
throw new Error('Client Test 1')
|
||||
}
|
||||
|
||||
export default Test1
|
7
examples/with-sentry-simple/pages/client/test2.js
Normal file
7
examples/with-sentry-simple/pages/client/test2.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test2 = () => <h1>Client Test 2</h1>
|
||||
|
||||
Test2.getInitialProps = () => Promise.reject(new Error('Client Test 2'))
|
||||
|
||||
export default Test2
|
13
examples/with-sentry-simple/pages/client/test3.js
Normal file
13
examples/with-sentry-simple/pages/client/test3.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test3 = () => <h1>Client Test 3</h1>
|
||||
|
||||
Test3.getInitialProps = () => {
|
||||
const doAsyncWork = () => Promise.reject(new Error('Client Test 3'))
|
||||
|
||||
doAsyncWork()
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
export default Test3
|
8
examples/with-sentry-simple/pages/client/test4.js
Normal file
8
examples/with-sentry-simple/pages/client/test4.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
|
||||
const doAsyncWork = () => Promise.reject(new Error('Client Test 4'))
|
||||
doAsyncWork()
|
||||
|
||||
const Test4 = () => <h1>Client Test 4</h1>
|
||||
|
||||
export default Test4
|
19
examples/with-sentry-simple/pages/client/test5.js
Normal file
19
examples/with-sentry-simple/pages/client/test5.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React from 'react'
|
||||
|
||||
// This code will run just fine on the server in Node.js, but process will be
|
||||
// undefined in a browser. Note that `isProd = process.env.NODE_ENV` would have
|
||||
// worked because Webpack's DefinePlugin will replace it with a string at build
|
||||
// time: https://nextjs.org/docs#build-time-configuration
|
||||
const env = process.env
|
||||
const isProd = env.NODE_ENV === 'production'
|
||||
|
||||
const Test5 = () => (
|
||||
<React.Fragment>
|
||||
<h1>Client Test 5</h1>
|
||||
<p>
|
||||
isProd: {isProd}
|
||||
</p>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
||||
export default Test5
|
11
examples/with-sentry-simple/pages/client/test6.js
Normal file
11
examples/with-sentry-simple/pages/client/test6.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test6 = () => {
|
||||
React.useEffect(() => {
|
||||
throw new Error('Client Test 6')
|
||||
}, [])
|
||||
|
||||
return <h1>Client Test 6</h1>
|
||||
}
|
||||
|
||||
export default Test6
|
13
examples/with-sentry-simple/pages/client/test7.js
Normal file
13
examples/with-sentry-simple/pages/client/test7.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test7 = () => {
|
||||
React.useEffect(async () => {
|
||||
const doAsyncWork = () => Promise.reject(new Error('Client Test 7'))
|
||||
const result = await doAsyncWork()
|
||||
console.log(result)
|
||||
}, [])
|
||||
|
||||
return <h1>Client Test 7</h1>
|
||||
}
|
||||
|
||||
export default Test7
|
16
examples/with-sentry-simple/pages/client/test8.js
Normal file
16
examples/with-sentry-simple/pages/client/test8.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test8 = () => (
|
||||
<React.Fragment>
|
||||
<h1>Client Test 8</h1>
|
||||
<button
|
||||
onClick={() => {
|
||||
throw new Error('Client Test 8')
|
||||
}}
|
||||
>
|
||||
Click me to throw an Error
|
||||
</button>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
||||
export default Test8
|
|
@ -1,49 +1,183 @@
|
|||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
class Index extends React.Component {
|
||||
static getInitialProps ({ query }) {
|
||||
if (query.raiseError) {
|
||||
throw new Error('Error in getInitialProps')
|
||||
}
|
||||
}
|
||||
|
||||
state = {
|
||||
raiseErrorInRender: false,
|
||||
raiseErrorInUpdate: false
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this.state.raiseErrorInUpdate) {
|
||||
throw new Error('Error in componentDidUpdate')
|
||||
}
|
||||
}
|
||||
|
||||
raiseErrorInUpdate = () => this.setState({ raiseErrorInUpdate: '1' })
|
||||
raiseErrorInRender = () => this.setState({ raiseErrorInRender: '1' })
|
||||
|
||||
render () {
|
||||
if (this.state.raiseErrorInRender) {
|
||||
throw new Error('Error in render')
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Sentry Example 🚨</h2>
|
||||
const Index = () => (
|
||||
<div style={{ maxWidth: 700, margin: '0 auto' }}>
|
||||
<h2>Sentry Simple Example 🚨</h2>
|
||||
<p>
|
||||
This example demonstrates how to record unhandled exceptions in your code
|
||||
with Sentry. There are several test pages below that result in various
|
||||
kinds of unhandled exceptions.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Important:</strong> exceptions in development mode take a
|
||||
different path than in production. These tests should be run on a
|
||||
production build (i.e. 'next build').
|
||||
{' '}
|
||||
<a href='https://nextjs.org/docs#custom-error-handling'>Read more</a>
|
||||
</p>
|
||||
<ul>
|
||||
<li>Server exceptions</li>
|
||||
<ul>
|
||||
<li>
|
||||
<a href='#' onClick={this.raiseErrorInRender}>
|
||||
Raise the error in render
|
||||
getInitialProps throws an Error. This should cause _error.js to
|
||||
render and record Error('Client Test 1') in Sentry.
|
||||
{' '}
|
||||
<a href='/server/test1' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='#' onClick={this.raiseErrorInUpdate}>
|
||||
Raise the error in componentDidUpdate
|
||||
getInitialProps returns a Promise that rejects. This should cause
|
||||
_error.js to render and record Error('Server Test 2') in Sentry.
|
||||
{' '}
|
||||
<a href='/server/test2' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
getInitialProps calls a Promise that rejects, but does not handle the
|
||||
rejection or await its result (returning synchronously). Sentry should
|
||||
record Error('Server Test 3').
|
||||
{' '}
|
||||
<a href='/server/test3' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
There is a top-of-module Promise that rejects, but its result is not
|
||||
awaited. Sentry should record Error('Server Test 4'). Note this will
|
||||
also be recorded on the client side, once the page is hydrated.
|
||||
{' '}
|
||||
<a href='/server/test4' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<li>Client exceptions</li>
|
||||
<ul>
|
||||
<li>
|
||||
getInitialProps throws an Error. This should cause _error.js to render
|
||||
and record Error('Client Test 1') in Sentry. Note Sentry will double
|
||||
count this exception. Once from an unhandledrejection and again in
|
||||
_error.js. Could be a bug in Next.js or Sentry, requires more
|
||||
debugging.
|
||||
{' '}
|
||||
<Link href='/client/test1'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
getInitialProps returns a Promise that rejects. This should cause
|
||||
_error.js to render and record Error('Client Test 2') in Sentry. As
|
||||
above, Sentry will double count this exception.
|
||||
{' '}
|
||||
<Link href='/client/test2'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
getInitialProps calls a Promise that rejects, but does not handle the
|
||||
rejection or await its result (returning synchronously). Sentry should
|
||||
record Error('Client Test 3').
|
||||
{' '}
|
||||
<Link href='/client/test3'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
There is a top-of-module Promise that rejects, but its result is not
|
||||
awaited. Sentry should record Error('Client Test 4').
|
||||
{' '}
|
||||
<Link href='/client/test4'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
{' '}
|
||||
or
|
||||
{' '}
|
||||
<a href='/client/test4' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
There is a top-of-module exception. _error.js should render and record
|
||||
ReferenceError('process is not defined') in Sentry.
|
||||
{' '}
|
||||
<Link href='/client/test5'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
{' '}
|
||||
or
|
||||
{' '}
|
||||
<a href='/client/test5' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
There is an exception during React lifecycle that is caught by
|
||||
Next.js's React Error Boundary. In this case, when the component
|
||||
mounts. This should cause _error.js to render and record
|
||||
Error('Client Test 6') in Sentry.
|
||||
{' '}
|
||||
<Link href='/client/test6'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
{' '}
|
||||
or
|
||||
{' '}
|
||||
<a href='/client/test6' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
There is an unhandled Promise rejection during React lifecycle. In
|
||||
this case, when the component mounts. Sentry should record
|
||||
Error('Client Test 7').
|
||||
{' '}
|
||||
<Link href='/client/test7'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
{' '}
|
||||
or
|
||||
{' '}
|
||||
<a href='/client/test7' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
An Error is thrown from an event handler. Sentry should record
|
||||
Error('Client Test 8').
|
||||
{' '}
|
||||
<Link href='/client/test8'>
|
||||
<a>
|
||||
Perform client side navigation
|
||||
</a>
|
||||
</Link>
|
||||
{' '}
|
||||
or
|
||||
{' '}
|
||||
<a href='/client/test8' target='_blank'>
|
||||
Open in a new tab
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Index
|
||||
|
|
9
examples/with-sentry-simple/pages/server/test1.js
Normal file
9
examples/with-sentry-simple/pages/server/test1.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test1 = () => <h1>Server Test 1</h1>
|
||||
|
||||
Test1.getInitialProps = () => {
|
||||
throw new Error('Server Test 1')
|
||||
}
|
||||
|
||||
export default Test1
|
7
examples/with-sentry-simple/pages/server/test2.js
Normal file
7
examples/with-sentry-simple/pages/server/test2.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test2 = () => <h1>Server Test 2</h1>
|
||||
|
||||
Test2.getInitialProps = () => Promise.reject(new Error('Server Test 2'))
|
||||
|
||||
export default Test2
|
13
examples/with-sentry-simple/pages/server/test3.js
Normal file
13
examples/with-sentry-simple/pages/server/test3.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react'
|
||||
|
||||
const Test3 = () => <h1>Server Test 3</h1>
|
||||
|
||||
Test3.getInitialProps = () => {
|
||||
const doAsyncWork = () => Promise.reject(new Error('Server Test 3'))
|
||||
|
||||
doAsyncWork()
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
export default Test3
|
14
examples/with-sentry-simple/pages/server/test4.js
Normal file
14
examples/with-sentry-simple/pages/server/test4.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from 'react'
|
||||
|
||||
const doAsyncWork = () => Promise.reject(new Error('Server Test 4'))
|
||||
doAsyncWork()
|
||||
|
||||
const Test4 = () => <h1>Server Test 4</h1>
|
||||
|
||||
// Define getInitialProps so that the page will be rendered on the server
|
||||
// instead of statically
|
||||
Test4.getInitialProps = () => {
|
||||
return {}
|
||||
}
|
||||
|
||||
export default Test4
|
Loading…
Reference in a new issue