batiste / pug-vdom

PUG template to HyperScript Virtual DOM
MIT License
18 stars 6 forks source link

Plain HTML text not supported #15

Closed gryphonmyers closed 6 years ago

gryphonmyers commented 7 years ago

https://github.com/batiste/pug-vdom/blob/master/pug-vdom.js#L102

This one is tricky. I have researched the options for supporting HTML text with virtual-dom and have come up with the following options:

1) Parse the HTML using the client's native DomParser (as noted in the comment). I am not a fan of this idea, because while cheap to load, it would be computationally inefficient as we would go from HTMLString -> Dom Node -> Virtual DOM node -> Dom Node. Part of the point of virtual dom is to avoid unnecessary instantiation of DOM nodes.

2) Parse the HTML using a third party lib. This would of course add the requirement for a runtime dependency, and a lot of HTML parsers are quite large. https://www.npmjs.com/package/prescribe might be an option - it is tiny, and I have gotten promising results with it in the past.

3) virtual-dom does expose the innerHTML DOM node property, meaning that you can do: h('div', {innerHTML: myHTMLString}) and it will render the DOM node with the HTML string as 'black box' content, which it wont attempt to incoporate into its diffing tree. This works relatively well and seems appropriate, however, it does mean that an additional DOM node needs to be introduced. For instance:

.my-element
    | !{"<div class='moo'>Check 1 2</div>"}

would end up as:

h('div', {class: 'my-element'}, [h('div',
  {
    innerHTML: "<div class='moo'>Check 1 2</div>"
  }
])

and finally:

<div class="my-element>
  <div>
    <div class="moo">Check 1 2</div>
  </div>
</div>

This is a problem because the markup is not being accurately represented with the inclusion of the additional DOM node. The node is required though, because if you try to set innerHTML on an element that also has child elements, the results are... unpredictable.

For these reasons, I lean most toward option 2, but the parser/runtime should only be a requirement for templates where plain text is used.

batiste commented 7 years ago

@gryphonmyers totally agree. Actually I never considered option 1. When I said DOMParser I was thinking about any API that could parse HTML. It could be a plus if this API is usable on the client side so you could potentially compile the pug template on the client although this is probably a far fetched use case.

Maybe have a look at this one as well: http://inikulin.github.io/parse5/globals.html#parsefragment

gryphonmyers commented 7 years ago

That is why I suggested prescribe - it is very small, I think 3KB gzipped if I'm remembering correctly. I was viewing client side parsing as a requirement since I often have html data in my template locals that needs to get rendered at runtime. Thus far I have been solving this by preparing the data using the innerHTML trick mentioned above, but it would be nice if the template could take care of html on its own.

On Sun, Oct 22, 2017, 11:58 PM Batiste Bieler notifications@github.com wrote:

@gryphonmyers https://github.com/gryphonmyers totally agree. Actually I never considered option 1. When I said DOMParser I was thinking about any API that could parse HTML. It could be a plus if this API is usable on the client side so you could potentially compile the pug template on the client although this is probably a far fetched use case.

Maybe have a look at this one as well: http://inikulin.github.io/parse5/globals.html#parsefragment

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/batiste/pug-vdom/issues/15#issuecomment-338564697, or mute the thread https://github.com/notifications/unsubscribe-auth/AFhG2OODXM9kn-c1MUT7zWTC6HpnwGoqks5svDkYgaJpZM4QCDbO .

batiste commented 7 years ago

@gryphonmyers I think you use case is slightly different with what is happening here I believe:

https://github.com/batiste/pug-vdom/blob/master/pug-vdom.js#L95

If it is at runtime, then pug cannot really help you. But you might be able to figure something out at runtime? For example in pug you can do raw output with !=. That would mean that there is potentially HTML in there that would need to be parsed by the pug-vdom runtime... I imagine you could figure out something and integrate that in the tree generation

gryphonmyers commented 6 years ago

Just thought of another potential solution to this problem. The virtual-dom widget API allows one to take control of the tree patching process: https://github.com/Matt-Esch/virtual-dom/blob/947ecf92b67d25bb693a0f625fa8e90c099887d5/docs/widget.md

For our purposes, we could potentially identify nodes that have plain text children, turn those nodes into widgets and write a patch method that uses native DOM parser on strings and does normal vdom patching on vnodes. This would remove the need for a third party HTML parser, and avoid having to use an incorrect DOM structure (assuming the patch method is written correctly).

Possible downside, we might be forfeiting compatibility with other VDOM implementations. I personally only use virtual-dom so I have no idea if such compatibility exists currently.