Skip to content
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

Ideas from lit-html #79

Closed
2 of 6 tasks
WebReflection opened this issue Aug 8, 2017 · 64 comments
Closed
2 of 6 tasks

Ideas from lit-html #79

WebReflection opened this issue Aug 8, 2017 · 64 comments

Comments

@WebReflection
Copy link
Owner

WebReflection commented Aug 8, 2017

While at this stage it's definitively inferior in terms of features, there are few ideas in lit-html that could be borrowed by hyperHTML keeping viperHTML counterpart compatibility a must-have.

Everything discussed in here will result into a major update due inevitable incompatibility with the current implementation but before going that far, I'd like to investigate few things.

Drop Comments ?

Solution: NO. Comments were not just improving performance splitting automatically the layout in chunks, comments were mandatory to solve partial tables layouts. There's no way without comments you can obtain the same. Also, dropping was a way to have attributes without quotes but current V1 candidate already support that.


lit-html is using {{}} as placeholder while hyperHTML is using <!--hyper-->. The reason for hyperHTML to chose comments is to have best performance on template creation too, not only on successive updates.

To be checked:

  • how badly performance would be affected walking nodes and, per each node, their text content (splitting it in chunks to create new nodes)
  • is {{}} supported without quotes (attributes) on every browser?
  • is {{}} supported with or without quotes (attributes) on svg elements?

Partial Attributes ?

Solution: NO. Partial attributes are YAGNI. You can already have template literals within interpolations so that either through arrays or string concatenation or even functions you can address attributes.

html`<div class=${`foo ${maybeBar ? 'bar' : ''}`}>Foo bar?</div>`;
html`<div class=${'foo' + (maybeBar ? ' bar' : '')}>Foo bar?</div>`;
html`<div class=${['foo', maybeBar ? 'bar' : ''].join(' ')}>Foo bar?</div>`;

html`<div style=${`top:${top}; left:${left};`}>x</div>`;

This has been asked more than once and I still believe it's not needed at all and it makes templates more messy instead of cleaner. However, lit-html supports partial attributes.

To be checked:

  • how badly performance would be affected walking attributes and, per each node, their text content
  • how costly is each new attribute composed update
  • what are the use cases - are use cases so common ?

HTML opt in ? see comment

lit-html is an "always textContent" template thing. It understands it's not text only if the interpolation is a rendered lit thing, hence at distance, post parsing or after the first pass.

hyperHTML has semantics to understand the intent upfront but there are cases where it needs to have an explicit opt-in or opt-out from text.

The recently introduced hyperHTML.escape(text) covers the opt-out from html but there's no official opt in.

hyperHTML.wire could be a good candidate for that, but I'm keen to hear other ideas too.

@joshgillies
Copy link

lit-html seems to have a nice way of assigning placeholder nodes to represent async partials via until(Promise, defaultContent). It would be cool if something similar could be added to hyperHTML.

@WebReflection
Copy link
Owner Author

hyperHTML.async(...) ?

@joshgillies
Copy link

hyperHTML.async(asyncThing, "Loading..."), looks good to me!

@WebReflection
Copy link
Owner Author

second argument as text-only placeholder? any placeholder?

@kenchris
Copy link

kenchris commented Aug 8, 2017

I think the intent of "until" is more clear.

@WebReflection
Copy link
Owner Author

hyperHTML.until(promise, "Loading...") ?

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 8, 2017

I forgot viperHTML.async has a meaning already so .until in hyperHTML makes more sense but it cannot possibly be compatible with viperHTML anyway (which is also a bit of a bummer due inability to reuse the same template declaration)

@gdorsi
Copy link

gdorsi commented Aug 8, 2017

I like the "html opt-in" thing. Simpler to understand than the whitespaces declaration and can be implemented without perf loss.

@bigopon
Copy link
Contributor

bigopon commented Aug 8, 2017

hyperHTML.wait ?

@WebReflection
Copy link
Owner Author

