Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to encapsulate the common functionality in a Vuejs project? Best Practice

I am working with a mid size project utilizing Vuejs as the front-end. The options I am exploring to encapsulate / separate the common methods which may be used in many components include mixins approach and plugin approach.
Mixin Approach
I have to write an import statement in each of the component (file) where I want to use the mixin methods. Does this increase the final file size as the mixin will be imported at multiple places? I can use this within the mixin methods.

Plugin Approach
I can install the plugin globally with Vue.use(MyPlugin) and use the plugin in any component without importing the plugin in each component.
Drawback: I am not able to use this[field] within the plugin methods. I have to pass the instance of the calling component vm to use such methods.

Edit 1 - to include Extend Approach
Extend Approach
I can define a base component with all the methods which will have use in multiple other components and then extend this BaseComponent to create new components. Here again, I need to pass in the instance of the inheriting component , this used in the BaseComponent does not refer to the calling/inheriting component.

Please find the trivial example of code similar to what I am using below:

    //mixin.js
    var MyMixin = {
       methods:{
          getName(){
              return this.name;
          }
       }
    };
    export default MyMixin;  


    //plugin.js
    var MyPlugin = {};

    MyPlugin.install = function(Vue, options){
        var service = {
    	getTheName(){
    	    retrun this.name;
    	},
            getTheNameVersion2(vm){  //here vm is the instance of the calling component passed as a parameter - is this proper way?
                return vm.name;
            }  
        }
    	
        Vue.prototype.$service = service;
    };

    export default MyPlugin;



    //my-component.js
    import MyMixin from './mixin';
    export default{
        template:require('./my-component-template.html'),
        mixins:[MyMixin],
        data(){
            return{
    	    name:'John Doe'
    	}
        },
        methods:{
           displayNameFromMixin(){
              console.log(this.getName()); //displays John Doe - using the mixin method.
           },
           displayNameFromPlugin(){
              console.log(this.$service.getTheName()); //error "this" references the plugin instead of the component instance
           },
           displayNameFromPluginVersion2(){
               console.log(this.$service.getTheNameVersion2(this)); //this works - passing the instance as method parameter
           }
    }   
    
    //base-component.js  
    export default{
        methods:{
            getName(vm){
                return vm.name;
            }
        }
    }   
    
//another-component.js
import BaseComponent from './base-component';
BaseComponent.extend({
    template:require('./another-component-template.html'),
    data(){
        return{
            name:'Jack Daniels';
        }
    },
    methods:{
        getNameFromBaseComponent(){
            console.log(this.getName(this)); //displays Jack Daniels - instance passed as method parameter
        }
    }
});


    //main.js

    import Vue from 'vue';
    import MyPlugin from './plugin';
    import MyComponent from './my-component';
    import AnotherComponent from './another-component';

    Vue.use(MyPlugin);

    new Vue({
        el:'body',
        components:{
            MyComponent, AnotherComponent
        }
    });

My questions:

  1. Importing mixin file in every component (which requires the methods) is it an efficient way of doing it?
    Does importing mixin at multiple places (component files) include code of mixin file repeatedly and increase the file size?

  2. Passing the instance of the calling component vm = this as a parameter - Is it a good practice? Does passing around component instances as method parameters cause any efficiency issue?

  3. How to bind this (instance of the calling/inheriting component) to the methods within plugin and/or BaseComponent so that this refers to the calling/inheriting component instance rather than plugin/BaseComponent?

  4. Which approach is most effective with regards to performance, DRYness and file size?
like image 904
Donkarnash Avatar asked Jul 04 '16 06:07

Donkarnash


People also ask

What is the best way to create a constant that can be accessible from entire application in VueJS?

You can always define a variable outside of the Vue app scope and use it throughout the application. However, if you are using any bundler like Webpack/Browserify/etc. you can do the same but you'd have to import it into every component using it.

Should always be multi word VueJS?

Component names should always be multi-word, except for root App components, and built-in components provided by Vue, such as <transition> or <component> . This prevents conflicts with existing and future HTML elements, since all HTML elements are a single word.


1 Answers

what I prefer (someone would consider it not the best way but it is enough for me) is to create plugins.

So I have a file called vue-utils.js with the content (for example):

; (function () {
    var install = function(Vue, options) {
        Vue.prototype.$utils = {}

        var vm = new Vue({ data: Vue.prototype.$utils });

        Vue.prototype.$utils.validateEmail = function(value) {
            return /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(value);
        }
    }

    if (typeof exports == 'object') {
        module.exports = install;

    } else if (typeof define == 'function' && define.amd) {
        define([], function () { return install });

    } else if (window.Vue) {
        Vue.use(install);
    }
})();

I define the $utils first and then I create a new Vue instance with it so I transform any property to binded, and then define another properties and methods.

Then load it in the app this way:

import VueUtils from './plugins/vue-utils.js';
Vue.use(VueUtils);

And you will be able to reach the component in the HTML like $utils and in the JS by this.$utils

like image 167
ragnar Avatar answered Oct 13 '22 17:10

ragnar