So as we all know, HTML is case insensitive. myProp="123"
gets parsed as myprop="123"
and this has led to the caveat in Vue.js where you have to use my-prop="123"
to refer to a prop declared in JavaScript as myProp
. This bites beginners quite often.
In addition, we also need to apply the same mapping to custom components - e.g. when you define a component:
import MyComponent from './my-component'
export default {
components: {
MyComponent // es2015 shorhand
}
}
You must use <my-component>
in the template instead of <MyComponent>
.
The annoying part here is because Vue.js relies on the browser to pre-parse the templates, by the time Vue.js gets to compile it, the case information is already lost.
What if we adjust the matching logic so that things would just work? For example, making this possible:
<MyComponent :myProp="msg"></MyComponent>
In addition to eliminating the camelCase vs kebab-case inconsistency in our code, there are a few practical reasons why we would prefer PascalCase/camelCase for components and props:
myProp
vs. this['my-prop']
)import MyComp from './my-comp'
but my-comp
is simply not a valid variable name. And with the ES2015 object literal shorthand you can just do components: { MyComp }
.The underlying implementation is that when we process the props and component options, we normalize them into lowercase. This way, they simply become mycomponent
and myprop
during internal matching process, but you can still use the desired case in your app code. (In fact users don't even need to know about these internals)
Potential concerns:
myProp
and MyProp
will be treated as the same thing in the template. However, it doesn't make any sense to have two props or two components in the same component differentiated only by case, and we can easily detect and warn against such usage.html
<MyComponent @myEvent="handleIt"></MyComponent>
This basically means event names become case-insensitive, which has a bigger implication than props and component names because this affects event system usage in pure javascript. Does it make sense to normalize all event names into lowercase? Again, it seems rare to have two events differentiated only by case (e.g. having both myEvent
and myevent
in the same app that do different things), but I do want to get feedback on this.
<MyComponent :myProp="msg"></MyComponent>
+
I often want to write that way to see difference between the components and tags
+1
Does it make sense to normalize all event names into lowercase?
Yes! It makes sense, because it makes code more readable. I always keep event names lowercase, separate them by dash, instead of camelcase. I think adding warning for camelcase event names would be also good.
Does this means that Vuejs will be moving away from the HTML spec pursing a similar approach like Angular?
Is there some performance concern?
A couple thoughts on the potential concerns:
var CamelCase
would refer to a class and var camelCase
would refer to a non-class variable, var camelCase = new CamelCase();
. But, I don't think this would be an issue, because you wouldn't want to be creating classes that were named after your components.My biggest concern is introducing weird inconsistencies with how people code. For example, all of these are valid and identical: :myprop=""
:myProp=""
:mYpRoP=""
:my-prop=""
.
👎 Keep kebab-case in the markup and camel case in the code. It's part of the HTML spec and ignoring case will be a greater learning curve for those coming from other frameworks or who have already learned the standard.
I agree with @Teevio, consistency will be lost
HTML uses kebab-case & it's an accepted community standard that ECMAScript is a camelCase language. We should keep them separate instead of _hiding_ (In react the only way you can get react to render custom attribute is via data-* & aria-*, which enforces consistency).
Explaining why (say via MDN link or even here) camelCase <-> kebab-case to a _beginner_ will greatly help the beginner's HTML understanding.
Agree with Evan, readability and code consistency is more important!
+1
To me it will look really weird to have camelCase inside HTML.
HTML is HTML, JS is JS
current version is just fine
Having been using Vue for 6 months, that - still gets me everytime :( not a big deal as the warning for Vue are so good I know what I did, but I can fully understand the idea here, and support it +1
+1 Backwards compatibility too.
+1
I agreed. we need to keep the backwards compatibility.
Does it make sense to normalize all event names into lowercase?
I agree with @azamat-sharapov
@Teevio Vue components are roughly classes: when you do var MyComp = Vue.extend({ .. })
you can then do var myComp = new MyComp()
. As for the multiple valid syntax issue, it already exists: :my-prop
, :MY-PROP
and :mY-pRop
all work the same as of now, because HTML simply throws away all case information. It's not much different with the proposed feature. Like with all style arguments, it's all about picking a style and stick with it.
Re @jamesxv7 @moe-szyslak @jonagoldman and others that have concerns about moving away from HTML standard: it's totally valid to write camelCase tags/attributes in HTML, it's just the tag/attribute name matching will be performed in a case-insensitive manner. This is what the spec says:
In documents in the HTML syntax:
Tag names for HTML elements may be written with any mix of lowercase and uppercase letters that are a case-insensitive match for the names of the elements given in the HTML elements section of this document; that is, tag names are case-insensitive.
Attribute names for HTML elements may be written with any mix of lowercase and uppercase letters that are a case-insensitive match for the names of the attributes given in the HTML elements section of this document; that is, attribute names are case-insensitive.
So, if using PascalCase/camelCase improves code consistency/readability, it's totally spec-compliant to do so. This may not be for everyone, but if you prefer kebab-case you can keep using that.
And in particular, re @jamesxv7: this is different from what Angular 2 is doing. Angular 2 is making their templates case-sensitive by introducing a customized HTML parser. On the contrary Vue actually follows the spec by making the JS counterparts case-insensitive.
I prefer keeping kebab in html. I like the idea of consistency but I like the idea of spec compliance more.
Found camelCase tag:
. HTML is case-insensitive. Use instead. Vue will automatically match it against components defined with camelCase ids in JavaScript.
This warning is already pretty concise as to how component registration works. That said, as others have mentioned, I think allowing camelCase in HTML is great, as long there's still the option to continue writing kebab.
@yyx990803 yah, agreed. Just trying to think up as many arguments as I could against it, but honestly I don't have any that would stick. Like you mentioned, at the end of the day we're arguing stylistic choices. I personally think that as long as we can stick with what we already have while having the option to use the new stuff (but not forced to) I'm cool with the changes mentioned.
If kebab-case still works and using camelCase/ PascalCase are an option that don't break BC, when I use them, then I can't be against the addition. It isn't a change that forces me to do something different. It's just a new option.
The only thing I could say or suggest is to make sure this option is well documented and - Good work, as always Evan!
Scott
Maybe we can make an option out of it: warning or ignoring.
Say I have a component: myComponent
and I refer to it in html as mycompOnent
I personally would prefer a warning, like:
we found something that would match "myComponent": "mycompOnent" (line 152), use "my-component" instead
The same for props of course.
I think later-on-readabilty is more important than very thing working on the first try.
I also stumbled upon kebab-case/camelCase problems. But the real problem was I got no warnings what was wrong ;)
Default could be that there is no warning and it just works, that's irrelevant for me.
Also the warnings should be visible only in debug mode I think
What about things like atone
vs a-tone
vs at-one
? I imagine they are quite rare occurrences though.
@simplesmiler kebab case props would still be matched with case-sensitivity using old rules.
This doesn't promote transparency to web standards. The custom elements spec states that names should contain a hypen: <my-component/>
What about what @simplesmiler said: addOne
and adDone
would execute the same code. This would be especially nasty for the implementation for events,
And because html is case insensitive, lets not introduce the idea of casing from the library. This implementation would only promote casing in html, which in my opinion is a bad idea.
Also, we use hypen separation in file names. Should we remove them there as well, and start adding casing?
Lastly: having the hypen & casing system co-exist promotes different coding styles for new developers on a team.
I prefer @paulpflug's approach; Proper warnings in this area would help a lot.
I'm not a fan of making the HTML Pascal/Camel case. It breaks web standards, I know it's nice to keep consistency.
By trying to make things the tiniest bit consistent you add another layer of complexity. It may also be enticing bad practices. A library should promote staying to the standards and not mislead developers, as one day they may have to work in a place not using Vue, resulting in not understanding why the HTML is being parsed differently.
I totally agree with @paulpflug: Adding a warning means less work for production code and puts developers back on track to writing valid code.
A good argument case as to why this shouldn't be implemented: http://eisenbergeffect.bluespire.com/on-angular-2-and-html/
This is commonly a highlighted reason people dislike Angular 2. I agree totally with keeping libraries conforming to standards. It was once drafted for HTML to be case sensitive, and it was thrown out because of too many issues and opening up situations of too much flexibility.
@jamesxv7 That comment sums it up pretty well; Evan is not proposing changing HTML spec, he's proposing changing how Vue locates component names. Rather than convert kebab to camel and finding the matching component it would probably strip dashes (to accommodate kebab) and then search components with no case sensitivity. The HTML itself will continue to be spec compliant. It also would allow us to use whatever case we want. This seems like not an evil or bad choice to me :)
@yyx990803 do you plan the <MyComponent>
style to be the promoted style (i.e. docs and examples will be written like this), or it will be just an option, and kebab-case style will remain the primary one?
@blake-newman do read this comment - it does conform to the standard :)
@paulpflug @guidobouman : there already are warnings for camelCase tags and attributes if you are using latest versions of vue-loader
or vueify
. However, the camelCase checks must be performed at compile time because at runtime the case information would have already been lost due to the HTML parser behavior. So if you are using Vue without vue-loader
or vueify
, there won't (and can't) be any warnings.
@yyx990803 - But, the spec @blake-newman linked to for web components does state this:
The custom element type identifies a custom element interface and is a sequence of characters that must match the NCName production, must contain a _U+002D HYPHEN-MINUS character_, and _must not contain any uppercase ASCII letters_.
I am just not too sure how that relates to Vue components. In the docs, you do say, you try to loosely follow the web components standard.
You may have noticed that Vue.js components are very similar to Custom Elements, which is part of the Web Components Spec. In fact, Vue.js’ component syntax is loosely modeled after the spec.
So, I'd say the spec needs to change first, in order to allow camelCase and PascalCase.
Scott
@smolinari the Vue docs say that it is 'loosely modeled' not 'strictly' and in my mind that leaves room for this change.
@yyx990803 the case information may be lost, but there could still be a warning.
When I wrote 'mycOmponent' in the template it will be parsed to mycomponent
but expected is my-component
then Vue (in debug mode) should look for mycomponent
besides my-component
and warn me about the wrong usage. The lost case information doesn't matter here.
There could be an option to suppress the warning and match directly instead (equals your suggested behavior).
-1 to migrating to camelCase/PascalCase. It would be somewhat jarring to see JS-like syntax in HTML. Same reason why I cannot stand jsx.
+1 to @paulpflug's suggestion. If the problem is onboarding beginners, why not just issue a warning that informs the user of the problem?
@paulpflug that does sound like a valid idea!
I agree, having a warning that says 'mycomponent' is missing, did you mean 'my-component'?
feels better than silent substitution.
@yyx990803 Is it possible to do this on a global option api?
eg
Vue.config.kebab = true
(by default) -> <my-component :my-prop="msg"></my-component>
Vue.config.kebab = false
-> <MyComponent :myProp="msg"></MyComponent>
@yyx990803
just wondering, what is the ideal we are striving for?
as @rpkilby said, <MyComponent myCustomProp="myProp" data-name="prop" aria-label="Close" onclick="myDialog.close()">
looks weird.
Essentially, the problem exists because js and html are different technologies and use different naming systems. And using same case(kebab or camel) in both technologies will shift weirdness from one place to another but the underlying problem will persist
So I believe, best we can do is draw a line. and the current line i,e. kebab case in html context and camleCase (and PascalCase) in js context is very good.
so IMO, we should just support current conventions instead of looking for a better one. And ofcourse, use warning to help beginners
@prog-rajkamal yeah, I'm now inclined to just implement the warning.
I now vote :+1: on just adding the warning too.
Scott
:+1: for adding a warning
:+1: for the warning too
Closed via ccf9bede6bc39fb62e43e1efe98136c5f35dae6b & d7b55c4ee8491dbd853e28a1527050d2d1e7deab
A warning would be great. I just spent an hour trying to figure out why my custom event wasn't be responded to (the answer being it had a camel cased name).
There's a warning when you have a corresponding component or prop that would respond to the kebab-case
version of your PascalCase
component or prop. If you make a typo in an event there's not much Vue can do about that.
Or do you mean for default existing event props like v-on:keyup
or @keyup
in short?
@guidobouman in my template file I had <my-component v-on:customEvent="myMethod">
. In a child component I had this.$emit('customEvent');
. The actual event being listened to by the parent is customevent
not customEvent
, of course, but it took me ages to figure that out because it's not easy to debug. I was thinking it would have been good to warn that a camel case attribute would not be parsed as such, for forgetful folk like me. Perhaps this has already been discussed above, and if so I apologize.
@anthonygore unfortunately it's impossible, because browser converts html to lowercase before Vue has a chance to access it.
My question is, why does Vue cannot convert it for us? Why do we have to remember about kebab-case in in vue files? It makes things more awkward for beginners... I just wasted last 20 mins for that...
The one rule to commit to memory: HTML = kebab-case, JavaScript = camelCase
By HTML I mean attributes and tags. Attribute values are JavaScript expressions when you use v-bind
, so the second statement applies.
My question is, why does Vue cannot convert it for us? Why do we have to remember about kebab-case in in vue files? It makes things more awkward for beginners... I just wasted last 20 mins for that...
wasted last 1.5hr because I didn't just google it... dxmn
Most helpful comment
The one rule to commit to memory:
HTML = kebab-case, JavaScript = camelCase
By HTML I mean attributes and tags. Attribute values are JavaScript expressions when you use
v-bind
, so the second statement applies.