Lit-html: Render to a stream

Created on 14 Nov 2017  路  16Comments  路  Source: Polymer/lit-html

For demos, prototyping and SSR use-cases, it would be useful if lit-html supported rendering to a string. For example:

import {html, render} from 'lit-html';

const helloTemplate = (name) => html`<div>Hello ${name}!</div>`;

// This returns <div>Hello Steve!</div>
render(helloTemplate('Steve'));
Medium Enhancement Competitive parity Enable new use cases Reduce adoption friction

Most helpful comment

@justinfagnani and I spoke a bit about this. To summarize (I hope I'm remembering correctly):

  • SSR will probably be handled by another implementation of html and render.

    • (my thoughts): Requiring DOM access on the server is just dumb. We have a abstract templating system, there's no reason to require it.

    • This would probably hamper re-rendering on the server, but I'm not sure how many would actually do that.

  • As for rehydrating on the client, we'll probably need to leave Comment nodes so we know where Parts start and end. (Mainly because of the multi-node support)

    • Might even need a hydrate function, that'll attached the cached values that were used to render on the server to the DOM nodes on the client.

    • This wouldn't validate or render, just setup the cached logic so render doesn't blow away the nodes.

In all, SSR doesn't seem super difficult. They're _just_ tagged template literals, we might even just let it stringify like a normal template literal.

All 16 comments

I guess, for SSR we need DOM API support on server side. It can be done with JSDOM, but I do not sure.

@justinfagnani and I spoke a bit about this. To summarize (I hope I'm remembering correctly):

  • SSR will probably be handled by another implementation of html and render.

    • (my thoughts): Requiring DOM access on the server is just dumb. We have a abstract templating system, there's no reason to require it.

    • This would probably hamper re-rendering on the server, but I'm not sure how many would actually do that.

  • As for rehydrating on the client, we'll probably need to leave Comment nodes so we know where Parts start and end. (Mainly because of the multi-node support)

    • Might even need a hydrate function, that'll attached the cached values that were used to render on the server to the DOM nodes on the client.

    • This wouldn't validate or render, just setup the cached logic so render doesn't blow away the nodes.

In all, SSR doesn't seem super difficult. They're _just_ tagged template literals, we might even just let it stringify like a normal template literal.

@jridgewell good summary. It's ever-slightly more complicated than using a no-op template tag on the server though, because we want to offer the same XSS protection. I think we'd want to do the same HTML-string generation, then run through parse5, then do value substitution. It's a perf cost, but ensures parsing behavior and escaping.

The repeat() and until() directives would also need to made available too, right?

It would also be neat if the goal of "Efficient updates of previously rendered DOM" was achieved if the initial rendering occurred server-side. (This may require embedding some of the data structures needed into the server-side rendered string--perhaps something similar to what glimmer describes as rehydration--or generating client-side JS at template compilation time.)

What also would be great is if lit-html鈥檚 server-side rendering someday also supported asynchronous/streaming string rendering, like how Marko already does.

Most SSR libraries today, like React, can render HTML on the server only into single, concatenated, contiguous-memory strings. But this has obvious memory-allocation and IO disadvantages. It should be possible for lit-html to render a template into a Node stream (or, eventually, an async iterable or a WHATWG readable stream) that yields strings of HTML chunks.

This would allow Node to start serving dynamically generated HTML in its HTTP response as soon as possible, which in turn would allow browser engines to progressively render the initial HTML as soon as possible, without being blocked on server-side file/database IO and waiting for an entire render. It may also make memory allocation more efficient for very large documents: only smaller chunks of HTML, rather than large strings for entire pages, would be allocated on the heap.

Streaming SSR is not urgently needed, but it's something to keep in mind from the beginning of designing lit-html鈥檚 SSR, so as not to preclude adding it in the future.

Some prior art:

I might be interested in pitching in on developing SSR if possible. What would an appropiate starting approach be in terms of where I put the code etc?

also we need renderToString for unit testing

There is now an (unofficial) lit-html-server project being worked on and discussed in #461

Working on this now, but I'm doing it as rendering to a stream, rather than a string.

We use Puppeteer for rendering HTML out as PNGs, most libraries support SSR but add markers for rehydration on the client which doesn't work for us because we don't want to load any clientside code or have any reactivity which makes renderToString essential.

Any progress, plans ?

I have some rather rough experimental code I can into a repo today.

hmmm when i read render to stream i get headache we got already the stream implamentation with lit-html server in reallife tests that is not enought.

And the Stream Implamentation does add a lot of unneeded code.. but ok go for it but i think we could then simply copy paste the relevant parts from lit-html-server

@justinfagnani @popeindustries Hi to both the lit-html team and the creator of lit-html-server. Thank you both for these wonderful projects, they are great accomplishments

I wanted to chime in to say I've been working on a means of making isomorphic apps that can use either implementation, as well as including a state management pattern for interactive front end apps and a few other features, called lit-app. It's published now on NPM, I'd appreciate any feedback.

https://github.com/klaudhaus/lit-app

IMHO it would make sense to keep the implementations (DOM / static) separate - that way you avoid unnecessary code inclusion or complication. It keeps to the Unix principal of small tools that do one thing well (which I try to follow too, the state management is a separate package called lit-up that can be used independently of lit-app).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fopsdev picture fopsdev  路  5Comments

dakom picture dakom  路  4Comments

depeele picture depeele  路  3Comments

MVSICA-FICTA picture MVSICA-FICTA  路  5Comments

AndyOGo picture AndyOGo  路  3Comments