Description
Feature request
Currently there are a lot of users that create a custom server to do middleware
behavior, for example server-side parsing of request bodies, cookies etc. Currently Next.js provides no way of handling this without a custom server. Meaning it can't be done in serverless / other environments.
Describe the solution you'd like
Ideally users would define middleware as a top level export. Meaning that pages can define middleware requirements:
// PageContext being the same values as `getInitialProps`'s context
export async function middleware({req, res}: PageContext) {
// do something with `req` / `res`
}
function IndexPage() {
return <h1>Hello world</h1>
}
export default IndexPage
However this also introduces the complexity of having to code-split / tree shake away user imports that are server-only.
So for the initial implementation (and incrementally working towards the implementation above) I'd start with supporting middleware in pages_document.js
which is always server-side rendered so it makes sense to have it there.
One thing that was brought up is "why can't this just be done in getInitialProps of _document".
The reason that we need a new method is that the lifecycle of calling getInitialProps looks like this:
- pages/_app.js getInitialProps is called,
- pages/_app.js getInitialProps calls the page's getInitialProps
- pages/_document.js getInitialProps is called
- pages/_document.js getInitialProps calls
renderPage
renderPage
calls React'srenderToString
and returns the html, head tags and styles.renderToStaticMarkup
is called to render the _document shell- request is ended using send-html.ts, which adds etag etc.
Generally when using middleware it has to be called before getInitialProps
because you could be parsing something needed in getInitialProps
So the middleware has to be called earlier.
Meaning the lifecycle would look like:
- pages/_document.js middleware is called
- pages/_app.js getInitialProps is called,
- pages/_app.js getInitialProps calls the page's getInitialProps
- pages/_document.js getInitialProps is called
- pages/_document.js getInitialProps calls
renderPage
renderPage
calls React'srenderToString
and returns the html, head tags and styles.renderToStaticMarkup
is called to render the _document shell- request is ended using send-html.ts, which adds etag etc.
So for the initial implementation we'd want something like:
// pages/_document.js
// PageContext being the same values as `getInitialProps`'s context
export async function middleware({req, res}: PageContext) {
// do something with `req` / `res`
}
// rest of _document.js