How to Publish a React Component as an npm Package Using Vite
May 29, 2025
~3 min read
ReactViteLibrarynpm
Introduction
Have you ever built a cool React component and wanted to share it with the world? In this guide, I'll show you how I published @janardanpethani/genmoji — a mood-based emoji generator — as an npm package, starting from a Vite React app.
Why Use a lib
Directory for Components?
Organizing your reusable code in a
lib/
directory keeps your published package clean and focused. It separates library code from demo or app code, makes exports easier to manage, and follows best practices used by many open source libraries.1. Create a Vite React App
bash
1npm create vite@latest <your library name> -- --template react-ts
bash
1cd <your library name>
bash
1npm install
2. Develop Your Component
Write your component as you would in any React app. For example, in lib/components/Chat.tsx:
tsx
1import React from "react";
2
3type ChatProps = {
4 // Add any props you want to support
5};
6
7export const Chat: React.FC<ChatProps> = (props) => {
8 return <button>Open Genmoji Chat</button>;
9};
Create index.ts in lib/components and export everything from it:
ts
1export * from "./Chat";
Create index.ts in lib and export everything from it:
ts
1export * from "./components";
3. Configure Vite for Library Build
ts
1import { defineConfig } from "vite";
2import react from "@vitejs/plugin-react";
3import dts from "vite-plugin-dts";
4
5// https://vite.dev/config/
6export default defineConfig({
7 // Configure plugins for Vite
8 plugins: [
9 // React plugin for Vite
10 react(),
11 // Plugin to generate TypeScript declaration files (d.ts)
12 dts({
13 // Specify the path to the build-specific tsconfig file
14 tsconfigPath: "./tsconfig.build.json",
15 }),
16 ],
17 // Build configuration options
18 build: {
19 // Library build options
20 lib: {
21 // Entry point for the library build
22 entry: "lib/index.ts",
23 // Function to determine the output file name based on the format
24 fileName: (format) => `genmoji.${format}.js`,
25 // Output formats for the library
26 formats: ["es", "cjs"],
27 },
28 // Rollup specific options (used under the hood by Vite)
29 rollupOptions: {
30 // Specify dependencies that should not be bundled into the library
31 external: ["react", "react-dom"],
32 // Output options for Rollup
33 output: {
34 // Configure global variables for external dependencies
35 globals: {
36 react: "React",
37 "react-dom": "ReactDOM",
38 },
39 },
40 },
41 // Empty the output directory before building
42 emptyOutDir: true,
43 // Do not copy the public directory to the output directory
44 copyPublicDir: false,
45 // Minify the output code
46 minify: true,
47 },
48})
You need to install vite-plugin-dts to generate TypeScript declaration files.
bash
1npm install vite-plugin-dts
4. Update package.json
json
1{
2 ...
3 "type": "module",
4 "main": "dist/genmoji.cjs.js",
5 "module": "dist/genmoji.es.js",
6 "types": "dist/index.d.ts",
7 "exports": {
8 ".": {
9 "types": "./dist/index.d.ts",
10 "import": "./dist/genmoji.es.js",
11 "require": "./dist/genmoji.cjs.js"
12 }
13 },
14 "files": [
15 "dist"
16 ],
17 "publishConfig": {
18 "access": "public"
19 },
20 ...
21 "dependencies": {
22 "framer-motion": "^12.15.0"
23 },
24 "peerDependencies": {
25 "react": "^19.1.0",
26 "react-dom": "^19.1.0"
27 },
28 ...
29}
Why These package.json
Fields?
Field | Description |
---|---|
main/module/types | Ensures compatibility with all bundlers and editors. |
exports | Modern way to define entry points for different environments. |
files | Only publish what's needed (keeps npm package small and clean). |
peerDependencies | Prevents multiple React versions in the consumers app. |
publishConfig | This setting is specifically relevant for scoped packages (packages whose names start with @scope/ , like yours: @janardanpethani/genmoji ). By default, scoped packages are published as private. Setting "access": "public" ensures your package is published publicly, making it available for anyone to install from the npm registry. |
scripts.build | Runs both TypeScript and Vite build for a complete output. |
5. Build Your Package
bash
1npm run build
This will output your library to the dist/ folder.
6. Publish to npm
bash
1npm login
bash
1npm publish --access public
7. Usage Example
tsx
1
2import { Chat } from "@janardanpethani/genmoji";
3function App() {
4 return <Chat />;
5}
Conclusion
Vite makes it easy to go from a React app to a reusable npm package. You can see the full source and real-world example here: github.com/JanardanPethani/genmoji