DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. JavaScript
  4. How to Publish Your Vue.js Component on NPM

How to Publish Your Vue.js Component on NPM

If you've built a Vue.js component, check out this tutorial to learn how to share it with other developers by packaging and publishing it on NPM.

Anthony Gore user avatar by
Anthony Gore
CORE ·
Feb. 04, 20 · Tutorial
Like (7)
Save
Tweet
Share
14.22K Views

Join the DZone community and get the full member experience.

Join For Free

You've made an awesome component with Vue.js that you think other developers could use in their projects. How can you share it with them?

In this article, I'll show you how to prepare your component so that it can be packaged and published on NPM. I'll use an example project and demonstrate the following:

  • Ensuring dependencies are not included in the package
  • Using Webpack to create separate builds for the browser and Node
  • Creating a plugin for the browser
  • Important configuration of package.json
  • Publishing on NPM

Case Study Project: Vue Clock

I've created this simple clock component which I'm going to publish on NPM. Maybe it's not the coolest component you've ever seen, but it's good enough for a demonstration.

Final output (clock app)

Final output (clock app)


Here's the component file. There's nothing too special here, but note that I'm importing the moment library in order to format the time. It's important to exclude dependencies from your package, which we'll look at shortly.

Clock.vue

HTML
 




xxxxxxxxxx
1
24


 
1
<template>
2
  <div>{{ display }}</div>
3
</template>
4
<script>
5
  import moment from 'moment';
6

          
7
  export default {
8
    data() {
9
      return {
10
        time: Date.now()
11
      }
12
    },
13
    computed: {
14
      display() {
15
        return moment(this.time).format("HH:mm:ss");
16
      }
17
    },
18
    created() {
19
      setInterval(() => {
20
        this.time = Date.now();
21
      }, 1000);
22
    }
23
  }
24
</script>



Key Tool: Webpack

Most of what I need to do to prepare this component for NPM is done with Webpack. Here's the basic Webpack setup that I'll be adding to in this article. It shouldn't include many surprises if you've used Vue and Webpack before:

webpack.config.js

JavaScript
 




xxxxxxxxxx
1
38


 
1
const webpack = require('webpack');
2
const path = require('path');
3

          
4
module.exports = {
5
  entry: path.resolve(__dirname + '/src/Clock.vue'),
6
  output: {
7
    path: path.resolve(__dirname + '/dist/'),
8
    filename: 'vue-clock.js'
9
  },
10
  module: {
11
    loaders: [
12
      {
13
        test: /\.js$/,
14
        loader: 'babel',
15
        include: __dirname,
16
        exclude: /node_modules/
17
      },
18
      {
19
        test: /\.vue$/,
20
        loader: 'vue'
21
      },
22
      {
23
        test: /\.css$/,
24
        loader: 'style!less!css'
25
      }
26
    ]
27
  },
28
  plugins: [
29
    new webpack.optimize.UglifyJsPlugin( {
30
      minimize : true,
31
      sourceMap : false,
32
      mangle: true,
33
      compress: {
34
        warnings: false
35
      }
36
    })
37
  ]
38
};



Externals

The externals configuration option provides a way of excluding dependencies from the Webpack output bundle. I don't want my package to include dependencies because they will bloat its size and potentially cause version conflicts in the user's environment. The user will have to install dependencies themselves.

In the case study project, I'm using the moment library as a dependency. To ensure it doesn't get bundled into my package, I'll specify it as an external in my Webpack configuration:

webpack.config.js

JavaScript
 




xxxxxxxxxx
1


 
1
module.exports = {
2
  ...
3
  externals: {
4
    moment: 'moment'
5
  },
6
  ...
7
}



Environment Builds

In Vue.js, there are two different environments where a user might want to install a component. Firstly, the browser e.g.

HTML
 




xxxxxxxxxx
1


 
1
<script type="text/javascript" src="vue-clock.js"></script>



Secondly, Node.js-based development environments e.g.

JavaScript
 




xxxxxxxxxx
1


 
1
import VueClock from 'vue-clock';



Ideally, I want users to be able to use Vue Clock in either environment. Unfortunately, these environments require the code to be bundled differently, which means I'll have to set up two different builds.

To do this, I'll create two separate Webpack configurations. This is easier than it sounds because the configurations will be almost identical. First I'll create a common configuration object, then use webpack-merge to include it in both environment configurations:

webpack.config.js

JavaScript
 




xxxxxxxxxx
1
27


 
1
const webpack = require('webpack');
2
const merge = require('webpack-merge');
3
const path = require('path');
4

          
5
var commonConfig = {
6
  output: {
7
    path: path.resolve(__dirname + '/dist/'),
8
  },
9
  module: {
10
    loaders: [ ... ]
11
  },
12
  externals: { ... },
13
  plugins: [ ... ]
14
};
15

          
16
module.exports = [
17

          
18
  // Config 1: For browser environment
19
  merge(commonConfig, {
20

          
21
  }),
22

          
23
  // Config 2: For Node-based development environments
24
  merge(commonConfig, {
25

          
26
  })
27
];



