developit / htm

Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.
Apache License 2.0
8.67k stars 170 forks source link

Support HTML5 void elements #171

Closed Siilwyn closed 3 years ago

Siilwyn commented 4 years ago

It would be great to be able to write standard HTML5 without needing to close tags like in JSX, which is just another small thing to learn for developers.

E.g: an image tag normally works but doesn't in HTM: <img src="hi.png>.

dy commented 4 years ago

htm@1.x supported that.

I've experimented with implementation of void elements, as well as optional closing elements here, and noticed that that reduces original HTM performance by ~20% (it needs to check each tag if that's in void list) and increases bundle size ~108 bytes.

Also see #91.

Siilwyn commented 4 years ago

@dy ah interesting, optional closing elements are not something I'm after, is that 20% performance difference only caused by supporting void elements?

Maybe it can be given as an option to support since 108 bytes more is not that much, the performance doesn't matter to me since I plan to use 'babel-plugin-htm'.

dy commented 4 years ago

is that 20% performance difference only caused by supporting void elements

Yes - each opening tag in markup should be checked against list of possible self-closing matches: area base br col command embed hr img input keygen link meta param source track wbr. That is 16x redundant ops for each tag, unless some smart filtering involved.

cztomsik commented 4 years ago

you can use this (preprocessing) hack:

html = html.replace(/<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)([^<>]*?)[^\/]>/gi, '<$1$2/>')
dy commented 4 years ago

@cztomsik but how would you use it with templates html`<img src=${src}>`?

cztomsik commented 4 years ago

I didn't need that (I'm using htm as temporary html parser so I'm just calling htm.bind(x)([html])) but you can:

import htm from 'https://unpkg.com/htm?module'

const boundHtm = htm.bind((tag, atts, ...kids) => ({ tag, atts, kids }))
const voidBoundHtm = (strings, ...values) => boundHtm(strings.map(addSlash), ...values)
const addSlash = html => html.replace(/<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)([^<>]*?)\/?>/gi, '<$1$2/>')

const hello = 'Hello'
console.log(voidBoundHtm`<br><hr><span>${hello}</span>`)

It's ugly but it seems to work (and the regex had one bug)

developit commented 3 years ago

FWIW one of the reasons I don't think we're likely to consider this is because there are a lot of other HTML features that are unsupported in HTM. Adding a feature like void elements is net negative for performance, but it increases the likelihood of folks thinking HTM is an HTML parser. This assumption breaks down pretty quickly - attribute names are case-sensitive, whitespace is trimmed, etc.

HTM is also most often used with Virtual DOM libraries, which further diverge from HTML since they tend to adopt HTML's property semantics for "props" rather than the string-only semantics of HTML attributes. We've actually had cases in Preact where folks using HTM have run into issues using namespaced attributes. VDOM doesn't have those, and they're only "supported" in HTM because it's faster and smaller to pass-through namespaces than it would be to prevent their usage.

That all said, I do think it would be interesting for someone to resurrect the htm@1 codebase and repurpose it as a standalone HTML-to-VDOM library. It would be the fastest implementation, support 100% of HTML (since it uses DOMParser), and weigh in at around 300b. A library for that purpose wouldn't need the tagged templates stuff, it would just be a string => VNode transformer.

Siilwyn commented 3 years ago

Thank you for the reply @developit, much appreciated. I understand the decision. I might publish a htm@1 project when I find time. :crossed_fingers:

Will close, ofc. discussion is still possible.

cztomsik commented 3 years ago

of folks thinking HTM is an HTML parser.

Of course it's not, I'm using it only temporarily

BTW: @developit do you know about some small (well-formed is enough, speed is not an issue) HTML parsers?

dy commented 3 years ago

In case if you need htm-compatible API, have a look at xhtm https://github.com/spectjs/xhtm

On Tue, Sep 22, 2020 at 5:31 AM Kamil Tomšík notifications@github.com wrote:

of folks thinking HTM is an HTML parser.

Of course it's not, I'm using it only temporarily

BTW: @developit https://github.com/developit do you know about some small (well-formed is enough, speed is not an issue) HTML parsers?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/developit/htm/issues/171#issuecomment-696611305, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACJIIZT4LL7I4WPU44A5B3SHBVGFANCNFSM4NZERNKA .