DEV Community

Cover image for NPM package development with Vite
Brian Ng
Brian Ng

Posted on

NPM package development with Vite

Why vite is awesome

Before, when we developed npm packages, it involved A LOT of manual configuration, development steps and testing to ship out a npm package.

We were dealing with webpack and rollup and more, the templating or boilerplate open-source repos that provides rapid-development for our npm package(s) - these were valuable to shortening our development & testing time.

Thankfully, vite is here and it is awesome! And the attractive feature here, is that vite pre-bundles dependencies with esbuild [1]. There are more features we will get to play with, which we will explore in this article.

Let's build our first npm package!

First, let's create with yarn create vite.
yarn create vite

Now, our new project has been scaffolded, and let's see our package.json file.

  "name": "awesome-vite-module",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  "devDependencies": {
    "typescript": "^4.5.4",
    "vite": "^2.9.9"
Enter fullscreen mode Exit fullscreen mode

Next, new goal is to configure our project with rollup config and vite config together.

First, let's install new package dependencies we will need - we want to use the built-in rollup features in vite.

  "name": "awesome-vite-module",
  "private": true,
  "version": "0.0.0",
  "exports": {
    ".": {
      "import": "./dist/",
      "require": "./dist/main.cjs.js"
  "main": "./dist/main.cjs.js",
  "module": "./dist/",
  "typings": "./dist/main.d.ts",
  "files": [
  "scripts": {
    "build": "tsc && vite build",
    "build:watch": "tsc && vite build --watch",
    "dev": "vite",
  "dependencies": {},
  "devDependencies": {
    "@rollup/plugin-typescript": "^8.2.1",
    "@types/node": "^17.0.35",
    "prettier": "2.6.2",
    "rollup-plugin-typescript-paths": "^1.3.0",
    "tslib": "^2.4.0",
    "typescript": "^4.7.2",
    "vite": "^2.9.9",
Enter fullscreen mode Exit fullscreen mode

Next, let's set up our tsconfig.json file [2].

  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "types": ["vite/client", "node"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "baseUrl": "./",
    "paths": {
      "~/*": ["src/*"]
  "include": ["./src"],
  "exclude": ["node_modules"]
Enter fullscreen mode Exit fullscreen mode

We will need to set up a new vite.config.ts [3 4] (also because this tutorial is typescript scaffolded).

// vite.config.ts
import { defineConfig } from "vite";

import typescript from "@rollup/plugin-typescript";
import path from "path";
import { typescriptPaths } from "rollup-plugin-typescript-paths";

export default defineConfig({
  plugins: [],
  resolve: {
    alias: [
        find: "~",
        replacement: path.resolve(__dirname, "./src"),
  server: {
    port: 3000,
  build: {
    manifest: true,
    minify: true,
    reportCompressedSize: true,
    lib: {
      entry: path.resolve(__dirname, "src/main.ts"),
      fileName: "main",
      formats: ["es", "cjs"],
    rollupOptions: {
      external: [],
      plugins: [
          preserveExtensions: true,
          sourceMap: false,
          declaration: true,
          outDir: "dist",
Enter fullscreen mode Exit fullscreen mode

And let's clean up main.ts, to declare a simple demo feature, a function called hello.

// main.ts
const hello = (name: string) => {
  return `Hello there, ${name}!`;

export { hello };
Enter fullscreen mode Exit fullscreen mode

Almost done, some cleaning up

Lastly, let's get rid of files we don't need at this time:

  1. style.css
  2. index.html

Rapid testing (without unit testing)

Looks like our first npm package is ready for testing. But how do we do a quick test, without jest or vitest?

There are two module testing suggestions, using yalc or npm link (yalc is preferred).

We execute npm link in our awesome-vite-module project.

npm link
Enter fullscreen mode Exit fullscreen mode

Then, we are now able to use it, in another project. Let's quick scaffold a demo project, with another vite based framework, called solidjs [5].

npx degit solidjs/templates/js my-app
cd my-app
npm i
npm run dev
Enter fullscreen mode Exit fullscreen mode

Once created and have dependencies installed, run npm link awesome-vite-module in it.

Lastly, modify the App.tsx file like example below

import type { Component } from "solid-js";

import logo from "./logo.svg";
import styles from "./App.module.css";

import { hello } from "awesome-vite-module";

const App: Component = () => {
  return (
    <div class={styles.App}>
      <header class={styles.header}>
        <img src={logo} class={styles.logo} alt="logo" />

export default App;
Enter fullscreen mode Exit fullscreen mode

Awesome, it's working!
example solidjs project

When you're done, execute npm unlink awesome-vite-module.

That's it!

That's the end of this article, eventually you're able to npm login and later npm publish your first npm package.

Did some sections not work, or returned errors? Debugging will be part of the learning journey - and if you learn better from examples, see the vite boilerplate of vanilla-ts here at

I hope this article / tutorial was helpful, and enjoy using vite as much as I do these days! Thanks, and happy coding!


  1. Vite | Slow Server Start
  2. Vite | Features > Client Types
  3. Vite | Building for Production > Customising the build
  4. Vite | Config File > Config Intellisense
  5. SolidJS | Getting Started

Discussion (0)