/ xiegerts / blog

Consolidating components into a Vue.js plugin

March 11, 2019

At this point, we have a structured approach for creating new Vue.js components and consolidating them into a single module export. Awesome! Next, we’ll bundle the components into a plugin to be registered on a Vue instance.

Remember that the Vue CLI creates a main.js entry point file in the root of the /src directory during the project initialization. Usually, that’s used as the entry point for a new Vue application. We’ll modify this to create the plugin.

If you’re landing on this post without reading the series introduction, jump there first.

main.js entry point

Starting off, let’s remove the generated code. We’ll replace with the differences below.

// main.js

- import Vue from 'vue'
- import App from './App.vue'

- Vue.config.productionTip = false

- new Vue({
-  render: h => h(App),
- }).$mount('#app')

+ import * as components from './components'
+
+ const ComponentLibrary = {
+  install(Vue, options = {}) {
+    // components
+    for (const componentName in components) {
+      const component = components[componentName]
+
+      Vue.component(component.name, component)
+    }
+  }
+ }
+
+ export default ComponentLibrary
+
+ if (typeof window !== 'undefined' && window.Vue) {
+  window.Vue.use(ComponentLibrary)
+ }

The file should look like:

// main.js

import * as components from './components'

const ComponentLibrary = {
  install(Vue, options = {}) {
    // components
    for (const componentName in components) {
      const component = components[componentName]

      Vue.component(component.name, component)
    }
  }
}

export default ComponentLibrary

if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(ComponentLibrary)
}

Let’s step through this 👀.

A Vue.js plugin should expose an install method…The method will be called with the Vue constructor as the first argument, along with possible options

In the above, componentName is not the same as component.name.
import Vue from 'vue'
import ComponentLibrary from './main.js'

Vue.use(ComponentLibrary)

...

Currently, the above set up does one thing - registering components. That’s all we need it to do now but there are different patterns for plugin creation and the library entry point, main.js, in this case.

A few examples include:

The outline prescribed in the Vue documentation for writing a plugin is:

// 1. add global method or property
Vue.myGlobalMethod = function () {
  // some logic ...
}

// 2. add a global asset
Vue.directive('my-directive', {
  bind (el, binding, vnode, oldVnode) {
    // some logic ...
  }
  ...
})

// 3. inject some component options
Vue.mixin({
  created: function () {
    // some logic ...
  }
  ...
})

// 4. add an instance method
Vue.prototype.$myMethod = function (methodOptions) {
  // some logic ...
}

Source: https://vuejs.org/v2/guide/plugins.html#Writing-a-Plugin

One last tip

Also, always remember to populate a name attribute in your components if using the Vue.component and component.name approach above. The registration will throw an error if component.name doesn’t exist.

<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
  export default {
    name: 'name-of-your-component' // 👈
  }
</script>

<style></style>

Give your components a name ☝️

Next up, tightening the feedback loop plus a hint of amazing documentation with VuePress 🌋.

👋 Related posts in the Vue Component Library series...