Vue: Vue using wrong component when there're global and local components with same name but registered with different naming conventions

Created on 10 Dec 2016  路  14Comments  路  Source: vuejs/vue

JSFiddle: http://jsfiddle.net/fenivana/3y7hzwg8/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <x-foo/>
    </div>

    <script>
    Vue.component('x-foo', {
      template: '<div>global foo component will be used</div>'
    })

    new Vue({
      el: '#app',

      components: {
        XFoo: {
          template: '<div>local foo component won\'t show</div>'
        }
      }
    })
    </script>
  </body>
</html>

Most helpful comment

@JounQin Here is what happend internally. https://github.com/vuejs/vue/blob/8c0fac699a48ec62b25a94b4083ea1d75c52c236/src/core/util/options.js#L322

const res = assets[id] ||
    // camelCase ID
    assets[camelize(id)] ||
    // Pascal Case ID
    assets[capitalize(camelize(id))]

with [, it will check prototype chain, so first x-foo, then XFoo

So I think it might bring breaking change in some cases if we apply the new resolving strategy.

All 14 comments

change it to:

new Vue({
    el: '#app',
    components: {
      'x-foo': {
        template: '<div>local foo component won\'t show</div>'
    }
  }
})

x-foo and XFoo are different, it seems to be just a fallback when x-foo component not found.

^ As above

I exactly know changing to x-foo can solve the problem, but I think the fallback preference is wrong. It should find all naming conventions in local registered components first, If not found, then look into global components.

@yyx990803 @fnlctrl What do you think?

And how can I know what naming conventions the third party UI libraries are using? Will my local components with the same name conflict with theirs? Who knows.

And how can I know what naming conventions the third party UI libraries are using?

Why would it be relevant? You can always alias them inside the components options.

Consider the reverse scenario, where you want to override a third party component's local component x-foo, with your own globally registered component x-foo.

Anyway, you should always explicitly alias components if there is a potential naming conflict, and never rely on the fallback precedence.

Why would it be relevant? You can always alias them inside the components options.

The real scenario is, when we use a UI collection set. we simply import it and use it:

import SomeUI from 'some-ui'
Vue.use(SomeUI)

We don't need to care about whether it's registered with kebab-case, camelCase, or TitleCase.

If we register a local component , we simply do:

<template>
  <div>
    <tab-pane>something</tab-pane>
  </div>
</template>

<script>
import TabPane from './TabPane.vue'
export default {
  components: {
    TabPane
  }
}
</script>

But what if SomeUI also has a component named 'tab-pane', and it is registered with:

Vue.component('tab-pane', {...})

Then the local registered component will never be used.

We have to use a longer syntax:

export default {
  component: {
    'tab-pane': TabPane
  }
}

And what you said overriding a thirty UI's local component with a global component is a rare case, it's like a hack. And if it's local component is registered with kebab-case, you'd never had a chance.

And, the vue guide says:

When registering components (or props), you can use kebab-case, camelCase, or TitleCase.
Vue doesn鈥檛 care.

And you just told me vue cares about it, and we should care about it too!

And you just told me vue cares about it, and we should care about it too!

That's not what I said. Let me quote my words again:

You should always explicitly alias components if there is a potential naming conflict, and never rely on the fallback precedence.

In your case you're creating a component that has the same name of a 3rd party component, which should have been avoided in the first place, since it's you defining the local component and you have full control over its name.

Please don't play with words. What the fact is I registered a component with the wrong naming convention and Vue cares about it.

Please let @yyx990803 to end the dispute.

Yeah, you can say, it's not a bug, it's a feature, doc is wrong, not the code.

I think this is a bug, camel case and title case component name seems aliases rather than fallback. Practically, we use camel/title case to register local component (with ES6 object shorthand) since JavaScript does not allow kebab case as variable names.

And also, local component should not be overridden by global components. It can easily cause unexpected behavior and break capsulations of third party components.

Sounds reasonable, but maybe it will bring a breaking change.

What about using both of them (<x-foo/> and <XFoo/>) in one template, how could it render? Are they same?

@JounQin Here is what happend internally. https://github.com/vuejs/vue/blob/8c0fac699a48ec62b25a94b4083ea1d75c52c236/src/core/util/options.js#L322

const res = assets[id] ||
    // camelCase ID
    assets[camelize(id)] ||
    // Pascal Case ID
    assets[capitalize(camelize(id))]

with [, it will check prototype chain, so first x-foo, then XFoo

So I think it might bring breaking change in some cases if we apply the new resolving strategy.

Was this page helpful?
0 / 5 - 0 ratings