Simpler to understand than the whitespaces declaration

it's a semantic. > ${'text'} </ VS >${'html'}</ I am not sure why this is seen as difficult ... but ...

can be implemented without perf loss.

Nope. That's the reason hyperHTML went for semantics in the first place: you can understand the intent upfront. lit-html has to parse and also to decide what to do only once the interpolation is resolved so it needs 2 passes VS one.

If anything, performance is not surely a win for lit

@gdorsi
Copy link

gdorsi commented Aug 8, 2017

So if you have to sacrifice perf for opinable syntax changes, I think they not worth it.

@WebReflection
Copy link
Owner Author

@gdorsi I wonder if you've used hyperHTML before. I don't find its 2.5 rules too difficult to grasp.

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 8, 2017

Also @gdorsi, for explicit text, you can always use \t (as in t ext)

html`a <a href="#">\t${'b'}</a> c`;

Isn't that explicit enough?

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 8, 2017

Another thing I'd like to understand is what would be a reasonable compromise for hyperHTML to be developers-friendly.

The current 2.5 rules are just 2.5 but I can see controversial for many.

What would be the best option, considering all features already available ?

// API
hyperHTML
  .bind // should be called `.render` ?
  .wire // should be called `.html` ?
  .adopt
  .until // ???

Specially the .wire() is basically what .html does in lit-html.

The main difference is that a wire is weakly related to a generic object while html in lit always create new content if used in the wild.

On the semantic side, the only thing I could think of that makes sense with current hyperHTML implementation is to always be a textContent unless the interpolation content is not text.

I still don't want to lose html injection capabilities because sometimes that's all you need but I wonder if having <div>${'text'}</div> VS <div>${['html']}</div> would make more sense than having spaces around.

Thinking about the future, based on modern JavaScript, I also wonder if having objects could be the key to solve all the issues.

function withText(render, text) {
  return render`<div>${{text}}</div>`;
}

function withHTML(render, html) {
  return render`<div>${{html}}</div>`;
}

Not only this would look even more like a template, but it'll make absolutely not-ambiguous in terms of intent: object with text property is text, and object with html property is html.

The optional, non-text, condition would be any, meaning Array, DOM nodes, Promise or, in case of string content, html which is surely more popular and demanded than just text when you want text.

I know I'm rushing ideas here but I'm also in the process of writing the whole documentation and if there are changes to make and release a V1 first, I'd be happy to do that now.

Thank everyone for extra hints, thoughts, or suggestions.

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 8, 2017

Recap

function html(render) {
  return render`
    <!-- text by default for strings -->
    <p>Hello ${'World'}</p>
    <!-- text as explicit intent -->
    <p>Hello ${{text: 'World'}}</p>
    <select>
      <!-- any by default for no-strings -->
      ${['a', 'b'].map(v => `<option value="${v}">${v}</option>`)}
    </select>
    <!-- html as explicit intent -->
    <p>Hello ${{html: '<strong>World</strong>'}}</p>
    <!-- any as explicit intent -->
    <p>Hello ${{any: fetch('thing').then(b => b.text())}}</p>
  `;
}

Summary

  • always textContent for strings
  • easy opt-in for HTML via any other kind of interpolation that is not typeof "string"
  • possible explicit opt-in/out via object literal

Breaking

  • spaces won't mean anything anymore
  • that means no backward compatibility in V1.0.0 already

Pros

  • virtual logic is already compatible with this scenario
  • since using comments won't bring in any benefit anymore, attributes can be assigned without quotes (still no partial attributes support planned at this point, it's YAGNI)

Cons

  • parser needs huge refactoring
  • performance will be degraded because virtual logic is inevitably the slowest one to deal with

@gdorsi
Copy link

gdorsi commented Aug 8, 2017

I didn't find it hard to understand the 2.5 rules, but making them more explicit can be only a plus.

