How to share Vue components between multiple projects

Avoid code duplication in your Vue-based projects by sharing components and libraries without using a 3rd-party service or symlinks.

As software developers we tend to nit-pick about code organization, efficiency of logic and naming things. Every time we have to work with a new framework, these same issues come up and we need a method to solve them. I’ve been creating quite a few VueJs-based widgets lately and found myself creating the same components for each of them. Obviously, it drove me nuts that I was duplicating the same component into multiple projects. After some research and many billable hours wasted trying to figure this out, I came upon a solution that would allow me to share a common directory of components and helpers in each of many separate Vue apps.

No 3rd-party service needed
No Symlink directories required

Let’s jump right in with a sample application structure shown within PhpStorm. I’m sure you’ll have a different setup than I’m describing here, but the concept is the same regardless.

Since I’m assuming you’re already familiar with creating a Vue app, I won’t be going into any detail on that.

These are the important parts to get this working:

  • A shared directory with your common components and/or libraries.
  • Multiple app directories with their own Vue app.
  • Webpack aliases that map the correct paths and modules.
  • A config file to help PhpStorm handle intellisense.

Once these things are in place you’ll be able to achieve an app component that uses shared imports like this:

<template>
  <div>
    <kicker>Tips & Tricks</kicker>
    <headline>Shared Components</headline>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias animi assumenda beatae debitis dolorem error id
      modi totam. Atque culpa dolor error expedita in itaque, nesciunt nihil quae repellat voluptatum.</p>
  </div>

</template>

<script>

import {ref} from 'vue';
import Kicker from '@shared/components/Kicker';
import Headline from '@shared/components/Headline';

export default {
  name: 'App',
  components: {Kicker, Headline},
  setup(){

    const foo = ref(false);

    return { foo };
  }
};
</script>

Okay, so assuming you’re project is setup with all of the correct Vue/npm goodness, I’ll post my package.json file here so you can reference my dependency setup and copy any missing packages into your own:

{
  "name": "widget-1",
  "version": "1.0.0",
  "description": "",
  "main": "src/app.js",
  "scripts": {
    "dev": "mix",
    "watch": "mix watch",
    "prod": "mix --production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "laravel-mix": "^6.0.39",
    "vue": "^3.2.26",
    "vue-loader": "^16.8.3"
  }
}

We’re using the convenient laravel-mix npm package here. Create a webpack.mix.js file in one of your app’s root directory. Open it up and paste this config:

const path = require('path');
let mix = require('laravel-mix');

/**
 * mix.alias = webpackConfig.resolve.alias:
 *
 * -- @shared: Setup shortcut to common files
 * -- vue$:    Force all components to use local project instance of VueJs
 */

mix.alias(
	{
		'@shared': path.join( __dirname, '../_shared' ),
		'vue$': path.join( __dirname, 'node_modules/vue/dist/vue.esm-bundler.js' )
	}
).js('src/app.js', 'dist/')
.sourceMaps(false, 'eval-source-map')
.vue({ version: 3});

The mix.alias block is the key to making this technique work. You can rename the @shared alias to whatever you like. The vue$ alias forces all *.vue files in directories outside this app to use the vue and vue-loader in our local node_modules folder.

Now, this setup alone will allow your application to compile successfully (pending a npm install, of course).

This final tip will appease the annoying code validation in PhpStorm and basically trick it into recognizing your share alias keyword. In the outermost root of your Project, create a phpstorm.config.js file. Paste this config into your file and save:

/**
 * NOTE: This file helps provide intellisense for imported JS components located
 * within aliased directories.
 */
System.config({
	"paths": {
		"@shared/*":"./apps/_shared/*"
	}
});

Just make sure the aliased path matches your project structure.

That’s it for now. I hope you were able to successfully get shared components working in your multi-app project.