How to Package and Distribute a Vue.js 3 Plugin on NPM

Perhaps you’ve create a Vue.js 3 plugin that adds some awesome functionality to a Vue app but how do you get that plugin into the hands of other developers? Let’s breakdown the steps in this article.

Bundle the Vue Plugin with Vite

How to Configure Vite

In a previous article we built this simple tooltip plugin for Vue.js 3. We can use Vite to generate JavaScript files ready for use with both common JS or as ES modules. (This assumes you’ve developed your plugin with Vite.) When it comes to build time you can configure the plugin as a library with the build.lib setting in vite.config.js.

// vite.config.js

import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      // the entry file that is loaded whenever someone imports
      // your plugin in their app
      entry: resolve(__dirname, 'lib/main.js'),

            // the exposed global variable
      // is required when formats includes 'umd' or 'iife'
      name: 'SweetVueTooltip',

      // the proper extensions will be added, ie:
         // name.js (es module)
         // name.umd.cjs) (common js module)
      // default fileName is the name option of package.json
      fileName: 'sweet-vue-tooltip'
    },
    rollupOptions: {

      // make sure to externalize deps that shouldn't be bundled
      // into your library
      external: ['vue'],
      output: {
        // Provide global variables to use in the UMD build
        // for externalized deps
        globals: {
          vue: 'Vue'
        }
      }
    }
  }
})

How to Configure package.json

Once Vite is configured you’ll need to configure a few things in package.json.

First, we should specify that all .js files are ES modules. Vite will pick up on this and generate the file extensions accordingly.

"type": "module"

Next, since Vite will generate built files in a dist directory, then we can specify that only these files should be included in the distributed pacakge.

"files": ["dist"],

For common JS and ES modules to target the proper files you should provide the main, module, and exports options. (These files in the values will be generated by Vite based on the build.lib.fileName option in vite.config.js.)

"main": "./dist/sweet-vue-tooltip.umd.cjs",
"module": "./dist/sweet-vue-tooltip.js",
"exports": {
  ".": {
    "import": "./dist/sweet-vue-tooltip.js",
    "require": "./dist/sweet-vue-tooltip.umd.cjs"
  },
},

Also if your plugin includes any styles like our tooltip plugin did, you’ll need to export those as well with the exports option.

// with this, plugin end users can import styles like:
// import "sweet-vue-tooltip/style.css"; 
// and that will import the styles.css file from the dist directory
"exports": {
  //...
  "./style.css": "./dist/style.css"
}

Here’s all the additions necessy for package.json mentioned above so you can copy and paste them if you’d like.

// package.json
{
  //...
  "type": "module",
  "files": [
    "dist"
  ],
  "main": "./dist/sweet-vue-tooltip.umd.cjs",
  "module": "./dist/sweet-vue-tooltip.js",
  "exports": {
    ".": {
      "import": "./dist/sweet-vue-tooltip.js",
      "require": "./dist/sweet-vue-tooltip.umd.cjs"
    },
    "./style.css": "./dist/style.css"
  },
}

Build the Files to Distribute

With the proper configurations made to both vite.config.js and package.json, you should now be able to run npm run build (or vite build) and get a dist directory generated.

In this dist directory you’ll find entry points for both common js and es modules, as well as a JavaScript file for your actual plugin, and plain JavaScript files for any single file components that might have been included by your plugin. Your compiled styles from any components will exist here as well.

/dist
  - index.f5907655 // the plugin file
  - style.css // the compiled styles
  - sweet-vue-tooltip.js // es modules entry point
  - sweet-vue-tooltip.umd.cjs // common js entry point
  - ToolTip.92754567.js // compiled .vue file

Publish to NPM