That said, if you want to make this library perf-first, it's ok to sacrifice usability to be more performant. It's only a matter of objectives.

@WebReflection
Copy link
Owner Author

The initial objective of hyperHTML was to bit the DOM at its own operations in a developer friendly way, without bloating the RAM and CPU with unnecessary Virtual-DOM middleware.

I can say, that achievement has been unlocked 6 months ago already.

Today

The goal is to make it as fast, production ready, and developer-friendly as possible.

I've already achieved the first two points, but the current status is clearly struggling to make it a "just works" for newcomers.

Everyone failed at reading and understanding those 2.5 constrains, everyone asked once about attributes without quotes and #text VS html.

I blame lack of proper documentation first, but also if I have to train everyone because they are used to think template literals in such different way, it means I need to improve the library side first.

If anything, lit-html confirmed developers prefer verbosity over magic, so that an explicit opt-in on Web development is seen as "better" way to go.

Hence my latest proposals that will sacrifice indeed performance a little bit, but I'll find out a way to bit myself on the final implementation, providing a cleaner way for developers to express their intent.

Everything else in lit-html seems quite unnecessary to me, because everything can be already addressed with current hyperHTML in a way or another so ... yeah, anyone can write modules that exports functionalities on top and everyone can render again a promise once it has been resolved.

The only blocker, or better breaking change I see, is the semantic used to define templates.

That's the most important bit, and I think hyperHTML is already superior in terms of interpolation values analysis, but probably not too developer-friendly when it comes to its own 2.5 rules to follow, due performance, and technical choices, constrains.

Having best from every world would be ideal, specially before publishing tons of documents related to the library.

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 8, 2017

P.S. the object literal could also be the entry point for plugins. text, html, any would be available by default, {yourPluginName: content} could be how you extend in hyperHTML.

The more I think about it, the more I like it, specially because it doesn't need global/local scoped variables. 🎉

@oslego
Copy link

oslego commented Aug 8, 2017

A few small points:

If anything, lit-html confirmed developers prefer verbosity over magic

The library didn't confirm anything yet per-se. It's still in its infancy, as recognised by its authors, and there's no need to rush to conclusions. Monitor what lit-html users are reporting, reflect and take some time before making a judgement.

still no partial attributes support planned at this point, it's YAGNI

I disagreed at the beginning, but after having used hyperHTML for a few projects I'm now in agreement that support for partial attributes isn't required. It takes a bit of cognitive effort at the beginning, but after a while I learned to carefully manage setting the attributes in one operation.

However, I do believe this should be more prominently featured in the docs.
One of the most common use cases where devs will encounter and trip is this:

<a class="button--save ${isDisabled ? 'button--disabled' : '' }" href="#">

I blame lack of proper documentation first, but also if I have to train everyone because they are used to think template literals in such different way, it means I need to improve the library side first.

Try docs first :)

@WebReflection
Copy link
Owner Author

Try docs first :)

well, I involved you because you were one of those asking to prevent stringification.

Did I convince you that current semantics make sense? 😃

@joshgillies
Copy link

@WebReflection just skimmed through this. But my immediate thoughts around partial attributes are that they aren't needed. I feel as though the current pattern is more than sufficient, especially if there's a chance of hyperHTML taking a perf hit just to accomodate html<div class="foo ${maybeBar ? 'bar' : ''}">Foo bar?</div> especially when html<div class="${['foo', maybeBar ? 'bar' : ''].join(' ')}">Foo bar?</div> is perfectly acceptable to my eyes.

With regards to alternate methods of defining text, html, etc I'd be very interested in exploring the option of object passing in the form of { text: "Hello" }, { html: '<div>Hello</div>'}. Having spoken with @marcoscaceres recently the fact is if you as a developer neglect the 2.5 rule with hyperHTML there's a chance of XSS, and I'd be all for and explicit mechanism to declaring textContent vs innerHTML content. Also, correct me if i'm wrong but adding support for object passing would be relatively easy given the current state of hyperHTML, and would enable us to test this new API without having to redo all our existing code.

