New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: server-side stache templates that support incremental rendering #1122

Open
justinbmeyer opened this Issue Nov 2, 2018 · 7 comments

Comments

Projects
None yet
3 participants
@justinbmeyer
Copy link
Contributor

justinbmeyer commented Nov 2, 2018

TLDR; Create an incremental rendering template engine for NodeJS.

This was discussed on a recent live stream (15:56).

Summary

Incremental rendering is awesome. It shouldn't work for only Single Page Apps when it would work great for Multi Page Apps too. And while there are other server-side templates that support streaming, afaik, nothing else supports incremental rendering.

A basic express app might look like this:

var mental = require("mental");

var playersTemplate = mental(`
  <html>
    <head>
        <link ...>
    </head>
    <body>
        <header>
           <h1>Welcome</h1>
           {{#if sessionPromise.isResolved }} {{sessionPromise.value.name}} {{/if}}
        </header>
        <content>
            <nav> .... </nav>
            {{#for player of playersPromise }}<li>{{player.name}}</li>{{/for}}
        </content>
        <footer> ... </footer>
    </body>
  </html>
`);

var app = express();
app.get('/services/players', function(req, res){
  var playersPromise = GET_PLAYERS(); 
  var sessionPromise = GET_SESSION();

  playersTemplate(res, {
    playersPromise, sessionPromise
  })
})

This would push out all the HTML except what the server is waiting on (the session and players). Once those promises resolve, the server will send out mutation instructions for those.

On the client, we'd probably have a "mental.onDocumentReady()" hook so people know when the page has been fully loaded.

@mjstahl

This comment has been minimized.

Copy link
Member

mjstahl commented Nov 5, 2018

I think this would be really cool!

I think the part to really focus on with this is how the client gets those "mutation instructions".

Personally I would work backwards from "the developer shouldn't have to do /anything/. Maybe some JavaScript gets added to the <head></head> and just automagically hooks things up."

@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Nov 16, 2018

@mjstahl yes, this is how done-ssr@3 works already! done-ssr inlines a script tag that begins fetching the mutation stream and apply mutations.

I think this would be a good opportunity to share our tech with folks outside the SPA world.

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 26, 2018

@justinbmeyer i think that there is a reason why it not exists :)
i don't want to write now a public benchmark for that but i am really sure there is a reason i talked about that as you started with that idea.

Only for your Info a HTML Response gets Incremental Rendered by the Browser while he streams the html file it don't needs to be there complet on the client.

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 26, 2018

The response object is a writable stream. Just write to it, and Express will even set up chunked encoding for you automatically.

response.write(chunk);

You can also pipe to it if whatever is creating this "file" presents itself as a readable stream. http://nodejs.org/api/stream.html

and with that + deffered async stuff in html we even replace http push

<script type="module">, 
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">, 
<script defer src="script.js">, 
<script async src="script.js">

i don't write now about what is right when but this is incremental rendering fully control able for every situation. I will only fast talk about the rel="preload" with css as many could think this is simply a none supported type to load the css async but it is a supported type that faster fetches as a none supported media type. And script type module is also always async JS that is none blocking!!!!!

@justinbmeyer

This comment has been minimized.

Copy link
Contributor

justinbmeyer commented Nov 26, 2018

Frank, you have to write out in document order. Incremental rendering has no such limitation.

The reason it doesn’t exist is likely because you would need a DOM-based rendering template engine. Those don’t exist server-side.

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 27, 2018

@justinbmeyer nodejs has many dom based rendering engines 1 that would work is chromium headless firefox headless and so on but you would need the right rendering engine for the right request header this will not be performant.

I have runned tests with caching prerendered pages per engine rendered serverside by the engine on request and that was not performant and also not a good idea as the rendering must happen in the browser version also and then also need to do that best device specific

the best method in performance and compatiblity is to send out html from the server. I agree with your point of writing out html in order but that is not a bad thing at all for text from databases its a great fit as this can also be streamed.

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 27, 2018

@justinbmeyer maybe i should also point out about The google Material Design Expirences that show the fact that slow loading but right timed is better then Instand loading!

Examples: Click Image Fade Slow so the user Expirence is smooth
All the stuff about Emotions on loading

Summary:
Render out Ordered HTML with a Skeleton https://blog.iamsuleiman.com/wp-content/uploads/2017/02/linkedin-skeleton-screen-loading.png

Let JS Do the rest! For Search engines you render out for example the real final image tag a JS Script catches on inserted of the element and replaces it instant with the right skeleton view and that will replace them self with the original as loaded

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment