How To Create And Publish Your Own Vue 3 Component Library To NPM With Typescript And Vite
Sun Jan 08 2023

How To Create And Publish Your Own Vue 3 Component Library To NPM With Typescript And Vite

Many companies have designers that design layouts and components for use within the company. These components like buttons and form input fields get reused in many different projects. You may also be an individual developer that reuses the same components in many different projects. Creating a single component library that you can reuse in all your projects is a great way to save time and effort. In this article, we will create a Vue 3 component library using typescript and vue 3 and publish it to NPM.

Overview

In this tutorial I would be using

  • Vue 3 composition API with Typescript (feel free to remove typescript specific code if you are not using typescript)
  • Vite as the build tool (because it is way cooler imo)

Pre-requisites

In order to follow along with this article, you will need to have the following installed on your machine:

  • Node.js
  • An NPM account

Creating the project

To create the project we will be using vite. Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It is very fast and has a lot of cool features. Vite is the recommended build tool for vue. To create the project, run the following command:

With npm

npm create vite@latest

With yarn

yarn create vite

With pnpm

pnpm create vite

Follow the prompts and select the following options: Select vue as the framework and typescript as the variant (Select javascript if you don’t want to use typescript).

Change directory into the project folder and run the following command to install the dependencies:

npm install

Open the project in your favorite editor.

Creating the component library

Familiarity with the Vue 3 composition API is assumed. If you are not familiar with the composition API, you can read more about it here.

The following is the structure of the component library:

src
├── components
   ├── HelloWorld.vue
├── main.ts
tsconfig.json
package.json
vite.config.ts

There may be other files in the project but we will only be concerned with the files above.

Creating the component

Create a new file in the components folder of src and name it PersonalButton.vue. Add the following code to the file:

<template>
  <button class="personal-button">
    {{ props.text }}
  </button>
</template>

<script setup lang="ts">
const props = defineProps<{
  text: string;
}>();
</script>

<style scoped>
.personal-button {
  background-color: #000;
  color: #fff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
}
</style>

This is a simple button component that takes in a text prop and displays it. The component is styled using scoped css. You can change up the code to suit your needs. The important thing is that we have a component that we can use in our library.

You can create as many components as you want in the components folder. Assume PersonalTable.vue and PersonalInput.vue are components in the components folder.

Creating the entry file

Create a new file in the src folder and name it index.ts. Add the following code to the file:

// Import all the components here, there are more elegant ways to do this but this is the simplest
import PersonalButton from "./components/PersonalButton.vue";
import PersonalTable from "./components/PersonalTable.vue";
import PersonalInput from "./components/PersonalInput.vue";

export { PersonalButton, PersonalTable, PersonalInput };

This file is the entry file for the library. It exports all the components in the library.

Configuring the build

In vite.config.ts, add the following code:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "node:path";
import dts from "vite-plugin-dts";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), dts()],
  build: {
    lib: {
      entry: resolve(__dirname, "src/index.ts"),
      name: "TestComponent",
      fileName: "test-component",
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});

What are we doing here?

The build object is the configuration for the build. We are telling vite to build a library. The lib object is the configuration for the library. The entry property is the entry file for the library and it points to our index.ts which exports all our components. The name property is the name of the library. The fileName property is the name of the output file.

The rollupOptions object is the configuration for rollup. We are telling rollup to exclude vue from the bundle because it is a peer dependency. We are also telling rollup to use Vue as the global variable for vue.

We are also using the vite-plugin-dts plugin to generate the type definitions for the library. We have to install this package as a dev dependency. Run the following command to install it:

npm install vite-plugin-dts --save-dev

Editing the package.json file

Edit the package.json file and add the following code:

{
  "name": "test-component",
  "version": "0.0.1",
  "description": "A test component library",
  "main": "./dist/fileName.umd.js",
  "module": "./dist/fileName.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/fileName.esm.js",
      "require": "./dist/fileName.js"
    }
  },
  "files": [
    "dist",
    "src"
  ],
  "scripts": {
    "build": "vite build",
    "dev": "vite",
    "serve": "vite preview"
  },
  "keywords": [
    "vue",
    "vue3",
    "component",
    "library"
  ],
  "author": "Your Name",
  "peerDependencies": {
    "vue": "^3.0.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.2.4",
    "typescript": "^4.3.5",
    "vite": "^2.3.7",
    "vite-plugin-dts": "^0.17.0",
    "vue": "^3.0.0"
  }
}

We do not want to add vue into our bundle because we assume that the user of the library will have vue installed. Hence, we make vue a peer dependency. You may have noticed the duplication of vue in the devDependencies and peerDependencies. This is because vue is dependency in our project. We need to install vue in the devDependencies so that we can use it in the library. Peer dependencies are not installed automatically in older versions of npm. Hence, we need to install vue in the devDependencies to make sure that it is installed.

You can read more about dependencies here.

We also added main, module and exports properties to the package.json file. These properties are the entry points to our library and they are used to determine how the library is imported. You can read more about the main, module and exports properties here.

Replace fileName with the name of the output file in the build object in vite.config.ts.

Other fields in the package.json file are self-explanatory.

Building the library

Run the following command in the terminal:

npm run build

This will build the library and output the files in the dist folder.

Publishing the library

Run the following command in the terminal:

npm publish

This will publish the library to npm. (You need to be logged in to npm to publish the library.) Assuming all goes well, you should be able to see the library in the npm registry.

Installing the library

After publishing, you can install the library using the following command:

npm install <name of component>

You can also import the libray from your local machine using the following command:

npm install <path to library>

Using the library

You can use the library in your project by importing the components from the library. For example, if you want to use the PersonalButton component, you can import it like this:

<template>
  <PersonalButton text="button text here" />
</template>

<script setup lang="ts">
import { PersonalButton } from "test-component";
</script>

And that’s it! You have successfully created a component library using Vue 3 and Vite. There is a lot more to building a component library. This article is just a basic introduction to building a component library. See the repo to a component library that I built using Vue 3 and Vite.

Leave a comment if you have any questions or suggestions. I will be happy to answer them.