Finally, I'd like to say thanks for opening this issue and having this discussion around the future of hyperHTML. 👍

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 9, 2017

adding support for object passing would be relatively easy

Only if I keep semantics. What you are suggesting is that I keep semantics and I also put objects in the mix.

This is cool but also it's 1/3 of the job because I want to remove semantics completely so that your current templates, if you used html intentionally, will break.

// the following will break
render`<ul>${
  names.map(name => `<li>${name}</li>`)
}</ul>`;

It wouldn't break if you used wires though, but that's another story.

Edit nope, that works. Arrays are treated as explicit html intent.

WebReflection added a commit that referenced this issue Aug 9, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content

The usage of object literal will be improved in the future
to allow exporting any desired extra feature, if needed.

**Todo**

  * performance comparison with V0
  * make the ie test page green in older IE too
@WebReflection
Copy link
Owner Author

So, V1 is ready to land:
https://github.com/WebReflection/hyperHTML/blob/V1/hyperhtml.js

Whoever is interested, please test it as much as you can.

List of features and breaking changes here:
#81 (comment)

Basically, what I've proposed in here:
#79 (comment)

with attributes that won't require quotes anymore.

@WebReflection
Copy link
Owner Author

Interesting enough, not using comments basically breaks every table layout ... if I don't find a way to fix that, I might go back to comments injection and attributes that need quotes.

That would be unfortunate, but the only way to go.

WebReflection added a commit that referenced this issue Aug 10, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
@WebReflection
Copy link
Owner Author

WebReflection commented Aug 10, 2017

FYI viperHTML is already aligned as well.

I'm updating documentation around and will publish officially both versions ASAP.

Thanks for all the help and tests.

@joshgillies
Copy link

Great work @WebReflection - let us know if there's anything we can do to help. 👍

@marcoscaceres
Copy link
Contributor

Agree. Great work! Probably best thing we can do now is help review dev docs and make sure there are no typos, grammar is good, etc.

@WebReflection please feel free to ping me for review.

@joshgillies, all, would also be great if you can help too 🙂

WebReflection added a commit that referenced this issue Aug 10, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
@WebReflection
Copy link
Owner Author

WebReflection commented Aug 10, 2017

IE9 is now 100% code covered and green ... I repeat, IE9 is 100% code covered and green!

@WebReflection
Copy link
Owner Author

screenshot from 2017-08-10 15-02-21

@dyu
Copy link

dyu commented Aug 10, 2017

Looking good so far. Definitely a good approach that does not require special tooling (jsx).
Do you have any links to public benchmarks?
Adding it to https://github.com/krausest/js-framework-benchmark might be a good idea (allows you to identify bottlenecks in your own lib).

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 10, 2017

Do you have any links to public benchmarks?

DBMonster already showed it's at same level of the fastest libraries out there.

viper-news is the fastest HNPWA out there.

Testing V1 locally, it looks like next hyperHTML hasn't lost performance too much.

Performance are a concern when these are really a concern. Today hyperHTML is very fast, and on top of that, is very lightweight.

V1 is going to be dev friendly too, so I ask you where is the benchmark about these 3 points put together behind a 4KB library 😉

@dyu
Copy link

dyu commented Aug 10, 2017

There's a certain lib out there that is only 1k that starts with hyper as well :-) Just sayin.

Anyway, you don't even have to publish the result publicly. You can test your impl agains the benchmark and identify the bottlenecks (if there are any).

Also, when you look at the results, they show raw memory used by the libs.
You'll know how lightweight your lib is (compared to others) when you measure it.

@WebReflection
Copy link
Owner Author

@dyu did you come here friendly or just to speculate?

Show me your results thanks.

@WebReflection
Copy link
Owner Author

let me recap with real-world results, but if anyone wants to waste time on other benchmarks, please do, I'm sure the final result will make @dyu realize he could've helped instead of claiming FUD here.

