What is Vue.extend for?

This is a simple enough one, but I'm not getting the answer I need from the documentation. I'm in the process of learning Vue.js, and I don't really understand where Vue.extend fits in. I get Vue.component, but I don't see what Vue.extend does which Vue.component doesn't. Is it just a legacy feature from 1.0? If not, where is it useful in Vue 2.0?


Their guide in the previous Vuejs.org site had a document.

Copied from http://optimizely.github.io/vuejs.org/guide/composition.html which is forked from vuejs/Vuejs.org at version 0.10.6 of Vuejs.

It is important to understand the difference between Vue.extend() and Vue.component(). Since Vue itself is a constructor, Vue.extend() is a class inheritance method. Its task is to create a sub-class of Vue and return the constructor. Vue.component(), on the other hand, is an asset registration method similar to Vue.directive() and Vue.filter(). Its task is to associate a given constructor with a string ID so Vue.js can pick it up in templates. When directly passing in options to Vue.component(), it calls Vue.extend() under the hood.

Vue.js supports two different API paradigms: the class-based, imperative, Backbone style API, and the markup-based, declarative, Web Components style API. If you are confused, think about how you can create an image element with new Image(), or with an <img> tag. Each is useful in its own right and Vue.js tries to provide both for maximum flexibility.


In addition to the answers provided, there is a practical use case for calling Vue.extend() directly if you are using TypeScript.

It is recommended in most cases to import component definitions from other files when they are needed, instead of registering them globally with Vue.component(). It keeps things organized in larger projects and makes it easier to trace problems.

With the right library, TypeScript can look at your component definition and figure out what the type of the component will be when it's initialized, meaning it can then check the functions you've defined to see if they make sense (i.e. if you reference this.foo there is actually a prop, data field, computed value, or method named foo). If you use Vue.component() it will be able to do this, but not if you use the other typical way of making components available, which is exporting object literals.

However, another option is to export your component definitions wrapped in Vue.extend(). TypeScript will then be able to recognize it as a Vue component and run its type checking accordingly, but you won't have to abandon the best-practice pattern of exporting components rather than registering them globally.


I think the confusion is because extend & component are closely connected. To create a component Vue calls extend internally:

// register an options object (automatically call Vue.extend)
Vue.component('my-component', { /* ... */ })

Therefore you can use extend to mount a subclass of the base Vue constructor (a component constructor): https://vuejs.org/v2/api/#Vue-extend

However you are unlikely to come across or need to go down this road. Instead you'll be using components to get named subclasses which you can easily reference within your application.

Therefore Extend isn't really a "legacy" feature, it is central to Vue components, but the added sugar that components provide make them the default way you'll be working.


The documentation for Vue v2 is a bit sparse on Vue.extends but in short:

You use Vue.extend to create component definition (called "component constructor" in old documentation) and Vue.component to register it so it can be used in template to actually create component instance.

<div id="example">
  <my-component></my-component>
</div>
// define
var MyComponent = Vue.extend({
  template: '<div>A custom component!</div>'
})
// register
Vue.component('my-component', MyComponent)
// create a root instance
new Vue({
  el: '#example'
})

However, everywhere in Vue API where you can pass "component constructor" created by Vue.extend you can pass plain object instead and it will call Vue.extend for you.

So the previous example can be written as

// define
var MyComponent = {
  template: '<div>A custom component!</div>'
}
// register
Vue.component('my-component', MyComponent)
// create a root instance
new Vue({
  el: '#example'
})

It seams that people now prefer to define components just as plain JS object (called options object in Vue world).

You can see that in current documentation for Vue v2 you rarely see Vue.extends mentioned while in docs for v1 it is clearly explained in one of the first chapters that describes Vue Instance (compare it with v2) and very well explained in Components chapter. It is explicitly stated that passing options object directly is just a sugar.

My guess is, to keep it simple and easier to learn, the new documentation just use plain objects everywhere. Why explain additional concept like "Vue constructor function", "component constructor" and what is Vue.extend when 99% of time you don't need to understand it? You can define all your app's components with plain JS options objects and register them without using Vue.extends. The only place when you must use vue constructor function is when creating root Vue instance with new Vue({...}). This uses base Vue constructor function. You don't need to know that Vue constructor can be extended to create reusable component constructors with pre-defined options because although you can create extended instances imperatively, in most cases you will be registering a component constructor as a custom element and composing them in templates declaratively.(source)

So documentation authors decided you don't need to learn about Vue.extends. But are there any use case where it's worth to use Vue.extend instead of plain options object?

Yes.

Typescript

If you want to use Typescript (and don't like class-style components) then to have proper type inference you should use Vue.extend instead of plain objects. It uses ThisType<T> feature to get proper inference for this object.

image showing code with Vue.extend function where we see it's recognized by Typescript

Component inheritance (and Typescript again)

You can use .extend not only on base Vue constructor function, but also on your custom component. This is less flexible than mixins because you can use many mixins in component and .extend approach works just with one component. However, it works better with Typescript for which mixins seems to not play well. With .extend Typescript support is probably "good enough" for many cases. You can access fields from inherited component but if your component have some names collision with "base" component then it doesn't work well (for example I get a type of never for conflicting props' names).

<div id="appBar">
    {{fooMessage}} || {{barMessage}} || {{ additionalData}}
    <button v-on:click="changeAllMessages">Change</button>
</div>
var FooComponent = Vue.extend({
    data: () => ({
        fooMessage: 'Foo message'
    }),
    methods: {
        changeFooMessage() {
            this.fooMessage = "Foo message changed";
        }
    }
})
var BarComponent = FooComponent.extend({
    data: () => ({
        barMessage: "Bar message",
    }),
    methods: {
        changeAllMessages() {
            this.barMessage = "Bar message changes";
            this.changeFooMessage();
        }
    }
});
new BarComponent({ el: "#appBar", data: { additionalData: "additional data passed" } });

Here I also showed that you can use you custom component to create root Vue instance (new BarComponent({...})). Same like you can do with new Vue({...}). Maybe it's not that useful but it shows that BarComponent and FooComponent are just extended base Vue constructor functions and you can use it the same way as you would use Vue.