Initial Steps

We'll be developing our component with webpack. Now, configuring webpack alone is a daunting task, but luckily Vue creators provide us with a tool to make our lives easier. The tool is called vue-cli. Let's install it.

npm install -g vue-cli

Using vue-cli we can easily create an empty project with webpack set up out of the box so that you can jump right into development. Run the following command and answer all the prompted questions:

vue init webpack-simple vue-counter

This creates a new Vue project using the webpack-simple template. There's a more complex webpack template called webpack. It includes some extra stuff you don't necessarily need all the time and we won't cover it in this tutorial. Ok, now proceed to the just created folder and install all the required packages:

cd vue-counter
npm install

If you've never worked with webpack, what it essentially does is it builds multiple JavaScript modules (files) into a single file. Modules are or were not supported by (all the) browsers, depending on when you read this. Besides, it performs certain actions upon each module depending on the plugins you apply when building a single file. For example, it can convert the ES6 code into ES5 code so that all the browsers can read your code (although the ES6 support is already good at the moment), it can minify your code, and so on.

Anyway, you don't need to think about all of this since we're using a pre-defined template. Now, there are two commands available to build the project: npm run dev and npm run build. The first one starts a development server with hot module reloading (HMR) enabled and builds the project on the fly every time you edit and save a file. The other one builds a production version of the final build with minification.

If you're using Linux and HMR doesn't work on your system the way you'd expect to, the problem probably has to do with inotify and max_user_watches. The fix is described here.

Writing the Boilerplate Code

Alright, time to start developing our Vue component. src/ is the folder we will be working with. Let's delete the default files inside it - the assets/ folder and the App.vue file. Then we'll create our component file at src/Counter.vue with the following code:

<template>
    <div>Hello World!</div>
</template>

<script>
export default {

}
</script>

<style>

</style>

For now it's an empty component which simply outputs 'Hello World!'. Now open src/main.js and modify it as follows:

import Vue from 'vue'
import Counter from './Counter.vue'

Vue.component('counter', Counter);

new Vue({
  el: '#app'
})

export default Counter;

Here we're simply importing our component, registering it with Vue as <counter>, and then exporting it, which allows the users of our component to use it in a similar manner in their applications, namely:

import Counter from './Counter.vue'

Vue.component('counter', Counter);

Note that we've also deleted the render attribute from the Vue object because we don't want to render the component directly. Now open index.html - this is the file that the development server uses to display the result of our work (think of it as of a demo page for your package). We'll use our component the way our users would use it by adding an HTML element inside the #app div:

...
<div id="app">
    <counter></counter>
</div>
...

Run npm run dev - a development server should start and open a browser tab on your computer. You should see a blank page with 'Hello World!' at the top.

The Actual Development

Now you can start with the actual development of the component inside the src/Counter.vue file. This tutorial is not about how to develop using Vue.js per se, so I'll just give you the final code of our dummy component. Here it is:

<template>
    <div>
        <p>The current count is: {{ count }}</p>

        <p>
            <button @click="count++">Add one</button>
            <button @click="count = 0">Reset</button>
        </p>
    </div>
</template>

<script>
export default {
    data() {
        return {
            count: 0
        };
    }
}
</script>

Before Publishing

There are a few final steps before we can publish our package. Right now we have a stand-alone application which contains certain code we wouldn't need if we used it as a module/package.

First, open the package.json file and add this attribute somewhere:

"main": "src/main.js",

This is the entry point to your package. Without this line your package might not work inside other projects (you might get a "Can't resolve ..." error). Then, open .babelrc and replace the content of the file with this:

{
  "presets": [
    ["env", { "modules": false }]
  ]
}

Now the index.html file is used strictly for previewing results during the development process (at least in our case). If you want to keep it for the future development, open it and change the id of the <div id="app"> div to something else - something unique. This is important because if there is another div with the same id in a project, your package might re-initialize the Vue instance of the project it is used in.

Finally, let's open src/main.js and apply some of the initializations only in case an element with our custom id is present on the page.

import Vue from 'vue'
import Counter from './Counter.vue'

if (document.querySelector('#my-strictly-unique-id'))
{
    Vue.component('counter', Counter);

    new Vue({
        el: '#my-strictly-unique-id'
    });
}

export default Counter;

Another option is to delete the index.html file. The src/main.js file would look like this in that case:

export Counter from './Counter.vue'

Publishing an npm Package

When you've done developing you are ready to publish. Go to npmjs.com and create an account. Then on you local machine run npm login and enter your credentials. Alternatively, you could run npm adduser to create an account and to store the credentials on your machine at the same time.

Now, open your package.json file and take a look at the name attribute. Browse npmjs.com and make sure the name of your project is original - otherwise it won't let you publish it. If the name is used by someone else you should change it or prefix it with your username as a scope, for example @username/vue-counter.

Then, remove the "private": true, line. If you've uploaded your project to GitHub - tell npm about it by adding "repository": "https://github.com/your-login/your-repository".

Finally, when you're done, run npm publish and that's it! Your package is live now. Every time you make a change to your package you should increment its version in the package.json file (for example, from "1.0.0" to "1.0.1") and run npm publish again.