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 thebuild
object invite.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.