Vue.js - Making helper functions globally available to single-file components

vue.jsVuejs2Vue ComponentVuexVue Router

vue.js Problem Overview


I have a Vue 2 project that has many (50+) single-file components. I use Vue-Router for routing and Vuex for state.

There is a file, called helpers.js, that contains a bunch of general-purpose functions, such as capitalizing the first letter of a string. This file looks like this:

export default {
  capitalizeFirstLetter(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
}

My main.js file initializes the app:

import Vue from 'vue'
import VueResource from "vue-resource"
import store from "./store"
import Router from "./router"
import App from "./components/App.vue"

Vue.use(VueResource)

const app = new Vue({
  router: Router,
  store,
  template: '<app></app>',
  components: { App },
}).$mount('#app')

My App.vue file contains the template:

<template>
  <navbar></navbar>
  <div class="container">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // stuff
    }
  }
}
</script>

I then have a bunch of single-file components, which Vue-Router handles navigating to inside the <router-view> tag in the App.vue template.

Now let's say that I need to use the capitalizeFirstLetter() function inside a component that is defined in SomeComponent.vue. In order to do this, I first need to import it:

<template>Some Component</template>

<script>
import {capitalizeFirstLetter} from '../helpers.js'
export default {
  data() {
    return {
      myString = "test"
    }
  },
  created() {
    var newString = this.capitalizeFirstLetter(this.myString)
  }
}
</script>

This becomes a problem quickly because I end up importing the function into many different components, if not all of them. This seems repetitive and also makes the project harder to maintain. For example if I want to rename helpers.js, or the functions inside it, I then need to go into every single component that imports it and modify the import statement.

Long story short: how do I make the functions inside helpers.js globally available so that I can call them inside any component without having to first import them and then prepend this to the function name? I basically want to be able to do this:

<script>
export default {
  data() {
    return {
      myString = "test"
    }
  },
  created() {
    var newString = capitalizeFirstLetter(this.myString)
  }
}
</script>

vue.js Solutions


Solution 1 - vue.js

> inside any component without having to first import them and then prepend this to the function name

What you described is mixin.

Vue.mixin({
  methods: {
    capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1);
  }
})

This is a global mixin. with this ALL your components will have a capitalizeFirstLetter method, so you can call this.capitalizeFirstLetter(...) from component methods or you can call it directly as capitalizeFirstLetter(...) in component template.

Working example: http://codepen.io/CodinCat/pen/LWRVGQ?editors=1010

See the documentation here: https://vuejs.org/v2/guide/mixins.html

Solution 2 - vue.js

Otherwise, you could try to make your helpers function a plugin:

import Vue from 'vue'
import helpers from './helpers'

const plugin = {
  install () {
    Vue.helpers = helpers
	Vue.prototype.$helpers = helpers
  }
}

Vue.use(plugin)

In your helper.js export your functions, this way:

const capFirstLetter = (val) => val.charAt(0).toUpperCase() + val.slice(1);
const img2xUrl = (val) => `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;

export default { capFirstLetter, img2xUrl };

or

export default { 
  capFirstLetter(val) {
    return val.charAt(0).toUpperCase() + val.slice(1);
  },
  img2xUrl(val) {
    return `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;
  },
};

You should then be able to use them anywhere in your components using:

this.$helpers.capitalizeFirstLetter()

or anywhere in your application using:

Vue.helpers.capitalizeFirstLetter()

You can learn more about this in the documentation: https://vuejs.org/v2/guide/plugins.html

Solution 3 - vue.js

Create a new mixin:

"src/mixins/generalMixin.js"

Vue.mixin({
  methods: {
    capitalizeFirstLetter(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }    
  }
})

Then import it into your main.js like:

import '@/mixins/generalMixin'

From now on you will be able to use the function like this.capitalizeFirstLetter(str) within your component script or without this in a template. i.e.:

<template>
    <div>{{ capitalizeFirstLetter('hello') }}</div>
</template>

You have to use this because you mixed a method into the main Vue instance. If there are ways of removing this it will probably involve something unconventional, this at least is a documented way of sharing functions which will be easy to understand for any future Vue devs to your project.

Solution 4 - vue.js

> Using Webpack v4

Create a separate file for readability (just dropped mine in plugins folder). Reproduced from @CodinCat and @digout responses.

//resources/js/plugins/mixin.js
import Vue from 'vue';
    
Vue.mixin({
  methods: {
    capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1),
    sampleFunction() {
      alert('Global Functions');
    },
  }
});

Then, import in your main.js or app.js file.

//app.js
import mixin from './plugins/mixin';

USAGE:

Call this.sampleFunction() or this.capitalizeFirstLetter().

Solution 5 - vue.js

Use a global filter if it only concerns how data is formatted when rendered. This is the first example in the docs:

{{ message | capitalize }}
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

Solution 6 - vue.js

Great question. In my research I found vue-inject can handle this in the best way. I have many function libraries (services) kept separate from standard vue component logic handling methods. My choice is to have component methods just be delegators that call the service functions.

https://github.com/jackmellis/vue-inject

Solution 7 - vue.js

Import it in the main.js file just like 'store' and you can access it in all the components.

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  render: h => h(App)
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEge ErsozView Question on Stackoverflow
Solution 1 - vue.jsCodinCatView Answer on Stackoverflow
Solution 2 - vue.jsHammerbotView Answer on Stackoverflow
Solution 3 - vue.jsdigoutView Answer on Stackoverflow
Solution 4 - vue.jsDAVID AJAYIView Answer on Stackoverflow
Solution 5 - vue.jsellisdodView Answer on Stackoverflow
Solution 6 - vue.jsuser3525949View Answer on Stackoverflow
Solution 7 - vue.jsuser2090357View Answer on Stackoverflow