The common configuration is exactly as it was before (I've abbreviated most of it to save space), except I've removed the entry and output.filename options. I'll specify these individually in the separate build configurations.

Browser Bundle

Browsers can't import JavaScript modules from another file the same way a Node can. They can use a script loader like AMD, but for maximum ease, I want to allow my component script to be added more simply as a global variable.

Also, I don't want the user to have to think too hard to figure out how to use the component. I'll make it so the component can easily be registered as a global component when the user includes the script. Vue's plugin system will help here.

The result I'm aiming for is this simple setup:

index.html

HTML
 




xxxxxxxxxx
1


 
1
<body>
2
<div id="app">
3
  <vue-clock></vue-clock>
4
</div>
5
<script type="text/javascript" src="vue-clock.js"></script>
6
<script type="text/javascript">
7
  Vue.use(VueClock);
8
</script>
9
</body>



Plugin

First, I'll create a plugin wrapper to allow for easy installation of the component:

plugin.js

JavaScript
 




xxxxxxxxxx
1


 
1
import Clock from './Clock.vue';
2

          
3
module.exports = {
4
  install: function (Vue, options) {
5
    Vue.component('vue-clock', Clock);
6
  }
7
};



This plugin registers the component globally, so the user can call the clock component anywhere in their application.

Webpack Configuration

I'll now use the plugin file as the entry point for the browser build. I'll output to a file called vue-clock.min.js as that'll be most obvious to the user.

JavaScript
 




xxxxxxxxxx
1


 
1
module.exports = [
2
  merge(config, {
3
    entry: path.resolve(__dirname + '/src/plugin.js'),
4
    output: {
5
      filename: 'vue-clock.min.js',
6
    }
7
  }),
8
  ...
9
];



Exporting as a Library

Webpack can expose your bundled script in a variety of different ways, e.g. as an AMD or CommonJS module, as an object, as a global variable etc. You can specify this with the libraryTarget option.

For the browser bundle, I'll use the window target. I could also use UMD for more flexibility, but since I'm creating two bundles already, I'll just confine this bundle for use in the browser.

I'll also specify the library name as 'VueClock'. This means that when a browser includes the bundle, it will be available as the global window.VueClock.

Plain Text
 




xxxxxxxxxx
1


 
1
output: {
2
  filename: 'vue-clock.min.js',
3
  libraryTarget: 'window',
4
  library: 'VueClock'
5
}



Node Bundle

To allow users to use the component in a Node-based development environment, I'll use the UMD library target for the Node bundle. UMD is a flexible module type that allows code to be used in a variety of different script loaders and environments.

JavaScript
 




xxxxxxxxxx
1
14


 
1
module.exports = [
2
  ...
3
  merge(config, {
4
    entry: path.resolve(__dirname + '/src/Clock.vue'),
5
    output: {
6
      filename: 'vue-clock.js',
7
      libraryTarget: 'umd',
8

          
9
      // These options are useful if the user wants to load the module with AMD
10
      library: 'vue-clock',
11
      umdNamedDefine: true
12
    }
13
  })
14
];



Note that the Node bundle uses the single-file component as its entry point and does not use plugin wrapper, as it is not needed. This allows a more flexible installation:

JavaScript
 




xxxxxxxxxx
1


 
1
import VueClock from 'vue-clock';
2

          
3
new Vue({
4
  components: {
5
    VueClock
6
  }
7
});



package.json

Before publishing to NPM I'll setup my package.json file. A detailed description of each option is available on npmjs.com.

package.json

JSON
 




xxxxxxxxxx
1
16


 
1
{
2
  "name": "vue-clock-simple",
3
  "version": "1.0.0",
4
  "description": "A Vue.js component that displays a clock.",
5
  "main": "dist/vue-clock.js",
6
  "scripts": {
7
    "build": "rimraf ./dist && webpack --config ./webpack.config.js"
8
  },
9
  "author": "Anthony Gore",
10
  "license": "MIT",
11
  "dependencies": {
12
    "moment": "^2.18.1"
13
  },
14
  "repository": { ... },
15
  "devDependencies": { ... }
16
}



I've abbreviated most of this file, but the important things to note are:

1. The main script file i.e. "main": "dist/vue-clock.js". This points the Node bundle file, ensuring that modules loaders know which file to read i.e.

JavaScript
 




xxxxxxxxxx
1


 
1
import VueClock from 'vue-clock' // this resolves to dist/vue-clock.js



2. Dependencies. Since I've excluded any dependencies from the package, users must install the dependencies to use the package.

Publishing to NPM

Now that my component is set up correctly, it's ready to be published on NPM. I won't repeat the instructions here since they're covered nicely on npmjs.com.

Here's the result:

Publishing on npm

Publishing on npm


  • Github code
  • NPM page


Further Reading

  • Vue Tutorial 3 - Handling User Input.
  • Vue.js 2 Authentication Tutorial, Part 1.
Npm (software) Vue.js

Published at DZone with permission of Anthony Gore, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • The Real Democratization of AI, and Why It Has to Be Closely Monitored
  • The Top 3 Challenges Facing Engineering Leaders Today—And How to Overcome Them
  • How to Rescue Your Magento 2 Project
  • Hackerman [Comic]

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: