Ref https://github.com/zeit/next.js/issues/1209
With this we could easily allow to use alternative server renderes like Preact, Inferno, rapscallion.
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
Most helpful comment
@guidiego @renatorib Our idea is to allow it to customize on the custom document. Here's how we think about it.