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

Both className and class attributes created. #85

Closed
tunnckoCore opened this issue Feb 12, 2017 · 39 comments
Closed

Both className and class attributes created. #85

tunnckoCore opened this issue Feb 12, 2017 · 39 comments
Labels
bug Something isn't working

Comments

@tunnckoCore
Copy link

tunnckoCore commented Feb 12, 2017

There is classname and class attributes at the created DOM nodes.

2017-02-13-00 08 36_1280x1024_scrot

Kinda feel that i faced that while decoupling the dom diffing and fixed it but cant remember how and where it was and where the codes are. (just did kinda dozen rewrites of few things in a couple of folders; wrote 3-4 new packages that i am lazy to write tests and docs, haha. i'm totally 🤒 👿 💢)

@tunnckoCore tunnckoCore changed the title Virtual DOM bug Bug inside the DOM diffing, while creating the real DOM nodes Feb 12, 2017
@selfup
Copy link
Contributor

selfup commented Feb 12, 2017

I think I have seen something similar here:

http://codepen.io/selfup/pen/WRgOrR

To reproduce

Make two ideas

Hit X on the latest idea (top)

The X button is still highlighted on the idea that was not clicked 🤔


It seems that this happens when a node replaces an old node

Exceptions

If you delete the bottom idea, the top one stays "clean"

@jorgebucaran jorgebucaran added the bug Something isn't working label Feb 13, 2017
@jorgebucaran
Copy link
Owner

@selfup It seems we're talking about two different bugs here?

One with className (safely) polluting the element's HTML and another one which is the one that can be seen in @selfup's CodePen.

Both need fixing, but I'm more interested in fixing the second one as that's a bug that has been bothering me in the TodoMVC implementation for a while.

@selfup
Copy link
Contributor

selfup commented Feb 13, 2017

We might very well be, but I am wondering if it has to do with the diffing.

If you want I can submit a new issue 😄

Or we can just keep track of it in here

@jorgebucaran
Copy link
Owner

@selfup I think they're different, but let me investigate further, they might be related after all.

@jorgebucaran
Copy link
Owner

@selfup @tunnckoCore Could this be a bug/feature of Hyperx? This does not occur when using JSX.

@tunnckoCore
Copy link
Author

dont think so. try raw h calls?

i'll do a pen and will see if when it appears

@jorgebucaran
Copy link
Owner

@tunnckoCore I can confirm both class and className are added when using hyperx, but definitely not when using JSX.

@selfup
Copy link
Contributor

selfup commented Feb 17, 2017

@jbucaran Both examples with issues are JSX apps.

@jorgebucaran jorgebucaran changed the title Bug inside the DOM diffing, while creating the real DOM nodes Both className and class attributes created.. Feb 17, 2017
@jorgebucaran jorgebucaran changed the title Both className and class attributes created.. Both className and class attributes created. Feb 17, 2017
@jorgebucaran
Copy link
Owner

jorgebucaran commented Feb 17, 2017

@selfup Alright, can we open a new issue to track the bug you described here?

Let's keep this issue about the class/className bug.

@tunnckoCore Can you confirm this occurs when using JSX too?

@jorgebucaran
Copy link
Owner

@tunnckoCore @selfup The reason you have both classname and class is because you're using className in the JSX.

See: https://github.com/selfup/hyperapp-one/blob/master/src/views/counter.js#L10.

@selfup Consider using only class? We're not constrained by this.

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

@jbucaran I have the same initial issue with duplicated classname and class attributes on each element.
I'm using hyperx and the class attribute (not className).
I don't have any actions, just a static model, so there is no diffing involved (afaik).

Do you have a clue on this particular bug?

@jorgebucaran
Copy link
Owner

@ngryman Yes, I just had a chance to look at this.

See this Pen.

@jorgebucaran
Copy link
Owner

jorgebucaran commented Mar 5, 2017

Hyperx adds a classname attribute to the virtual node data object. In Hyperapp we just go ahead and set that property in the element which causes the class to be set correctly.

I don't understand why Hyperx does this, however. This is the commit that introduces the functionality in Hyperx.

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

Ok, I get it.
Any chance this does not work for some reason: https://github.com/feross/hyperscript-attribute-to-property/blob/master/index.js#L14?

@jorgebucaran
Copy link
Owner

@ngryman Well observed, this is definitely odd and requires some investigation. 🤔

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

@jbucaran On my local machine, only className is left so class is well deleted.
I can investigate a little on this...

@jorgebucaran
Copy link
Owner

@ngryman Wait, it's working, so it's class what gets deleted.

@jorgebucaran
Copy link
Owner

jorgebucaran commented Mar 5, 2017

Given this view:

<div class="hi">Hello</div>

JSX produces:

{
  children: ["Hello"],
  data: {
    class: "hi"
  },
  tag: "div"
}

Hyperx produces:

{
  children: ["Hello"],
  data: {
    className: "hi"
  },
  tag: "div"
}

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

Using hyperx I have a different result.

Source

const { h } = require('hyperapp')
const hyperx = require('hyperx')
const html = hyperx(h)

const vnode = html`<div class="foo">`
console.log(vnode)

Output

{
  children: [],
  data: {
    className: "foo"
  },
  tag: "div"
}

EDIT: Didn't see you preceding comment 👻

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

It makes sense as hyperscript-attribute-to-property proxy does replace class with className. hyperx probably expects the rendering framework to transform className into a class attribute.

@jorgebucaran
Copy link
Owner

@ngryman Hmm, that sounds right. But why?

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

My guess is that they want to be able to put class instead of className in the markup.
It makes sense as unlike jsx, markup is a string, so there is no reserved keyword to handle.
But in the same time they also want to be react-compatible, react only supports className.

@ngryman
Copy link
Contributor

ngryman commented Mar 5, 2017

Either you could patch your code to revert className to class or we could file hyperx an issue to ask them if it's possible to add some kind of opt-in for this transform.

@jorgebucaran
Copy link
Owner

🤔 That seems like out of the scope of Hyperx.

@jorgebucaran
Copy link
Owner

jorgebucaran commented Mar 5, 2017

Either you could patch your code to revert className to class or we could file hyperx an issue to ask them if it's possible to add some kind of opt-in for this transform.

Sounds like a plan: choojs/hyperx#48.

@tunnckoCore
Copy link
Author

hallelujah

@ngryman
Copy link
Contributor

ngryman commented Mar 9, 2017

@jbucaran Another issue related to this one is that for svg elements only classname attribute is kept so it's basically impossible to style svg elements for now 😢

I have a feeling the hyperx issue may take some time to resolve, should we implement a temporary fix that just reverts className to class?

@jorgebucaran
Copy link
Owner

@ngryman You against JSX?

@jorgebucaran
Copy link
Owner

@ngryman I can get that, so then why not fork hyperx, fix the issue (send a PR along upstream too) and use your fork in the meantime.

@ngryman
Copy link
Contributor

ngryman commented Mar 9, 2017

@jbucaran Good idea.
Haha I'm not against jsx but in the quest of a minimal setup with es6 native solutions ⚔️

@ngryman
Copy link
Contributor

ngryman commented Mar 9, 2017

@jbucaran fyi choojs/hyperx#49

@ngryman
Copy link
Contributor

ngryman commented Mar 10, 2017

PR has been merged and starting from hyperx 2.2.0 you can now disable this:

const { h, app } = require("hyperapp")
const hyperx = require("hyperx")
const html = hyperx(h, { attrToProp: false })

@jorgebucaran
Copy link
Owner

Good job @ngryman! 🍟 🍔

@jorgebucaran
Copy link
Owner

jorgebucaran commented Mar 10, 2017

@ngryman How would a PR for hyperapp that deals with this look like?

const html = hyperx(h, { attrToProp: false })

it's kinda ugly. Maybe we can take care of it for all the Hyperx-folk using hyperapp :)

@ngryman
Copy link
Contributor

ngryman commented Mar 10, 2017

I totally agree it's ugly 😢

TBH if we think about the full boilerplate, it is kinda heavy too:

import { h } from 'hyperapp'
import hyperx from 'hyperx'

const html = hyperx(h)

We should find a solution to wrap and expose this in some way.

Peer dependency

We could reference hyperx as a peer dependency and then export a helper html:

// html.js

import { h } from 'hyperapp'
import hyperx from 'hyperx'

export default hyperx(h, { attrToProp: false })

So now we can simply do:

import { html } from 'hyperapp'

New package

We could create something like hyperapp-hyperx and do the same. It's not my favorite but it preserves SoC.

@jbucaran If you have other ideas? I don't know how others deal with this.

@jorgebucaran
Copy link
Owner

We could reference hyperx as a peer dependency and then export a helper html:

It was like that when I first released the project. The problem is: I couldn't find a way to support both Hyperx and JSX in an unopinionated way.

There may be other template literal or JSX-like libraries in the future and I'd like to support them all if possible.

@jorgebucaran
Copy link
Owner

@ngryman

TBH if we think about the full boilerplate, it is kinda heavy too:

import { h } from 'hyperapp'
import hyperx from 'hyperx'
const html = hyperx(h)

There's no way about it unless we make other compromises. I tried something, but was ignored too.

See: https://github.com/substack/hyperxify/pull/8

@ngryman
Copy link
Contributor

ngryman commented Mar 10, 2017

I get it, why not something like installing any template function and then get it via hyperapp?
Naming is subject to change but this is the core idea.

This would be called once to install the template function, in index.js for example:

import { app } from 'hyperapp'
import hyperx from 'hyperx'

app(/*...*/, template: hyperx)

And would be used like this in the views:

import { html } from `hyperapp'

@jorgebucaran
Copy link
Owner

jorgebucaran commented Mar 11, 2017

@ngryman Thanks, but there's absolutely no way to go around the hyperx boilerplate, and I tried to address that in substack/hyperxify#8.

Even if we export an html module out of the box, the boilerplate will have to be written somewhere, and worse, it will be impossible to use hyperxify to remove the hyperx parser from your application bundle.

The reason for the current boilerplate is not to "punish" hyperx users, on the contrary, it's to make using hyperx with hyperapp not suck (consider the alternative, sending the entire parser down the wire, not to mention it's slow, but the bytes!).

Finally, I think the syntax you've proposed doesn't work with JSX either, so that would certainly punish JSX, which whether we like it or not, are most likely the majority.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants