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

Road to V2 #107

Closed
WebReflection opened this Issue Sep 11, 2017 · 73 comments

Comments

Projects
None yet
9 participants
@WebReflection
Owner

WebReflection commented Sep 11, 2017

While latest API and logic is mature and battle-tested enough, there are few things that worked well but others that didn't shine in V1.

Following a list of things I'd like to improve for the next release:

  • ES2015+ code. I'm happy about current hyperHTML compatibility and features detection capabilities, but the code is a little monolith written in old ES5, hence not too welcoming for contributors
  • ES2015 modules. I'd like to split all internals in modules and utilities. This should give me the ability to produce a light version of hyperHTML that doesn't include method and wire adopt-ability
  • there is already a 100% code covered viperHTML branch that produces layouts with hyper friendly comments in the right place. This would make hyperHTML adopt capability way easier, reaching attributes with ease but also making multiple placeholders discovery a no-brainer. Factoring out from main package adopt-ability would make hyperHTML lighter and hyperHTML.adopt accurate. Moreover, the current adopt logic is partially broken in core due unability to discover templates previously used.

This will be a big effort in terms of code refactoring, it will partially change/break current adoptability (an experimental feature not many are using so far anyway), but it will not change the API as we know it.

However, adopt will be not available by default (breaking change) and because of that I think V2 makes sense (as also previously suggested).


If you have anything in particular you'd like to see in a V2 please add a comment to this future-plan issue, thank you.

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 11, 2017

Contributor

How about a build tool/optimizer (or babel plugin), along the lines of yo-yoify? Just an idea: is there some performance to be gained by modifying the AST to make run-time faster?

Contributor

asapach commented Sep 11, 2017

How about a build tool/optimizer (or babel plugin), along the lines of yo-yoify? Just an idea: is there some performance to be gained by modifying the AST to make run-time faster?

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 11, 2017

Owner

Actually I've just read what is yo-yoify about, basically it's exactly what huperHTML is out of the box.

So no, nothing like that is needed. It's already how the core works.

Owner

WebReflection commented Sep 11, 2017

Actually I've just read what is yo-yoify about, basically it's exactly what huperHTML is out of the box.

So no, nothing like that is needed. It's already how the core works.

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 11, 2017

Contributor

