DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

amroessam
amroessam

Posted on

Publish Your First NPM Package (Vue) - PART 1

Hi Everyone,

It's me again 😊

So Fast forward 4 months from my first post

I've realised my article wasn't the most helpfulπŸ€¦πŸ½β€β™‚οΈ, as I didn't get into details on how I created my first NPM package.

In this post, I'm planning on doing so😁, I'll also try to cover how to get intelliSense working for a vue component in vscode.

For simplicity's sake, we're making a very minimal reusable alert component
We'll be using rollup to build

Let's get started πŸ˜ŽπŸ™Œ

1. Creating the component

We'll be using vue cli in this tutorial, so if you're unfamiliar with it, a great place to start would be vue's cli documentation

Open your favourite terminal and change directory into your projects directory

cd c:/projects

Now create a new project using vue cli

vue create simplealertcomponent

Select the default preset, wait till vue-cli creates all the necessary boilerplate files for you.

Change directory to the new folder that's made and launch your editor, I'm using vscode so...

cd simplealertcomponent && code .

This is the file structure you should have

.
β”œβ”€β”€β”€public
β”‚     favicon.ico
β”‚     index.html
└───src
    β”‚ App.vue
    β”‚ main.js
    β”œβ”€β”€β”€assets
    β”‚ logo.png
    └───components
      HelloWorld.vue

Delete everything inside the src folder so it's empty, also delete the public folder because we won't be needing it.

Now create entry.js file in the src folder, this will be the entry point to our application.

first we import our component, we'll be creating it later

import component from './SimpleAlert.vue'

Then, we're gonna register it into the vue instance if it exists

function install(Vue) {
  if (install.installed) return
  install.installed = true
  Vue.component('SimpleAlert', component)
}

const plugin = {
  install
}

let GlobalVue = null
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue
} else if (typeof global !== 'undefined') {
  GlobalVue = global.vue
}

if (GlobalVue) {
  GlobalVue.use(plugin)
}

component.install = install

Then export the component as follows

export default component

So the file entry.js finally looks like this after linting and formatting

// ./src/entry.js

import component from "./SimpleAlert.vue";

function install(Vue) {
  if (install.installed) return;
  install.installed = true;
  Vue.component("SimpleAlert", component);
}

const plugin = {
  install
};

let GlobalVue = null;
if (typeof window !== "undefined") {
  GlobalVue = window.Vue;
} else if (typeof global !== "undefined") {
  GlobalVue = global.vue;
}

if (GlobalVue) {
  GlobalVue.use(plugin);
}

component.install = install;

export default component;

Now, let's create the vue component.
Create a new file called SimpleAlert.vue

And add the following code inside it.

// ./src/SimpleAlert.vue

<script>
import { setTimeout } from "timers";
export default {
  name: "SimpleAlert",
  props: {
    message: {
      type: String,
      default: "Hello Dev.to"
    },
    timeout: {
      type: Number,
      default: 0
    }
  },
  mounted() {
    setTimeout(() => {
      alert(this.message);
    }, this.timeout);
  }
};
</script>

Notice how I didn't use a template or a script tag, it's because this component doesn't show any html, it just alerts.

Now create a new folder called build, it should be next to the src folder in the root directory, and add rollup.config.js inside it

So the project structure is as follows

.
β”‚
β”œβ”€β”€β”€build
β”‚     rollup.config.js
└───src
      entry.js
      SimpleAlert.vue

In rollup.config.js paste the following code

// rollup.config.js

import vue from "rollup-plugin-vue";
import buble from "rollup-plugin-buble";
import commonjs from "rollup-plugin-commonjs";
import replace from "rollup-plugin-replace";
import uglify from "rollup-plugin-uglify-es";
import minimist from "minimist";

const argv = minimist(process.argv.slice(2));

const config = {
  input: "src/entry.js",
  output: {
    name: "SimpleAlert",
    exports: "named"
  },
  plugins: [
    external,
    replace({
      "process.env.NODE_ENV": JSON.stringify("production")
    }),
    commonjs(),
    vue({
      css: true,
      compileTemplate: true,
      template: {
        isProduction: true
      }
    }),
    buble()
  ]
};

