Building npm libraries with Vite's library mode: entry, externals, and CSS
Learn how to use Vite's library mode to build npm packages: configure entry, externalize dependencies, handle CSS, set UMD name, and verify the output in a consumer project.
02 Aug 2025, 09:53 UTC

Problem: publishing a reusable UI component library
When you want to share a set of components as an npm package, you need a build that produces plain JavaScript and CSS files consumable by any project—whether it uses Vite, Webpack, or a plain HTML page. Using Vite’s default app build creates an index.html and bundles everything, which is unsuitable for a library.
Understanding Vite library mode
Vite’s build.lib option switches the output from an application bundle to a library bundle powered by Rollup. It skips HTML generation, disables SPA fallbacks, and lets you define the entry point, output formats (es, umd, etc.), and the global variable name for UMD/IIFE builds.
Key configuration fields
build.lib.entry– path to the library’s main source file.build.lib.name– the global variable exposed for UMD/IIFE formats.build.lib.formats– array of formats to generate (default:['es', 'umd']).
Worked example: a simple React button library
Assume a project my-ui-lib with src/index.js exporting a React component.
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: 'src/index.js',
name: 'MyUiLib',
formats: ['es', 'umd']
},
rollupOptions: {
// externalize React so consumers provide their own copy
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
}
}
})
Run the build from the project root (no special permissions needed):
npm run vite build
# or: npx vite build
After the build, inspect dist/:
my-ui-lib.es.js– ES module format.my-ui-lib.umd.js– UMD bundle exposingMyUiLib.my-ui-lib.css– extracted CSS (Vite does this by default).- No
index.htmlis generated.
Externalizing dependencies and peer declarations
Libraries should not bundle frameworks like React or Vue; otherwise consumers may end up with duplicate copies, causing hook errors or broken context. By listing them in build.rollupOptions.external and adding them to peerDependencies in package.json, you ensure the consumer’s install provides the framework.
# package.json snippet
{
"name": "my-ui-lib",
"version": "1.0.0",
"main": "dist/my-ui-lib.umd.js",
"module": "dist/my-ui-lib.es.js",
"exports": {
".": {
"import": "./dist/my-ui-lib.es.js",
"require": "./dist/my-ui-lib.umd.js"
}
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
}
}
CSS and UMD name considerations
Vite extracts CSS into a separate file by default. Consumers must import both the JavaScript and the CSS (or include the CSS via a link tag). For UMD builds, the build.lib.name field is required; without it the global variable may be undefined, leading to errors when the script is loaded directly in a browser.
Trade‑offs and limitations
- No HTML output: Library mode is not suitable for building a deployable site; you must test in a consumer project.
- Manual externalization: Forgetting to list a dependency in
externalbundles it into the library, increasing size and risking duplicates. - CSS scoping: Extracted CSS is not automatically scoped; ensure class names are unique or use a CSS‑in‑JS solution if isolation is needed.
To verify the build works outside Vite, publish a test version (npm pack or npm publish --tag dev), install it in a plain HTML page or a Webpack‑based project, import the UMD bundle, and confirm the component renders and the CSS applies.
Actionable closing
- Add
build.libto your Vite config with a propernameand entry point. - List all framework and utility dependencies in
build.rollupOptions.externaland mirror them aspeerDependencies. - Check the
dist/folder for separate JS and CSS files and the absence ofindex.html. - Test the built library in a non‑Vite consumer (e.g., a simple HTML page) to validate global name and CSS.
- Publish only after the consumer test passes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.