OK, another idea: is there a way to improve developer experience when using wire() with the same object, especially in a loop (https://viperhtml.js.org/hyperhtml/documentation/#api-1-2)? Should I always be using an id when iterating over elements? What if I mistakenly use the same id twice? What if I write one loop (without adding an id) and then my teammate creates another loop without realizing that we'll run into performance problems? Is it possible to catch these scenarios? Or better yet re-design the api to avoid them altogether.

Contributor

asapach commented Sep 11, 2017

OK, another idea: is there a way to improve developer experience when using wire() with the same object, especially in a loop (https://viperhtml.js.org/hyperhtml/documentation/#api-1-2)? Should I always be using an id when iterating over elements? What if I mistakenly use the same id twice? What if I write one loop (without adding an id) and then my teammate creates another loop without realizing that we'll run into performance problems? Is it possible to catch these scenarios? Or better yet re-design the api to avoid them altogether.

@joshgillies

This comment has been minimized.

Show comment
Hide comment
@joshgillies

joshgillies Sep 12, 2017

tbh - I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

The api in my mind is sound, though potentially introducing environment based messaging could help direct users away from non-performant patterns eg.

if (env === 'development') {
  if (doingSomethingWeirdWithWire) {
    console.warn("You're potentially doing something weird with wire, have you considered...")
  }
}

This kind of messaging can be easily removed by uglify for production builds, but then again how much messaging is too much when there's already ample documentation covering wire().


Something I'd like to raise again for consideration is lifecycle hooks for hyper.Component. The quintessential example in my mind is:

class Timer extends hyper.Component {
  get defaultState() {
    return {
      secondsElapsed: 0
    }
  }
  tick () {
    this.setState({
      secondsElapsed: this.state.secondsElapsed + 1
    })
  }
  connectedCallback () {
    this.interval = setInterval(() => this.tick(), 1000)
  }
  disconnectedCallback () {
    clearInterval(this.interval)
  }
  render () {
    return this.html`
      <div>Seconds Elapsed: ${this.state.secondsElapsed}</div>
    `
  }
}

I wonder is there an approach where we can determine whether a component has been rendered and inserted into the DOM without having to resort to MutationObserver + polyfill.

Looking over the likes of patrick-steele-idem/morphdom you can see they have hooks for onBeforeNodeAdded, onNodeAdded, onBeforeNodeDiscarded, and onNodeDiscarded. Which they manage to implement without MutationObserver. I'd have to look closer at how they manage to pull it off, but if similar could be applied to hyper.Component I think that would help to bring hyper.Component inline with the expectations of developers coming from the React world.

joshgillies commented Sep 12, 2017

tbh - I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

The api in my mind is sound, though potentially introducing environment based messaging could help direct users away from non-performant patterns eg.

if (env === 'development') {
  if (doingSomethingWeirdWithWire) {
    console.warn("You're potentially doing something weird with wire, have you considered...")
  }
}

This kind of messaging can be easily removed by uglify for production builds, but then again how much messaging is too much when there's already ample documentation covering wire().


Something I'd like to raise again for consideration is lifecycle hooks for hyper.Component. The quintessential example in my mind is:

class Timer extends hyper.Component {
  get defaultState() {
    return {
      secondsElapsed: 0
    }
  }
  tick () {
    this.setState({
      secondsElapsed: this.state.secondsElapsed + 1
    })
  }
  connectedCallback () {
    this.interval = setInterval(() => this.tick(), 1000)
  }
  disconnectedCallback () {
    clearInterval(this.interval)
  }
  render () {
    return this.html`
      <div>Seconds Elapsed: ${this.state.secondsElapsed}</div>
    `
  }
}

I wonder is there an approach where we can determine whether a component has been rendered and inserted into the DOM without having to resort to MutationObserver + polyfill.

Looking over the likes of patrick-steele-idem/morphdom you can see they have hooks for onBeforeNodeAdded, onNodeAdded, onBeforeNodeDiscarded, and onNodeDiscarded. Which they manage to implement without MutationObserver. I'd have to look closer at how they manage to pull it off, but if similar could be applied to hyper.Component I think that would help to bring hyper.Component inline with the expectations of developers coming from the React world.

@marcoscaceres

This comment has been minimized.

Show comment
Hide comment
@marcoscaceres

marcoscaceres Sep 12, 2017

Collaborator

Um, I still like AMD support (I know... but I'm using it with a legacy project)... otherwise, I need to put hyperHTML into the global scope, which makes me a bit sad.

Collaborator

marcoscaceres commented Sep 12, 2017

Um, I still like AMD support (I know... but I'm using it with a legacy project)... otherwise, I need to put hyperHTML into the global scope, which makes me a bit sad.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 12, 2017

Owner

@joshgillies

I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

Thank you.

is there an approach where we can determine whether a component has been rendered

as soon as you invoke this.render() the component is resolved and rendered

and inserted into the DOM

I could easily invoke a "connected" the first time it's rendered, but I cannot easily grant a "disconnected" without bloating the code and slowing it down per each splice operation.

On top of this, hyper components are compatible with the DOM right away. The only thing the "bind/render" does here is to invoke comp.render() if you pass a component instead of a node but technically you can have hyperHTML components that work out of the box on any other project simply explicitly invoking such .render() method.

Having hooks that work only when components are rendered inside hyperHTML is a functionality lock-in and I happily leave lit-html lock itself in its own classes and logic, keeping hyperHTML open to wider adoption outside its own domain.

without having to resort to MutationObserver + polyfill

I will check what/how they do that, but MutationObserver is the only way to go here, IMO. Remember: hyperHTML promotes the platform as much as it can.

@marcoscaceres

I still like AMD support

here I'm planning to move away from CommonJS and old syntax and go all-in ES2015 modules: AMD ain't gonna happen unless I export a file dedicated for that use case.

Would it work? Also ... if you had an ES2015 export could your bundler use it and wrap it as AMD or you need a file that's AMD out of the box?

Last, but not least, I also would like to see hyperHTML used in modern projects 😛

Owner

WebReflection commented Sep 12, 2017

@joshgillies

I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

Thank you.

is there an approach where we can determine whether a component has been rendered

as soon as you invoke this.render() the component is resolved and rendered

and inserted into the DOM

I could easily invoke a "connected" the first time it's rendered, but I cannot easily grant a "disconnected" without bloating the code and slowing it down per each splice operation.

On top of this, hyper components are compatible with the DOM right away. The only thing the "bind/render" does here is to invoke comp.render() if you pass a component instead of a node but technically you can have hyperHTML components that work out of the box on any other project simply explicitly invoking such .render() method.

Having hooks that work only when components are rendered inside hyperHTML is a functionality lock-in and I happily leave lit-html lock itself in its own classes and logic, keeping hyperHTML open to wider adoption outside its own domain.

without having to resort to MutationObserver + polyfill

I will check what/how they do that, but MutationObserver is the only way to go here, IMO. Remember: hyperHTML promotes the platform as much as it can.

@marcoscaceres

I still like AMD support

here I'm planning to move away from CommonJS and old syntax and go all-in ES2015 modules: AMD ain't gonna happen unless I export a file dedicated for that use case.

Would it work? Also ... if you had an ES2015 export could your bundler use it and wrap it as AMD or you need a file that's AMD out of the box?

Last, but not least, I also would like to see hyperHTML used in modern projects 😛

@marcoscaceres

This comment has been minimized.

Show comment
Hide comment
@marcoscaceres

marcoscaceres Sep 12, 2017

Collaborator

D'uh! Of course. I'll get it for free when I transpile! 🤠🥁👏

Collaborator

marcoscaceres commented Sep 12, 2017

D'uh! Of course. I'll get it for free when I transpile! 🤠🥁👏

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 12, 2017

Owner

then you have already the .mjs version these days ... index.mjs and min.mjs are exporting as ES2015 module. Do these work already?

Owner

WebReflection commented Sep 12, 2017

then you have already the .mjs version these days ... index.mjs and min.mjs are exporting as ES2015 module. Do these work already?

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 12, 2017

Contributor

tbh - I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

IMHO, the fact that you can get used to it doesn't necessarily mean it's a good api.

Contributor

asapach commented Sep 12, 2017

tbh - I feel like wire() has been covered extensively, and it's actually not that difficult to understand once you've actually used hyperHTML for more than a day.

IMHO, the fact that you can get used to it doesn't necessarily mean it's a good api.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 12, 2017

Owner

I think he meant you should actually use hyperHTML before complaining about it.

Also happy to analize your proposal.

Owner

WebReflection commented Sep 12, 2017

I think he meant you should actually use hyperHTML before complaining about it.

Also happy to analize your proposal.

@joshgillies

This comment has been minimized.

Show comment
Hide comment
@joshgillies

joshgillies Sep 12, 2017

@asapach apologies of I came off as rude. My comment wasn't so much around the API itself but the reality that with some new concepts it actually takes building something in order for it to make sense.

A comparison could be made between wire() and closures/scope in JavaScript. In that you can do all the reading in the world but true understanding comes from actually using the technology before the concepts can really take hold.

For me the realization that wire() was a weakly held reference between an Object and a Document Fragment was the spark. But I feel as though calling it weak() would be even more confusing.

Again, if you have an alternative API in mind please share your thoughts. :)

joshgillies commented Sep 12, 2017

@asapach apologies of I came off as rude. My comment wasn't so much around the API itself but the reality that with some new concepts it actually takes building something in order for it to make sense.

A comparison could be made between wire() and closures/scope in JavaScript. In that you can do all the reading in the world but true understanding comes from actually using the technology before the concepts can really take hold.

For me the realization that wire() was a weakly held reference between an Object and a Document Fragment was the spark. But I feel as though calling it weak() would be even more confusing.

Again, if you have an alternative API in mind please share your thoughts. :)

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 13, 2017

Contributor

OK, here's my problem with the wire API: why do I need to pass the id when I want to render different content based on the same object? Like wire(user, ':avatar') and wire(user, ':profile') in the docs. If I forget to do that, I'm shooting myself in the foot because it won't be able to track state.
A more contrived example is when I'm using this.html in a hyper.Component (which in turn uses wire(this) under the hood): I want to render content more than once, e.g. as a helper method (I don't say it's a good practice, but nevertheless):

render() {
  var snippet = this.renderSnippet();
  return this.html`Info: ${snippet}`;
}

renderSnippet() {
  return this.html`...`;
}

So here's my proposal: it should be possible to distinguish between wire(obj)`foo` and wire(obj)`bar` , since they use different TLs, so it should be clear that the intent of the developer is to use two different wires. Is it possible to cache wires based on TL rather than id?
Perhaps it could be a new/different API to avoid breaking existing functionality.

Contributor

asapach commented Sep 13, 2017

OK, here's my problem with the wire API: why do I need to pass the id when I want to render different content based on the same object? Like wire(user, ':avatar') and wire(user, ':profile') in the docs. If I forget to do that, I'm shooting myself in the foot because it won't be able to track state.
A more contrived example is when I'm using this.html in a hyper.Component (which in turn uses wire(this) under the hood): I want to render content more than once, e.g. as a helper method (I don't say it's a good practice, but nevertheless):

render() {
  var snippet = this.renderSnippet();
  return this.html`Info: ${snippet}`;
}

renderSnippet() {
  return this.html`...`;
}

So here's my proposal: it should be possible to distinguish between wire(obj)`foo` and wire(obj)`bar` , since they use different TLs, so it should be clear that the intent of the developer is to use two different wires. Is it possible to cache wires based on TL rather than id?
Perhaps it could be a new/different API to avoid breaking existing functionality.

@joshgillies

This comment has been minimized.

Show comment
Hide comment
@joshgillies

joshgillies Sep 13, 2017

@asapach

Is it possible to cache wires based on TL rather than id?

Sure, but you still need a way to handle the following scenarios:

// svgs
wire(obj, 'svg')`...`

// lists
items.map((item, i) => wire(item, `:item-${i}`)`...`

// verbose equivalent of above
wire(obj)`<div>${[
  wire(obj, ':span-1')`<span>${'foo'}</span>`,
  wire(obj, ':span-2')`<span>${'bar'}</span>`
]}</div>`

For these cases (there may be others!) the only real way to handle them is by passing in an :id that you as the developer control. Personally I feel as though if there are cases where you're still required to manually assign an :id, we may as well make that the default for all cases.

Edit: #107 (comment)

joshgillies commented Sep 13, 2017

@asapach

Is it possible to cache wires based on TL rather than id?

Sure, but you still need a way to handle the following scenarios:

// svgs
wire(obj, 'svg')`...`

// lists
items.map((item, i) => wire(item, `:item-${i}`)`...`

// verbose equivalent of above
wire(obj)`<div>${[
  wire(obj, ':span-1')`<span>${'foo'}</span>`,
  wire(obj, ':span-2')`<span>${'bar'}</span>`
]}</div>`

For these cases (there may be others!) the only real way to handle them is by passing in an :id that you as the developer control. Personally I feel as though if there are cases where you're still required to manually assign an :id, we may as well make that the default for all cases.

Edit: #107 (comment)

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 13, 2017

Owner

@asapach the wire is a weak relation between an object and a DOM representation.

If I forget to do that, I'm shooting myself in the foot because it won't be able to track state.

It's the same of having a weakmap. If you wm.set(obj, value1) and then wm.set(obj, value2) you inevitably lose the obj <=> value1 relationship and JavaScript wouldn't warn you: it's your code, it's your choice.

The wire gives you the ability to address ids like in a WeakMap relationship such:

// wire(myobj, ':id1')
wm.get(myobj).id1;

// wire(myobj, ':id2')
wm.get(myobj).id2;

// wire(myobj, ':somethingElse')
wm.get(myobj).somethingElse;

Since it'd be inconvenient to write code in any other way, you'll find that wires give you out of the box a very simple mechanism to reuse an object to represent same TL, like @joshgillies showed already, or various TLs for various cases.

This is not going to change and I don't see any proposal that would make it more robust, any better, less confusing, or more flexible.

Owner

WebReflection commented Sep 13, 2017

@asapach the wire is a weak relation between an object and a DOM representation.

If I forget to do that, I'm shooting myself in the foot because it won't be able to track state.

It's the same of having a weakmap. If you wm.set(obj, value1) and then wm.set(obj, value2) you inevitably lose the obj <=> value1 relationship and JavaScript wouldn't warn you: it's your code, it's your choice.

The wire gives you the ability to address ids like in a WeakMap relationship such:

// wire(myobj, ':id1')
wm.get(myobj).id1;

// wire(myobj, ':id2')
wm.get(myobj).id2;

// wire(myobj, ':somethingElse')
wm.get(myobj).somethingElse;

Since it'd be inconvenient to write code in any other way, you'll find that wires give you out of the box a very simple mechanism to reuse an object to represent same TL, like @joshgillies showed already, or various TLs for various cases.

This is not going to change and I don't see any proposal that would make it more robust, any better, less confusing, or more flexible.

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 13, 2017

Contributor

@joshgillies I totally get that you need different content for SVG and HTML, but that's type, not id.

items.map((item, i) => wire(item, `:item-${i}`)`...`

This is a bad example because you're wiring different objects, and you probably don't want to rely on the index, in case you change the order of the elements in the array.

  wire(obj, ':span-1')`<span>${'foo'}</span>`,
  wire(obj, ':span-2')`<span>${'bar'}</span>`

This is where my proposal might break down, since you're using the same TL on the same object multiple times. But in this case you could opt in and use id if you have to, but in 99% it should not be necessary.

@WebReflection I get that explanation and understand the rationale behind it, but it would be good if wireContent() would not just throw everything away if I use it with a different TL (source) and instead maybe maintain its own TL => wire WeakMap.

Contributor

asapach commented Sep 13, 2017

@joshgillies I totally get that you need different content for SVG and HTML, but that's type, not id.

items.map((item, i) => wire(item, `:item-${i}`)`...`

This is a bad example because you're wiring different objects, and you probably don't want to rely on the index, in case you change the order of the elements in the array.

  wire(obj, ':span-1')`<span>${'foo'}</span>`,
  wire(obj, ':span-2')`<span>${'bar'}</span>`

This is where my proposal might break down, since you're using the same TL on the same object multiple times. But in this case you could opt in and use id if you have to, but in 99% it should not be necessary.

@WebReflection I get that explanation and understand the rationale behind it, but it would be good if wireContent() would not just throw everything away if I use it with a different TL (source) and instead maybe maintain its own TL => wire WeakMap.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 13, 2017

Owner

You basically want to use the TL as :id by default.

This has the following implications:

  • it will be slow by default, while tons of examples, already created, showed it's really not hard to opt in with an id already
  • it will make the wire API even more magic and complex to explain, which was your initial comment, IIRC
Owner

WebReflection commented Sep 13, 2017

You basically want to use the TL as :id by default.

This has the following implications:

  • it will be slow by default, while tons of examples, already created, showed it's really not hard to opt in with an id already
  • it will make the wire API even more magic and complex to explain, which was your initial comment, IIRC
@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 13, 2017

Owner

P.S. I will try to benchmark & test the TL as default :id ... I just want to be sure people suggesting changes actually used the API and really had problems hard to solve or figure out otherwise.

Owner

WebReflection commented Sep 13, 2017

P.S. I will try to benchmark & test the TL as default :id ... I just want to be sure people suggesting changes actually used the API and really had problems hard to solve or figure out otherwise.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 13, 2017

Owner

update

I actually forgot that the wire is created before the TL so there's no way a wire can be lazily evaluated, 'cause the moment a wire is executed, it's relationship has already been made.

var wm = new WeakMap;
var createWire = obj => {
  wm.set(obj, TL => console.log('hyper'));
  return wm.get(obj);
};
var wire = createWire({any: 'object'});
wire`Hello World!`; // hyper

I'm not sure a massive core change would benefit much anyone that used wires and ids correctly here, the lazy bit doesn't look too core friendly.

I'll think about it

Owner

WebReflection commented Sep 13, 2017

update

I actually forgot that the wire is created before the TL so there's no way a wire can be lazily evaluated, 'cause the moment a wire is executed, it's relationship has already been made.

var wm = new WeakMap;
var createWire = obj => {
  wm.set(obj, TL => console.log('hyper'));
  return wm.get(obj);
};
var wire = createWire({any: 'object'});
wire`Hello World!`; // hyper

I'm not sure a massive core change would benefit much anyone that used wires and ids correctly here, the lazy bit doesn't look too core friendly.

I'll think about it

@joshgillies

This comment has been minimized.

Show comment
Hide comment
@joshgillies

joshgillies Sep 14, 2017

@asapach

This is a bad example because you're wiring different objects

Haha, you're right! I think what I was attempting to illustrate was more along the lines of:

wire(items)`<ul>${
  items.map((item) => wire(item)`<li>${
    wire(item, `:${item.id}`)`<span>${item.content}</span>`
  }</li>`)
}</ul>`

Which is equivalent to the third scenario in #107 (comment).


@WebReflection

I'm not sure a massive core change would benefit much anyone that used wires and ids correctly here, the lazy bit doesn't look too core friendly.

Technically this type of change would fall inline with a semver major release. I guess is it something we'd want to address with v2, or roadmap to maybe v3?

Thinking on this more, I do wonder whether there's scope to push this out into user-land? @asapach could the following meet your requirement at least initially?

// ⚠️ untested, likely full of bugs! ⚠️ 
const autoWire = (obj) => (TL, ...args) => wire(obj, `:${TL.raw.join('')}`)(TL, ...args)

autoWire(obj)`<div>${autoWire(obj)`<span>...</span>`}</div>`

joshgillies commented Sep 14, 2017

@asapach

This is a bad example because you're wiring different objects

Haha, you're right! I think what I was attempting to illustrate was more along the lines of:

wire(items)`<ul>${
  items.map((item) => wire(item)`<li>${
    wire(item, `:${item.id}`)`<span>${item.content}</span>`
  }</li>`)
}</ul>`

Which is equivalent to the third scenario in #107 (comment).


@WebReflection

I'm not sure a massive core change would benefit much anyone that used wires and ids correctly here, the lazy bit doesn't look too core friendly.

Technically this type of change would fall inline with a semver major release. I guess is it something we'd want to address with v2, or roadmap to maybe v3?

Thinking on this more, I do wonder whether there's scope to push this out into user-land? @asapach could the following meet your requirement at least initially?

// ⚠️ untested, likely full of bugs! ⚠️ 
const autoWire = (obj) => (TL, ...args) => wire(obj, `:${TL.raw.join('')}`)(TL, ...args)

autoWire(obj)`<div>${autoWire(obj)`<span>...</span>`}</div>`
@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 14, 2017

Contributor

@joshgillies, yes, that does seem to work: https://codepen.io/asapach/pen/aLzWdq?editors=0010
(no extra dom updates)

TL.raw.join('')

It would probably be a good idea to use a UID here to avoid collisions:

TL.raw.join(UID)
Contributor

asapach commented Sep 14, 2017

@joshgillies, yes, that does seem to work: https://codepen.io/asapach/pen/aLzWdq?editors=0010
(no extra dom updates)

TL.raw.join('')

It would probably be a good idea to use a UID here to avoid collisions:

TL.raw.join(UID)
@joshgillies

This comment has been minimized.

Show comment
Hide comment
@joshgillies

joshgillies Sep 14, 2017

@asapach

It would probably be a good idea to use a UID here to avoid collisions:

Remember, hyperHTML does a really good job of ensuring node reuse, and minimum set of changes to the DOM. I'd worry adding some UID into the above would cause more wire variants to be created where viable variants already exist. I guess this is the balancing act we need to perform, managing developer experience with out of the box performance of hyperHTML which is why I'm all for experimenting on things like this in user-land. Glad my little POC worked for you 👍

joshgillies commented Sep 14, 2017

@asapach

It would probably be a good idea to use a UID here to avoid collisions:

Remember, hyperHTML does a really good job of ensuring node reuse, and minimum set of changes to the DOM. I'd worry adding some UID into the above would cause more wire variants to be created where viable variants already exist. I guess this is the balancing act we need to perform, managing developer experience with out of the box performance of hyperHTML which is why I'm all for experimenting on things like this in user-land. Glad my little POC worked for you 👍

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 14, 2017

Owner

this one:

const autoWire = (obj) => (TL, ...args) => wire(obj, `:${TL.raw.join('')}`)(TL, ...args)

beside potentially accessing big IDs each time, this would create O(n) callbacks so that we optimized the DOM but still penalized the GC.

What I had in mind is different:

  • create a unique "hash" once per template, so that using it as ID won't need very long object keys
  • create a bound version of the function once per object, instead of N callbacks per each reference
  • optimize the access for one argument case only to not penalize performance

This is all fine for a V2 indeed but I don't want to rush conclusions neither.

If I have to make the wire lazy, I end up in "lit-html" or current hyper adopt land: it's incompatible with the outer world and one of the point of hyperHTML is playing nice out of the box with the regular DOM:

// already possible
document.body.appendChild(hyper`<p>hello</p>`);

That is basically just an empty wire that, having a single element, can be appended right away.
The concept works for hyper.Component classes with a single root node, you just invoke .render() and you can use it whenever you want, not only in hyperHTML rendered nodes.

I believe this is a strength of the library, avoiding lock-in with itself like in lit-html, and I'd like to keep it this way.

As summary, I will experiment with various ways to optimize the single object as wire argument case but I'm not planning to refactor wires as always lazy wraps of the current functionality.

Owner

WebReflection commented Sep 14, 2017

this one:

const autoWire = (obj) => (TL, ...args) => wire(obj, `:${TL.raw.join('')}`)(TL, ...args)

beside potentially accessing big IDs each time, this would create O(n) callbacks so that we optimized the DOM but still penalized the GC.

What I had in mind is different:

  • create a unique "hash" once per template, so that using it as ID won't need very long object keys
  • create a bound version of the function once per object, instead of N callbacks per each reference
  • optimize the access for one argument case only to not penalize performance

This is all fine for a V2 indeed but I don't want to rush conclusions neither.

If I have to make the wire lazy, I end up in "lit-html" or current hyper adopt land: it's incompatible with the outer world and one of the point of hyperHTML is playing nice out of the box with the regular DOM:

// already possible
document.body.appendChild(hyper`<p>hello</p>`);

That is basically just an empty wire that, having a single element, can be appended right away.
The concept works for hyper.Component classes with a single root node, you just invoke .render() and you can use it whenever you want, not only in hyperHTML rendered nodes.

I believe this is a strength of the library, avoiding lock-in with itself like in lit-html, and I'd like to keep it this way.

As summary, I will experiment with various ways to optimize the single object as wire argument case but I'm not planning to refactor wires as always lazy wraps of the current functionality.

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 14, 2017

Contributor

@joshgillies, what I mean is that foo and foo${bar} would produce the same key in your case, so you need a better separator than ''

@WebReflection

create a bound version of the function once per object, instead of N callbacks per each reference

Yes, that is similar to what I had in mind, too.

Thanks.

Contributor

asapach commented Sep 14, 2017

@joshgillies, what I mean is that foo and foo${bar} would produce the same key in your case, so you need a better separator than ''

@WebReflection

create a bound version of the function once per object, instead of N callbacks per each reference

Yes, that is similar to what I had in mind, too.

Thanks.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 14, 2017

Owner

foo and foo${bar} would produce the same key in your case, so you need a better separator than ''

correct. The TL is parsed once regardless and the string with internal UIDs is also created before parsing it.

Accordingly, here I could also create once a UID per template via something like:

function hash(str) {
  var hval = 0x811c9dc5, i = 0, length = str.length;
  while (i < length) {
    hval ^= str.charCodeAt(i++);
    hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
  }
  return hval >>> 0;
}

hoping there won't be collisions (hardly probable that both the object reference and few TL used would collide though).

At that point I'll have a :_${hash(TL)} reference to use as ID and I can lazy create wires once per reference.

It's a bit of a hell but doable

Owner

WebReflection commented Sep 14, 2017

foo and foo${bar} would produce the same key in your case, so you need a better separator than ''

correct. The TL is parsed once regardless and the string with internal UIDs is also created before parsing it.

Accordingly, here I could also create once a UID per template via something like:

function hash(str) {
  var hval = 0x811c9dc5, i = 0, length = str.length;
  while (i < length) {
    hval ^= str.charCodeAt(i++);
    hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
  }
  return hval >>> 0;
}

hoping there won't be collisions (hardly probable that both the object reference and few TL used would collide though).

At that point I'll have a :_${hash(TL)} reference to use as ID and I can lazy create wires once per reference.

It's a bit of a hell but doable

WebReflection added a commit that referenced this issue Sep 14, 2017

Making wire with one argument smarter
As discussed in #107 the wire could simplify
developers life if it was automatically smart enough
to relate the object to the DOM, accordingly to the used TL.

This is an experimental attempt to use such pattern.
@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 14, 2017

Owner

@asapach this is an experimental branch, beside V2, with the wire functionality you suggested:
https://github.com/WebReflection/hyperHTML/blob/8bba50bd4f6a9395221213964d1eca74343a6cf8/index.js

Please let me know how it works.

FWIW I'm not too happy right now because going too implicit here might result in footguns when it comes to SVG vs HTML as types while specifying the type would be a step close to just also add an ID to the wire. I will play around with it

Owner

WebReflection commented Sep 14, 2017

@asapach this is an experimental branch, beside V2, with the wire functionality you suggested:
https://github.com/WebReflection/hyperHTML/blob/8bba50bd4f6a9395221213964d1eca74343a6cf8/index.js

Please let me know how it works.

FWIW I'm not too happy right now because going too implicit here might result in footguns when it comes to SVG vs HTML as types while specifying the type would be a step close to just also add an ID to the wire. I will play around with it

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 14, 2017

Contributor

@WebReflection I gave it a go, and for the most part it works as expected.
And as expected this doesn't work:

wire(obj)`foo${bar}`
wire(obj)`foo${baz}`

A couple of issues, though:

  1. I think we also need to update Component, because it seems to work the old way (non-lazy):
class Test extends hyperHTML.Component {
  render() {
    return this.html`test ${this.html`<b>passed</b>`}`;
  }
}

But once I add this to the constructor it works fine:

this.html = hyperHTML.wire(this);
  1. Ran into this error (https://codepen.io/asapach/pen/YrXzYw?editors=1010):
  render() {
    return this.html`test ${{
      any: this.html`<b>passed</b>`,
      placeholder: '<i>failed</i>'
    }}`;
  }
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
    at Aura.splice (test.js:167:10)
    at Array.hodor (test.js:1291:35)
    at performOperations (test.js:1419:21)
    at majinbuu (test.js:1275:5)
    at Array.anyContent (test.js:362:19)
    at Array.update (test.js:1103:18)
    at HTMLDivElement.render (test.js:199:12)

Again, when changing this.html to lazy works fine.

Contributor

asapach commented Sep 14, 2017

@WebReflection I gave it a go, and for the most part it works as expected.
And as expected this doesn't work:

wire(obj)`foo${bar}`
wire(obj)`foo${baz}`

A couple of issues, though:

  1. I think we also need to update Component, because it seems to work the old way (non-lazy):
class Test extends hyperHTML.Component {
  render() {
    return this.html`test ${this.html`<b>passed</b>`}`;
  }
}

But once I add this to the constructor it works fine:

this.html = hyperHTML.wire(this);
  1. Ran into this error (https://codepen.io/asapach/pen/YrXzYw?editors=1010):
  render() {
    return this.html`test ${{
      any: this.html`<b>passed</b>`,
      placeholder: '<i>failed</i>'
    }}`;
  }
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
    at Aura.splice (test.js:167:10)
    at Array.hodor (test.js:1291:35)
    at performOperations (test.js:1419:21)
    at majinbuu (test.js:1275:5)
    at Array.anyContent (test.js:362:19)
    at Array.update (test.js:1103:18)
    at HTMLDivElement.render (test.js:199:12)

Again, when changing this.html to lazy works fine.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 14, 2017

Owner

And as expected this doesn't work:

What do you mean there? It's the same TL, only the interpolation should update there and there's no way I can/should change that.

Did I misunderstand your comment?

About the Component, I don't think using this.html more than once makes sense there. You need to return the result so it's way too confusing to have it in the wild inside its own templates.

What you need there is just the hyper function like in lit-html ... and since you need hyper.Component there, you have hyper already to use hyper(this) wherever you need.

TL;DR I think you went too far with the Component example. It's ambiguous and hard to document. Plus there is SVG too, and it'd be a mess combined. I don't think I want to implement that. It's visually and logically disturbing, IMO

Owner

WebReflection commented Sep 14, 2017

And as expected this doesn't work:

What do you mean there? It's the same TL, only the interpolation should update there and there's no way I can/should change that.

Did I misunderstand your comment?

About the Component, I don't think using this.html more than once makes sense there. You need to return the result so it's way too confusing to have it in the wild inside its own templates.

What you need there is just the hyper function like in lit-html ... and since you need hyper.Component there, you have hyper already to use hyper(this) wherever you need.

TL;DR I think you went too far with the Component example. It's ambiguous and hard to document. Plus there is SVG too, and it'd be a mess combined. I don't think I want to implement that. It's visually and logically disturbing, IMO

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 14, 2017

Contributor

What do you mean there?

This was one of the counter-examples raised by @joshgillies. I don't expect it to work, since as you said, there's no way to tell them apart. Let's leave it as a caveat for now.

I don't think using this.html more than once makes sense there.

Perhaps it's worth adding this to the docs?

Contributor

asapach commented Sep 14, 2017

What do you mean there?

This was one of the counter-examples raised by @joshgillies. I don't expect it to work, since as you said, there's no way to tell them apart. Let's leave it as a caveat for now.

I don't think using this.html more than once makes sense there.

Perhaps it's worth adding this to the docs?

@asapach

This comment has been minimized.

Show comment
Hide comment
@asapach

asapach Sep 16, 2017

Contributor

Thanks. A follow-up question if you don't mind: you think that this implicit dependency on plugins is better than explicit one? Is this the way you see people using it?

import {hyper} from 'hyperhtml';
import 'my-behavior-plugin'; // don't forget to import it every time you use it

...
hyper`foo ${{ myBehavior: 'bar' }}`

Versus explicit:

import {hyper} from 'hyperhtml';
import myBehavior from 'my-behavior-plugin';

...
hyper`foo ${ myBehavior('bar') }`
Contributor

asapach commented Sep 16, 2017

Thanks. A follow-up question if you don't mind: you think that this implicit dependency on plugins is better than explicit one? Is this the way you see people using it?

import {hyper} from 'hyperhtml';
import 'my-behavior-plugin'; // don't forget to import it every time you use it

...
hyper`foo ${{ myBehavior: 'bar' }}`

Versus explicit:

import {hyper} from 'hyperhtml';
import myBehavior from 'my-behavior-plugin';

...
hyper`foo ${ myBehavior('bar') }`
@obedm503

This comment has been minimized.

Show comment
Hide comment
@obedm503

obedm503 Sep 16, 2017

I also agree with the underlying idea that function-based explicit plugins are better. Honestly, the way plugins currently work makes it seems like custom "intents" follow the concept of global plugins (sort of like jQuery plugins)


on another note: why not separate out rendering from template creation/composition? I don't have any concrete use case right now, but when I first found out about hyperHTML I really wasn't sure where the template was being rendered and where the template was being constructed. This separation might lead to an easier to understand, and more extensible api as these constructed templates could be passed around freely before reaching a place where they will be rendered.

In the case of hyper.Component and HyperHTMLElement, that means that the user-defined render(){} method returns a constructed template and the rendering would happen internally as an implementation detail of such components.

Just an idea

obedm503 commented Sep 16, 2017

I also agree with the underlying idea that function-based explicit plugins are better. Honestly, the way plugins currently work makes it seems like custom "intents" follow the concept of global plugins (sort of like jQuery plugins)


on another note: why not separate out rendering from template creation/composition? I don't have any concrete use case right now, but when I first found out about hyperHTML I really wasn't sure where the template was being rendered and where the template was being constructed. This separation might lead to an easier to understand, and more extensible api as these constructed templates could be passed around freely before reaching a place where they will be rendered.

In the case of hyper.Component and HyperHTMLElement, that means that the user-defined render(){} method returns a constructed template and the rendering would happen internally as an implementation detail of such components.

Just an idea

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 18, 2017

Owner

Is this the way you see people using it?

no. the way is documented, you define behaviors through define.

That means you have portable templates, like I've mentioned and showed already.

module.exports = (render, model) => render`
  <section class="my-component">
    <h1>${model.title}</h1>
    <ul>
      ${withSpecialHandler: model.items}
    </ul>
  </section>
`;

Above module is portable on both client and server side, or even native-script side.

Above module doesn't force you to define the withSpecialHandler behavior at all, that is left to you.
In this way you can ignore special handler and simply return the list synchronously if you are using viperHTML on the backend, or do something, even asynchronous, on the client before rendering such list. It's up to your implementation.

The module, as view, can be tested in isolation, and the behavior mocked too.
This is what I mean by "no scope pollution here", and it's more powerful and more recyclable and flexible than any explicit, scoped, dependency.

Owner

WebReflection commented Sep 18, 2017

Is this the way you see people using it?

no. the way is documented, you define behaviors through define.

That means you have portable templates, like I've mentioned and showed already.

module.exports = (render, model) => render`
  <section class="my-component">
    <h1>${model.title}</h1>
    <ul>
      ${withSpecialHandler: model.items}
    </ul>
  </section>
`;

Above module is portable on both client and server side, or even native-script side.

Above module doesn't force you to define the withSpecialHandler behavior at all, that is left to you.
In this way you can ignore special handler and simply return the list synchronously if you are using viperHTML on the backend, or do something, even asynchronous, on the client before rendering such list. It's up to your implementation.

The module, as view, can be tested in isolation, and the behavior mocked too.
This is what I mean by "no scope pollution here", and it's more powerful and more recyclable and flexible than any explicit, scoped, dependency.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 18, 2017

Owner

I also agree with the underlying idea that function-based explicit plugins are better

good. So here you can do whatever you want, you can write explicit functions that returns whatever primitive you want, or you can use the define way, which is how you natively define custom elements too so ... nothing really new as a concept to learn.

on another note: why not separate out rendering from template creation/composition? I don't have any concrete use case right now,

I do, and I've linked it. The fastest Haker News PWA out there uses already this pattern. It shares same views with both client and server, since it's 100% SSR.

In the case of hyper.Component and HyperHTMLElement, that means that ...

... HyperHTMLElement is incompatible with SSR because Shadow DOM is incompatible with SSR, and if you don't use Shadow DOM you are probably better off with regular hyper.Component, although you won't have the created/connected/attributeChanged/disconnected callbacks provided by the platform, yet you can have a component that requires a view that can be shared with both client, server, and, eventually, native.

TL;DR what's in core already, beside the experimental adopt, works already, it has already use cases, it has been discussed already too before V1 went out, and this post is to discuss only missing bits. If you can achieve what you need by yourself, that means that the core exposes already the right primitives. Accordingly, unless I read, see, and understand real-world use cases that cannot be solved with the current core or are really needed, instead of speculating about the need or the performance implication, not much will change. That was never the intent of this thread. Thanks cfor your collaboration.

Owner

WebReflection commented Sep 18, 2017

I also agree with the underlying idea that function-based explicit plugins are better

good. So here you can do whatever you want, you can write explicit functions that returns whatever primitive you want, or you can use the define way, which is how you natively define custom elements too so ... nothing really new as a concept to learn.

on another note: why not separate out rendering from template creation/composition? I don't have any concrete use case right now,

I do, and I've linked it. The fastest Haker News PWA out there uses already this pattern. It shares same views with both client and server, since it's 100% SSR.

In the case of hyper.Component and HyperHTMLElement, that means that ...

... HyperHTMLElement is incompatible with SSR because Shadow DOM is incompatible with SSR, and if you don't use Shadow DOM you are probably better off with regular hyper.Component, although you won't have the created/connected/attributeChanged/disconnected callbacks provided by the platform, yet you can have a component that requires a view that can be shared with both client, server, and, eventually, native.

TL;DR what's in core already, beside the experimental adopt, works already, it has already use cases, it has been discussed already too before V1 went out, and this post is to discuss only missing bits. If you can achieve what you need by yourself, that means that the core exposes already the right primitives. Accordingly, unless I read, see, and understand real-world use cases that cannot be solved with the current core or are really needed, instead of speculating about the need or the performance implication, not much will change. That was never the intent of this thread. Thanks cfor your collaboration.

@kidwm

This comment has been minimized.

Show comment
Hide comment
@kidwm

kidwm Sep 22, 2017

I've found that hyperHTML.define is working like global object, it may to be overwrite in other modules after I defined the intent in my module.

It seems using hyperHTML.Component to encapsulate my intent into a module would be better than hyperHTML.define.

Will there be any improvement on hyperHTML.define?

kidwm commented Sep 22, 2017

I've found that hyperHTML.define is working like global object, it may to be overwrite in other modules after I defined the intent in my module.

It seems using hyperHTML.Component to encapsulate my intent into a module would be better than hyperHTML.define.

Will there be any improvement on hyperHTML.define?

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 22, 2017

Owner

I've found that hyperHTML.define is working like global object

it's rather like customElements.define except it doesn't throw. Namespaces or good names matter, and there's no way to improve the semantics, keeping it portable (as previously discussed).

it may to be overwrite in other modules after I defined the intent in my module.

would you prefer it to throw instead, if already defined ?

It seems using hyperHTML.Component to encapsulate my intent into a module would be better than hyperHTML.define.

you are comparing apples and oranges. define is for utilities that can be shared across components. Components is for ... components. If you need components, use components. If you need utilities, use utilities.

Last, but not least, if you have real-world use cases that cannot be solved with current primitives, please show them, thanks.

Owner

WebReflection commented Sep 22, 2017

I've found that hyperHTML.define is working like global object

it's rather like customElements.define except it doesn't throw. Namespaces or good names matter, and there's no way to improve the semantics, keeping it portable (as previously discussed).

it may to be overwrite in other modules after I defined the intent in my module.

would you prefer it to throw instead, if already defined ?

It seems using hyperHTML.Component to encapsulate my intent into a module would be better than hyperHTML.define.

you are comparing apples and oranges. define is for utilities that can be shared across components. Components is for ... components. If you need components, use components. If you need utilities, use utilities.

Last, but not least, if you have real-world use cases that cannot be solved with current primitives, please show them, thanks.

@kidwm

This comment has been minimized.

Show comment
Hide comment
@kidwm

kidwm Sep 22, 2017

would you prefer it to throw instead, if already defined ?

I have no preference on this, if I really want to avoid the collision, maybe I can use Symbol as the object key?

you are comparing apples and oranges. define is for utilities that can be shared across components.

Yes, FWIW, If I treat it like context in React, define would be a good solution and even better.

Last, but not least, if you have real-world use cases that cannot be solved with current primitives, please show them, thanks.

Sure, I'm working to port my react component to utilize hyperHTML, will ask you some questions about it soon.

kidwm commented Sep 22, 2017

would you prefer it to throw instead, if already defined ?

I have no preference on this, if I really want to avoid the collision, maybe I can use Symbol as the object key?

you are comparing apples and oranges. define is for utilities that can be shared across components.

Yes, FWIW, If I treat it like context in React, define would be a good solution and even better.

Last, but not least, if you have real-world use cases that cannot be solved with current primitives, please show them, thanks.

Sure, I'm working to port my react component to utilize hyperHTML, will ask you some questions about it soon.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 22, 2017

Owner

if I really want to avoid the collision, maybe I can use Symbol as the object key?

in theory, yes. in practice, I'm currently using a for/in which would miss a Symbol as key. However, I think Symbol as transformer key are a solution to all the use-cases so ... thanks for the hint, I'll land ASAP!

Regarding throwing ... I don't think that's needed. The reason define is easy-peasy is that its purpose is to be easily mocked at runtime, whenever it's needed.

Sure, I'm working to port my react component to utilize hyperHTML, will ask you some questions about it soon.

happy to help, although I'm not sure this is the right place for doing it. Open eventually new issues, ask in StackOverflow using hyperhtml tag, or ping me via Twitter (DM open)

Owner

WebReflection commented Sep 22, 2017

if I really want to avoid the collision, maybe I can use Symbol as the object key?

in theory, yes. in practice, I'm currently using a for/in which would miss a Symbol as key. However, I think Symbol as transformer key are a solution to all the use-cases so ... thanks for the hint, I'll land ASAP!

Regarding throwing ... I don't think that's needed. The reason define is easy-peasy is that its purpose is to be easily mocked at runtime, whenever it's needed.

Sure, I'm working to port my react component to utilize hyperHTML, will ask you some questions about it soon.

happy to help, although I'm not sure this is the right place for doing it. Open eventually new issues, ask in StackOverflow using hyperhtml tag, or ping me via Twitter (DM open)

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 22, 2017

Owner

@kidwm FYI version 1.9.0 is now compatible with Symbols too

Owner

WebReflection commented Sep 22, 2017

@kidwm FYI version 1.9.0 is now compatible with Symbols too

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 25, 2017

Owner

FYI, as extra proof that hyperHTML primitives are all there for our daily needs, a component helper just landed on npm to help solving connected and disconnected use cases, and without needing any change to hyperHTML itself.

Check hyperhtml-comp out.

Owner

WebReflection commented Sep 25, 2017

FYI, as extra proof that hyperHTML primitives are all there for our daily needs, a component helper just landed on npm to help solving connected and disconnected use cases, and without needing any change to hyperHTML itself.

Check hyperhtml-comp out.

@ematipico

This comment has been minimized.

Show comment
Hide comment
@ematipico

ematipico Sep 25, 2017

FYI version 1.9.0 is now compatible with Symbols too

Is there a changelog available somewhere?

ematipico commented Sep 25, 2017

FYI version 1.9.0 is now compatible with Symbols too

Is there a changelog available somewhere?

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 25, 2017

Owner

I just wrote it:

version 1.9.0 is now compatible with Symbols too

the change log is in commits so far

Owner

WebReflection commented Sep 25, 2017

I just wrote it:

version 1.9.0 is now compatible with Symbols too

the change log is in commits so far

@ematipico

This comment has been minimized.

Show comment
Hide comment
@ematipico

ematipico Sep 25, 2017

Yeah I know that you just wrote it. My question was about where is the changelog, not what you added in 1.9.0.

ematipico commented Sep 25, 2017

Yeah I know that you just wrote it. My question was about where is the changelog, not what you added in 1.9.0.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 25, 2017

Owner

where is the changelog

where every change log is born in any repository here: commits

when you see the version bump, that's npm version minor/patch and before that you see fixes for bugs (patches) or new features (minor) described per each commit.

This is all I've got so far, it will improve once v2 is out.

Owner

WebReflection commented Sep 25, 2017

where is the changelog

where every change log is born in any repository here: commits

when you see the version bump, that's npm version minor/patch and before that you see fixes for bugs (patches) or new features (minor) described per each commit.

This is all I've got so far, it will improve once v2 is out.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 26, 2017

Owner

FYI I've found a smart way to have better performance directly in core so hyperhtml-comp has been deprecated and version 1.10+ of hyperHTML will ship with component capables of connected and disconnected events.

Commits here: cfcc8e0

Owner

WebReflection commented Sep 26, 2017

FYI I've found a smart way to have better performance directly in core so hyperhtml-comp has been deprecated and version 1.10+ of hyperHTML will ship with component capables of connected and disconnected events.

Commits here: cfcc8e0

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Sep 26, 2017

Owner

P.S. this might be the last change before I completely rewrite the adopt part and, once fully green, rewrite the project for V2.

Owner

WebReflection commented Sep 26, 2017

P.S. this might be the last change before I completely rewrite the adopt part and, once fully green, rewrite the project for V2.

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 24, 2017

Owner

@esbenjuul why are you posting this here instead of StackOverflow? there is a hyperhtml tag there 😉

Owner

WebReflection commented Oct 24, 2017

@esbenjuul why are you posting this here instead of StackOverflow? there is a hyperhtml tag there 😉

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 24, 2017

Owner

Yes please

Owner

WebReflection commented Oct 24, 2017

Yes please

@mindplay-dk

This comment has been minimized.

Show comment
Hide comment
@mindplay-dk

mindplay-dk Oct 25, 2017

If you're going for a full rewrite, please consider Typescript, or fully JSDoc - which comes down to about the same thing, only you'd get so much more safety and strictness with TS (in strict mode) forcing you to write code that "does what it says" and to fully document everything as you go. It's worth the extra effort :-)

mindplay-dk commented Oct 25, 2017

If you're going for a full rewrite, please consider Typescript, or fully JSDoc - which comes down to about the same thing, only you'd get so much more safety and strictness with TS (in strict mode) forcing you to write code that "does what it says" and to fully document everything as you go. It's worth the extra effort :-)

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 25, 2017

Owner

I have 100% code coverage to ensure what I write works the way it's meant to, TypeScript will never land in any of my personal projects, I'm simply pro standards.

Owner

WebReflection commented Oct 25, 2017

I have 100% code coverage to ensure what I write works the way it's meant to, TypeScript will never land in any of my personal projects, I'm simply pro standards.

@mindplay-dk

This comment has been minimized.

Show comment
Hide comment
@mindplay-dk

mindplay-dk Oct 26, 2017

I'm pro standards - I'm also pro type-safety. Each to his own :-)

mindplay-dk commented Oct 26, 2017

I'm pro standards - I'm also pro type-safety. Each to his own :-)

@mindplay-dk

This comment has been minimized.

Show comment
Hide comment
@mindplay-dk

mindplay-dk Oct 26, 2017

@WebReflection just out of curiosity, what do you think about Flow and JSDoc and related tools?

From my perspective, they're essentially doing much of what Typescript does, but with the non-standard syntax hidden in standard comments, which IMO doesn't truly make them anymore "standards compliant" than Typescript - the compiled output of Typescript is standard JS (which is Typescript without the type-hints) and you'd "compile" Flow or JSDoc just the same to check and remove the type-hints, so the process and the mix of standards with proprietary type-syntax/checking are much the same. In my opinion, the only conceptual difference is Flow and JSDoc hide the proprietary syntax in doc-blocks.

I'm curious to know why you're so dead-set against Typescript though? We seem to have a lot of the same goals and objectives - I have many of the same minimalist points of view that you express in your blog posts and documentation. I view Typescript not so much as a language though - I view it mostly as a tool that helps me write correct, self-documenting, type-safe code with good IDE support.

Each to his own, I'm just curious to learn more about where you're coming from :-)

mindplay-dk commented Oct 26, 2017

@WebReflection just out of curiosity, what do you think about Flow and JSDoc and related tools?

From my perspective, they're essentially doing much of what Typescript does, but with the non-standard syntax hidden in standard comments, which IMO doesn't truly make them anymore "standards compliant" than Typescript - the compiled output of Typescript is standard JS (which is Typescript without the type-hints) and you'd "compile" Flow or JSDoc just the same to check and remove the type-hints, so the process and the mix of standards with proprietary type-syntax/checking are much the same. In my opinion, the only conceptual difference is Flow and JSDoc hide the proprietary syntax in doc-blocks.

I'm curious to know why you're so dead-set against Typescript though? We seem to have a lot of the same goals and objectives - I have many of the same minimalist points of view that you express in your blog posts and documentation. I view Typescript not so much as a language though - I view it mostly as a tool that helps me write correct, self-documenting, type-safe code with good IDE support.

Each to his own, I'm just curious to learn more about where you're coming from :-)

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 26, 2017

Owner

what do you think about Flow and JSDoc and related tools?

I wish flow was ECMAScript standard and I don't believe in JSDoc much 'cause I've worked with projects obsessed with it and yet I had no clue what the application using all those methods was doing.

Writing examples above methods that are contained to the method only also seem useless to me but yeah ... good documentation is hard either ways.

I'm curious to know why you're so dead-set against Typescript though?

  • it's not standard
  • it's a joke

I'm just curious to learn more about where you're coming from

I come from 18+ years of standards, advocating standards, and using them as much as I could.

The only issues I've ever really had in my experience as developers have been caused by non standard solutions.

The JavaScript i've written 18 years ago still works without any tool.

The ActionScript 1 doesn't work anymore, my old working projects are death.
The ActionScript 2 doesn't work anymore, my relatively recent projects are death.
TypeScript will do the exact same end of Dart. It's not standard, fewer and fewer will adopt it while JS will keep evolving through the standard path.

I've always bet in standards, and never[*] regret in doing so.

[*] ok, ok, WebSQL deprecation is still something I hate

Owner

WebReflection commented Oct 26, 2017

what do you think about Flow and JSDoc and related tools?

I wish flow was ECMAScript standard and I don't believe in JSDoc much 'cause I've worked with projects obsessed with it and yet I had no clue what the application using all those methods was doing.

Writing examples above methods that are contained to the method only also seem useless to me but yeah ... good documentation is hard either ways.

I'm curious to know why you're so dead-set against Typescript though?

  • it's not standard
  • it's a joke

I'm just curious to learn more about where you're coming from

I come from 18+ years of standards, advocating standards, and using them as much as I could.

The only issues I've ever really had in my experience as developers have been caused by non standard solutions.

The JavaScript i've written 18 years ago still works without any tool.

The ActionScript 1 doesn't work anymore, my old working projects are death.
The ActionScript 2 doesn't work anymore, my relatively recent projects are death.
TypeScript will do the exact same end of Dart. It's not standard, fewer and fewer will adopt it while JS will keep evolving through the standard path.

I've always bet in standards, and never[*] regret in doing so.

[*] ok, ok, WebSQL deprecation is still something I hate

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 26, 2017

Owner

worth clarifying that Dart is actually standard, but not de-facto standard for the Web.

Owner

WebReflection commented Oct 26, 2017

worth clarifying that Dart is actually standard, but not de-facto standard for the Web.

@marcoscaceres

This comment has been minimized.

Show comment
Hide comment
@marcoscaceres

marcoscaceres Oct 27, 2017

Collaborator

My experience mirror's @WebReflection's: I've been burnt too many times by proprietary things like TypeScript: they are not well suited for libraries/project that are supposed to last a decade or more (such as this one).

On the JSDoc stuff... if it's demonstrable that something like Visual Studio Code would pick up the definitions out of the box, in an unobtrusive manner, then it might be worth discussing - but I think showing the benefit is a precondition to any consideration for inclusion.

Collaborator

marcoscaceres commented Oct 27, 2017

My experience mirror's @WebReflection's: I've been burnt too many times by proprietary things like TypeScript: they are not well suited for libraries/project that are supposed to last a decade or more (such as this one).

On the JSDoc stuff... if it's demonstrable that something like Visual Studio Code would pick up the definitions out of the box, in an unobtrusive manner, then it might be worth discussing - but I think showing the benefit is a precondition to any consideration for inclusion.

@ematipico

This comment has been minimized.

Show comment
Hide comment
@ematipico

ematipico Oct 27, 2017

JSDoc are just comments that explain things. I do like it, it's not obstructive, are just comments that explain developers what is what. There are some IDEs or editors that take advantage of that and they give you autocomplete and such things, but it's just a bonus. Having comments is harmless

ematipico commented Oct 27, 2017

JSDoc are just comments that explain things. I do like it, it's not obstructive, are just comments that explain developers what is what. There are some IDEs or editors that take advantage of that and they give you autocomplete and such things, but it's just a bonus. Having comments is harmless

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 27, 2017

Owner

There are comments in hyperHTML and the API is basically two methods.

I just don’t care about strict jsdoc rules and I might prefer TypeScript definition file which AFAIK helps IDEs even more and it might be the only thing I like of .ts 😅

Owner

WebReflection commented Oct 27, 2017

There are comments in hyperHTML and the API is basically two methods.

I just don’t care about strict jsdoc rules and I might prefer TypeScript definition file which AFAIK helps IDEs even more and it might be the only thing I like of .ts 😅

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 27, 2017

Owner

I’m also closing this since the discussion lost focus. V2 will come out soon, no extra addictions/changes will be made beside huge refactoring in terms of standard and modern syntax + better project structures.

Thanks for all hints and suggestions

Owner

WebReflection commented Oct 27, 2017

I’m also closing this since the discussion lost focus. V2 will come out soon, no extra addictions/changes will be made beside huge refactoring in terms of standard and modern syntax + better project structures.

Thanks for all hints and suggestions

@WebReflection

This comment has been minimized.

Show comment
Hide comment
@WebReflection

WebReflection Oct 27, 2017

Owner

P.S. adopt won’t be in by default in V2

Owner

WebReflection commented Oct 27, 2017

P.S. adopt won’t be in by default in V2

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