vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.78k stars 26.95k forks source link

Custom Document component #251

Closed nkzawa closed 7 years ago

nkzawa commented 7 years ago

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

frol commented 7 years ago

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.

rauchg commented 7 years ago

@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

rauchg commented 7 years ago

@nkzawa also, to clarify, I was thinking pages/_document.js

jonaswindey commented 7 years ago

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.

philcockfield commented 7 years ago

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.

ijjk commented 5 years ago

Stats from current PR

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 | ✓ |

Serverless Mode
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