@dyu
Copy link

dyu commented Aug 10, 2017

Came here friendly. Not interested in any exchanges. Peace!

@WebReflection
Copy link
Owner Author

WebReflection commented Aug 10, 2017

So, I have better things to do than that. I'm testing IE9+ and every other browser including UC.

Micro benchmarks on a thing that doesn't even have clear specs just a long list of how to start the thing isn't exactly my focus right now.

Do you want to help this project? Go ahead and write that test, I'll be more than happy to tell you where eventually optimize it.

Do you want to spread FUD without results? I'm afraid I've already proven myself with real-world tests and results, I'm not willing to waste much time on the rest.

Here, try this with all other frameworks:
https://webreflection.github.io/hyperHTML/test/double-rainbow.html

WebReflection added a commit that referenced this issue Aug 11, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
WebReflection added a commit that referenced this issue Aug 11, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
WebReflection added a commit that referenced this issue Aug 11, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
WebReflection added a commit that referenced this issue Aug 11, 2017
As mentioned in ticket #79 the version 1.0 of hyperHTML
would like to address most painful points raised by developers.

Most specifically, this version 1 is going to drop
support to previous spaces based semantics.

**Breaking changes**

  * spaces are now meaningless.
  * strings are always text content
  * any non string will be automatically handled

**Improvements**

  * attributes do not need quotes anymore (still no partial support)
  * write templates as you want, explicitly opt in with special content
  * use ${{text}} or ${{html}} to explicitly opt-in/out
  * use ${{any}} to pass any content
  * IE11 and Edge are fully green on test page
  * hyperHTML.define(transformer, callback) to create your own transformers
  * object literals can have a placeholder for async content
@oslego
Copy link

oslego commented Aug 11, 2017

I just applied hyperHTML v1 in my side-project and it was thankfully just a drop-in replacement. No backwards compatibility issues in my usage. No issues to report so far.

It did feel liberating to use whitespace freely again. 😄

Thanks for working on this! 👍

@web3d0
Copy link

web3d0 commented Aug 13, 2017

bind and wire do need to be render and html. I haven't been able to understand "wire" except by ignoring the name and thinking "direct html output string... ish thingy" instead. Just needs that little bit of polish from native English usage to get the API more intuitive.

@WebReflection
Copy link
Owner Author

@web3d0 there is a whole new documentation with hopefully better explanations and live Code Pen examples.

These are just a couple of starting point to know more about the differences:
https://viperhtml.js.org/hyperhtml/documentation/#essentials-1

https://viperhtml.js.org/hyperhtml/documentation/#api-0

@web3d0
Copy link

web3d0 commented Aug 13, 2017

Always good to have more documentation. My point is the word "wire" sticks in my brain like a wire, and it is difficult to hang the meanings of what it does on the word "wire". If I shift my brain into the Andrea view, I can see glowing Tron dimensions of writhing HTML strings bridging objects, vibrating with white neon wiring the networks of the Master Computer together. For day to day, perhaps "render" and "html" are more understandable. :)

@WebReflection
Copy link
Owner Author

You render bound content and/or wired content.

The html is the reference to perform such operation.

Wires are connections , like cables , strings , between one or more DOM element to a specific, weakly referenced object.

Neither html nor render, describe this behavior.

If you read both links maybe it'd be more clear.

Also see HyperHTMLElement, which has both html property and a render / update concept.

@joshgillies
Copy link

@web3d0 I tend to agree that the terminology takes a bit to get used to, but tbh as @WebReflection points out, neither html or render adequately describe what's happening with regard to wire and bind. As an example does html as a method seem appropriate to describe some SVG element?

@jonkri
Copy link

jonkri commented Jul 7, 2018

Is there a hyperHTML equivalent to https://github.com/Polymer/lit-element?

@WebReflection
Copy link
Owner Author

It's called HyperHTMLElement

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

No branches or pull requests