To override the default document rendering, define _document.js.
This will allow you to use any css modules and head manage components.
For example, you'd be able to replace next/css with khan/aphrodite like the following:
import React from 'react'
import Head from 'next/head'
import { StyleSheetServer } from 'aphrodite'
export default class Document extends React.Component {
static getInitialProps ({ renderPageToString }) {
const { html, css } = StyleSheetServer.renderStatic(() => {
return renderPageToString()
})
const head = Head.rewind()
return { html, css, head }
}
render () {
return <html>
<head>
{this.props.head}
<style dangerouslySetInnerHTML={{ __html: this.props.css.content }} />
</head>
<body>
<div id='__next' dangerouslySetInnerHTML={{ __html: this.props.html }} />
<script src="/next.js" />
<script src="/static/aphrodite.js" />
<script dangerouslySetInnerHTML={{ __html: `
StyleSheet.rehydrate(${JSON.stringify(this.props.css.renderedClassNames)})
`}}>
</body>
</html>
}
}
Related: https://github.com/zeit/next.js/issues/247
cc @rauchg
This will also allow to flawlessly include external dependencies required in #221. However, it may introduce some issues with Next.js upgrades as those who chose to override the Document will need to keep track of the changes done in the Next.js built-in Document implementation.
@frol yeah, I did think about the upgrade scenario. But at the end of the day, this is advanced behavior. Most people are not going to need to extend the core document
@nkzawa also, to clarify, I was thinking pages/_document.js
Another reason to have a custom core document is if we want to add a className to the body tag, which is currently not possible.
A lot of bootstrap templates have classnames on this tag.
Totally! I second @jonaswindey point here. Even ignoring 3rd party CSS libs like bootstrap, avoiding the "white flash on load" when you have a dominant background color is important.
Default Server Mode
General
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| buildDuration | 16.7s | 17.1s | โ ๏ธ +356ms |
| nodeModulesSize | 48.2 MB | 48.2 MB | โ |
Client Bundles (main, webpack, commons)
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| main-HASH.js | 18.1 kB | 18.1 kB | โ |
| main-HASH.js gzip | 6.6 kB | 6.6 kB | โ |
| webpack-HASH.js | 1.53 kB | 1.53 kB | โ |
| webpack-HASH.js gzip | 746 B | 746 B | โ |
| 4952ddcd88e7..2b8407376.js | 21.9 kB | 21.9 kB | โ |
| 4952ddcd88e7..7376.js gzip | 7.81 kB | 7.81 kB | โ |
| de003c3a9d30..2ca0edb75.js | 43.2 kB | 43.2 kB | โ |
| de003c3a9d30..db75.js gzip | 15.5 kB | 15.5 kB | โ |
| framework.5b..dbaff70d3.js | 125 kB | 125 kB | โ |
| framework.5b..70d3.js gzip | 39.4 kB | 39.4 kB | โ |
| Overall change | 210 kB | 210 kB | โ |
Client Bundles (main, webpack, commons) Modern
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| main-HASH.module.js | 16.4 kB | 16.4 kB | โ |
| main-HASH.module.js gzip | 6.35 kB | 6.35 kB | โ |
| webpack-HASH.module.js | 1.53 kB | 1.53 kB | โ |
| webpack-HASH..dule.js gzip | 746 B | 746 B | โ |
| de003c3a9d30..c0.module.js | 45.6 kB | 45.6 kB | โ |
| de003c3a9d30..dule.js gzip | 16.5 kB | 16.5 kB | โ |
| framework.5b..d3.module.js | 125 kB | 125 kB | โ |
| framework.5b..dule.js gzip | 39.4 kB | 39.4 kB | โ |
| Overall change | 189 kB | 189 kB | โ |
Client Pages
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _app.js | 1.81 kB | 1.81 kB | โ |
| _app.js gzip | 873 B | 873 B | โ |
| _error.js | 12 kB | 12 kB | โ |
| _error.js gzip | 4.73 kB | 4.73 kB | โ |
| hooks.js | 12.7 kB | 12.7 kB | โ |
| hooks.js gzip | 4.79 kB | 4.79 kB | โ |
| index.js | 318 B | 318 B | โ |
| index.js gzip | 222 B | 222 B | โ |
| link.js | 8.14 kB | 8.14 kB | โ |
| link.js gzip | 3.5 kB | 3.5 kB | โ |
| routerDirect.js | 408 B | 408 B | โ |
| routerDirect.js gzip | 281 B | 281 B | โ |
| withRouter.js | 419 B | 419 B | โ |
| withRouter.js gzip | 280 B | 280 B | โ |
| Overall change | 35.8 kB | 35.8 kB | โ |
Client Pages Modern
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _app.module.js | 1.7 kB | 1.7 kB | โ |
| _app.module.js gzip | 832 B | 832 B | โ |
| _error.module.js | 23.3 kB | 23.3 kB | โ |
| _error.module.js gzip | 8.59 kB | 8.59 kB | โ |
| hooks.module.js | 1.52 kB | 1.52 kB | โ |
| hooks.module.js gzip | 793 B | 793 B | โ |
| index.module.js | 294 B | 294 B | โ |
| index.module.js gzip | 223 B | 223 B | โ |
| link.module.js | 8.53 kB | 8.53 kB | โ |
| link.module.js gzip | 3.68 kB | 3.68 kB | โ |
| routerDirect.module.js | 394 B | 394 B | โ |
| routerDirect..dule.js gzip | 281 B | 281 B | โ |
| withRouter.module.js | 404 B | 404 B | โ |
| withRouter.m..dule.js gzip | 278 B | 278 B | โ |
| Overall change | 36.1 kB | 36.1 kB | โ |
Client Build Manifests
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _buildManifest.js | 81 B | 81 B | โ |
| _buildManifest.js gzip | 61 B | 61 B | โ |
| _buildManifest.module.js | 81 B | 81 B | โ |
| _buildManife..dule.js gzip | 61 B | 61 B | โ |
| Overall change | 162 B | 162 B | โ |
Rendered Page Sizes
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| index.html | 3.62 kB | 3.62 kB | โ |
| index.html gzip | 946 B | 946 B | โ |
| link.html | 3.66 kB | 3.66 kB | โ |
| link.html gzip | 954 B | 954 B | โ |
| withRouter.html | 3.67 kB | 3.67 kB | โ |
| withRouter.html gzip | 941 B | 941 B | โ |
| Overall change | 10.9 kB | 10.9 kB | โ |
General
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| buildDuration | 17s | 16.8s | -253ms |
| nodeModulesSize | 48.2 MB | 48.2 MB | โ |
Client Bundles (main, webpack, commons)
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| main-HASH.js | 18.1 kB | 18.1 kB | โ |
| main-HASH.js gzip | 6.6 kB | 6.6 kB | โ |
| webpack-HASH.js | 1.53 kB | 1.53 kB | โ |
| webpack-HASH.js gzip | 746 B | 746 B | โ |
| 4952ddcd88e7..2b8407376.js | 21.9 kB | 21.9 kB | โ |
| 4952ddcd88e7..7376.js gzip | 7.81 kB | 7.81 kB | โ |
| de003c3a9d30..2ca0edb75.js | 43.2 kB | 43.2 kB | โ |
| de003c3a9d30..db75.js gzip | 15.5 kB | 15.5 kB | โ |
| framework.5b..dbaff70d3.js | 125 kB | 125 kB | โ |
| framework.5b..70d3.js gzip | 39.4 kB | 39.4 kB | โ |
| Overall change | 210 kB | 210 kB | โ |
Client Bundles (main, webpack, commons) Modern
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| main-HASH.module.js | 16.4 kB | 16.4 kB | โ |
| main-HASH.module.js gzip | 6.35 kB | 6.35 kB | โ |
| webpack-HASH.module.js | 1.53 kB | 1.53 kB | โ |
| webpack-HASH..dule.js gzip | 746 B | 746 B | โ |
| de003c3a9d30..c0.module.js | 45.6 kB | 45.6 kB | โ |
| de003c3a9d30..dule.js gzip | 16.5 kB | 16.5 kB | โ |
| framework.5b..d3.module.js | 125 kB | 125 kB | โ |
| framework.5b..dule.js gzip | 39.4 kB | 39.4 kB | โ |
| Overall change | 189 kB | 189 kB | โ |
Client Pages
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _app.js | 1.81 kB | 1.81 kB | โ |
| _app.js gzip | 873 B | 873 B | โ |
| _error.js | 12 kB | 12 kB | โ |
| _error.js gzip | 4.73 kB | 4.73 kB | โ |
| hooks.js | 12.7 kB | 12.7 kB | โ |
| hooks.js gzip | 4.79 kB | 4.79 kB | โ |
| index.js | 318 B | 318 B | โ |
| index.js gzip | 222 B | 222 B | โ |
| link.js | 8.14 kB | 8.14 kB | โ |
| link.js gzip | 3.5 kB | 3.5 kB | โ |
| routerDirect.js | 408 B | 408 B | โ |
| routerDirect.js gzip | 281 B | 281 B | โ |
| withRouter.js | 419 B | 419 B | โ |
| withRouter.js gzip | 280 B | 280 B | โ |
| Overall change | 35.8 kB | 35.8 kB | โ |
Client Pages Modern
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _app.module.js | 1.7 kB | 1.7 kB | โ |
| _app.module.js gzip | 832 B | 832 B | โ |
| _error.module.js | 23.3 kB | 23.3 kB | โ |
| _error.module.js gzip | 8.59 kB | 8.59 kB | โ |
| hooks.module.js | 1.52 kB | 1.52 kB | โ |
| hooks.module.js gzip | 793 B | 793 B | โ |
| index.module.js | 294 B | 294 B | โ |
| index.module.js gzip | 223 B | 223 B | โ |
| link.module.js | 8.53 kB | 8.53 kB | โ |
| link.module.js gzip | 3.68 kB | 3.68 kB | โ |
| routerDirect.module.js | 394 B | 394 B | โ |
| routerDirect..dule.js gzip | 281 B | 281 B | โ |
| withRouter.module.js | 404 B | 404 B | โ |
| withRouter.m..dule.js gzip | 278 B | 278 B | โ |
| Overall change | 36.1 kB | 36.1 kB | โ |
Client Build Manifests
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _buildManifest.js | 81 B | 81 B | โ |
| _buildManifest.js gzip | 61 B | 61 B | โ |
| _buildManifest.module.js | 81 B | 81 B | โ |
| _buildManife..dule.js gzip | 61 B | 61 B | โ |
| Overall change | 162 B | 162 B | โ |
Serverless bundles
| | zeit/next.js canary | zeit/next.js canary | Change |
| - | - | - | - |
| _error.js | 253 kB | 253 kB | โ |
| _error.js gzip | 67.9 kB | 67.9 kB | โ |
| hooks.html | 3.75 kB | 3.75 kB | โ |
| hooks.html gzip | 979 B | 979 B | โ |
| index.js | 254 kB | 254 kB | โ |
| index.js gzip | 68.2 kB | 68.2 kB | โ |
| link.js | 261 kB | 261 kB | โ |
| link.js gzip | 70.2 kB | 70.2 kB | โ |
| routerDirect.js | 255 kB | 255 kB | โ |
| routerDirect.js gzip | 68.3 kB | 68.3 kB | โ |
| withRouter.js | 255 kB | 255 kB | โ |
| withRouter.js gzip | 68.3 kB | 68.3 kB | โ |
| Overall change | 1.28 MB | 1.28 MB | โ |
Commit: 0bcd1fc39bb07f67b94238a0e867e9c3fe73a163
Most helpful comment
Another reason to have a custom core document is if we want to add a className to the body tag, which is currently not possible.
A lot of bootstrap templates have classnames on this tag.