// Only minify browser (iife) version
if (argv.format === "iife") {
  config.plugins.push(uglify());
}

export default config;

Now that we have everything in place, let's try to build it, we'll need to edit our package.json to include the build command.

Open your package.json and replace everything you have in there with the following

{
  "name": "simplealertcomponent",
  "version": "0.1.0",
  "main": "dist/simplealertcomponent.umd.js",
  "module": "dist/simplealertcomponent.esm.js",
  "unpkg": "dist/simplealertcomponent.min.js",
  "browser": {
    "./sfc": "src/simplealertcomponent.vue"
  },
  "files": [
    "dist/*",
    "src/*",
    "attributes.json",
    "tags.json"
  ],
  "vetur": {
    "tags": "tags.json",
    "attributes": "attributes.json"
  },
  "scripts": {
    "build": "npm run build:unpkg & npm run build:es & npm run build:umd",
    "build:umd": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format umd --file dist/simplealertcomponent.umd.js",
    "build:es": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format es --file dist/simplealertcomponent.esm.js",
    "build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife --file dist/simplealertcomponent.min.js"
  },
  "devDependencies": {
    "cross-env": "^5.2.0",
    "minimist": "^1.2.0",
    "rollup": "^1.14.4",
    "rollup-plugin-buble": "^0.19.6",
    "rollup-plugin-commonjs": "^9.3.4",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-uglify-es": "0.0.1",
    "rollup-plugin-vue": "^4.7.2",
    "vue": "^2.6.10",
    "vue-template-compiler": "^2.6.10"
  }
}

Now open a terminal and type npm i to install all the dev dependencies.
Once that's done, type npm run build, that will create a new folder called dist with all the files we need to push to NPM in order for other users to consume our component.

This is the end of part 1 πŸŽ‰πŸŽ‰, the rest is coming soon 😊

Top comments (8)

Collapse
stwic profile image
Amir

Nicely written article, easy to follow. But, npm run build fails with ReferenceError: external is not defined. Does anyone know what could this be and if there is a simple solution for this? My money is on the broken rollup.config.js file.

Collapse
veed76 profile image
vishal

Hi I also get the same error, is there any solution?

Collapse
gauravrawat440 profile image
Gaurav Singh Rawat

did you find anything about the "external is not defined".

Collapse
loicgeek profile image
ngou loic

Hi, I m trying to compile my plugin unsuccessfully

Collapse
amroessam profile image
amroessam Author

Hey, maybe I can help.
Can you provide some more context?

Collapse
loicgeek profile image
ngou loic • Edited on

that is my package.json

{
  "name": "vue-easy-printer",
  "version": "1.0.0",
  "private": false,
  "description": "The Best Vue Plugin To convert Html page, Components to pdf",
  "main": "./dist/index.js",
  "keywords": [
    "Vuejs",
    "html",
    "pdf"
  ],
  "files": [
    "dist/*"
  ],
  "scripts": {
    "build": "bili --name index --plugin vue "
  },
  "author": "loicgeek",
  "license": "MIT",
  "devDependencies": {
    "bili": "^4.8.1",
    "rollup-plugin-vue": "^5.1.2",
    "vue-template-compiler": "^2.6.10"
  }
}

when I run the command to build there are no errors, but on top of my dist/index.js, I got these lines

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var __vue_normalize__ = _interopDefault(require('F:PERSONNALue-easy-printer
ode_modules
ollup-plugin-vue
untime
ormalize.js'));
var __vue_create_injector__ = _interopDefault(require('F:PERSONNALue-easy-printer
ode_modules
ollup-plugin-vue
untimerowser.js'));

Collapse
thamibn profile image
thami-bn

nice article straight forward, can you please help on how can i add Vuex on my package?

Collapse
abdurrahmanriyad profile image
Abdur Rahman

Great article

🌚 Browsing with dark mode makes you a better developer.

It's a scientific fact.