Next.js: Make server rendering API pluggable

Created on 3 Mar 2017  路  15Comments  路  Source: vercel/next.js

Ref https://github.com/zeit/next.js/issues/1209

With this we could easily allow to use alternative server renderes like Preact, Inferno, rapscallion.

feature request

Most helpful comment

@guidiego @renatorib Our idea is to allow it to customize on the custom document. Here's how we think about it.

import React from 'react'
import { renderToString } from 'react-dom/server'
import BaseDocument from 'next/document'
import flush from 'styled-jsx/server'

export class Document extends React.Component {
  static getInitialProps ({ pageComponent, getHead }) {
    // Likewise, you could use your own renderer here.
    const { html } = renderToString(pageComponent)
    const head = getHead()
    const styles = flush()
    return { html, styles }
  }

  return () {
    <BaseDocument {...this.props}/> 
  }
}

All 15 comments

Already have ideas of how the "plug" configuration will work?

@arunoda @renatorib Maybe a config on next.config.js

module.exports = {
     serverRender: () => {
        // YOUR CODE
     }
}

@guidiego @renatorib Our idea is to allow it to customize on the custom document. Here's how we think about it.

import React from 'react'
import { renderToString } from 'react-dom/server'
import BaseDocument from 'next/document'
import flush from 'styled-jsx/server'

export class Document extends React.Component {
  static getInitialProps ({ pageComponent, getHead }) {
    // Likewise, you could use your own renderer here.
    const { html } = renderToString(pageComponent)
    const head = getHead()
    const styles = flush()
    return { html, styles }
  }

  return () {
    <BaseDocument {...this.props}/> 
  }
}

@arunoda And what we need to implements exactly? Looking your code and the code from document I not seen to many things to change :thinking: I can misunderstanding something!

@guidiego That's a one way to do it. Exposing it's not that hard.
But the problem is we use React for the Document as well. So, we need to do something for that.

Preact and Inferno not give support to react components?

@arunoda I liked the approach. But I think @guidiego's suggest is a bit better. IMO

And We like to see the support for streaming requests as well.

So API needs to support that too.

So, the initial point is remove React deep inside document and let this generic for any kind of react-like lib? @arunoda

Yep. That's the idea.
We also want to support streaming as well.

Let's talk about some possibilities :) To create a Generic Component (compatible with all react-like libs), we need to see if all of them give to us the same API. I believe the React and Preact are the same, but Inferno have Component outside from they core.

A simple approach is using Factory Pattern to create Constructor Functions with LibInstance (like React, Preact, Inferno) as a param. (another alternative is configuring in next.config to export this in global). This will generate something like:

export const NextDocumentConstructor = (libInstance, props) => (
  return class Document extends libInstance.Component {
    static getInitialProps ({ renderPage }) {
      const {html, head} = renderPage()
      const styles = flush()
      return { html, head, styles }
    }

    static childContextTypes = {
      _documentProps: PropTypes.any
    }

    getChildContext () {
      return { _documentProps: this.props }
    }

    render () {
      return <html>
        { NextHeadConstructor(libInstance) }
        <body>
          { NextMainConstructor(libInstance) }
          { NextScriptConstructor(libInstance) }
        </body>
      </html>
    }
  }
)

This can be located in something like: next/constructors/document and be imported and use in next/document with react (to maintain the actual compatibility). I not certainly if we have problem to not use import react, import preact or import inferno in this file (because we are passing this throught an argument. But we can try :)

EDIT: The code example from @arunoda with this implementation, will be something like:

import Inferno from 'inferno'
import Component from 'inferno-component'
import { renderToString } from 'inferno-server'
import NextDocumentConstructor from 'next/constructors/document'
import flush from 'styled-jsx/server'

export class Document extends Component {
  static getInitialProps ({ pageComponent, getHead }) {
    // Likewise, you could use your own renderer here.
    const { html } = renderToString(pageComponent)
    const head = getHead()
    const styles = flush()
    return { html, styles }
  }

  return () {
    return NextDocumentConstructor({Component}, this.props)
  }
}

Check out #2279; given that replacing renderToString() might mean you want something that doesn't behave the same way (i.e. isn't synchronous), you might need to replace document.js altogether at the server layer. That's how I was able to add Rapscallion support. I almost feel like that makes more sense, it's an "advanced" usage so I don't want to radically alter how Document works for the average Next user.

Hi! I would like to work on this one if someone can tell me what the ideal way is. I understand that next/document is central to the app, so @guidiego 's approach might need tweaking that. How should we go about it?

Hey guys, any news on this one ?

I saw a msg recently saying we may have the node streaming support soon, would be nice to have a bit of flexibility in the renderer (for component caching ..)

As of right now we're not planning to allow different server-renders that are incompatible with React. preact can be used already (see the examples dir).

The reason for this is that the React team is working on a new SSR / streaming rendering solution that would be incompatible + break in significant ways. By not allowing this extra complexity to be added by default we can ensure that the new solution will most likely "just work" for Next.js apps.

There are a few other relevant older issues like:
https://github.com/zeit/next.js/issues/1209
https://github.com/zeit/next.js/issues/1210

Was this page helpful?
0 / 5 - 0 ratings

Related issues

flybayer picture flybayer  路  3Comments

kenji4569 picture kenji4569  路  3Comments

olifante picture olifante  路  3Comments

irrigator picture irrigator  路  3Comments

knipferrc picture knipferrc  路  3Comments