If you've ever tried to build a library that exports individual components—think @acme/ui/button or @acme/utils/date—you know the pain. Keeping your package.json exports in sync, managing complex input globs, and maintaining a predictable output structure is a tedious, error-prone manual process.
Enter modular-library: a zero-config utility designed specifically to generate modular outputs for modern bundlers like Vite, Rollup, and Rolldown.
What is a "Modular Library"?
Unlike a monolithic library where you import everything from a single entry point, a modular library is split into small, focused modules.
The standard way:
import { Button } from "my-ui-lib";
Problem: Often requires evaluating the full package entry, even if you only need one component.
The modular way:
import Button from "my-ui-lib/button";
Solution: Loads only the code for the button. It’s faster, cleaner, and ensures perfect tree-shaking for the consumer.
Why use modular-library?
Building this manually usually means fighting your build tool's configuration as your source tree grows. modular-library automates the heavy lifting:
-
Zero-Config: It handles the mapping from
src/todist/automatically. - Predictable Structure: Your output mirrors your input without manual path mapping.
- Modern Stack Support: Works out of the box with Vite, Rollup, and Rolldown.
-
CLI Validation: Includes a CLI tool to verify that your
package.jsonexports actually match your build output.
Quick Start
modular-library requires Node.js 22 or newer.
npm install modular-library
Using it with Vite
Instead of manually defining every entry point in your vite.config.ts, you can use the plugin to handle the glob-based inputs.
// vite.config.ts
import { defineConfig } from "vite";
import modularLibrary from "modular-library/vite";
export default defineConfig({
plugins: [modularLibrary()],
build: {
lib: {
entry: ["src/**/*.ts"],
formats: ["es"],
},
},
});
Making it Consumable
To let users import your modules easily, add an exports map to your package.json:
{
"exports": {
"./*": "./dist/*.js"
}
}
The "Check" Command
One of the coolest features is the built-in CLI. After you run your build, you can validate that your exports are correct and that no files are missing:
npx modular-library check
This prevents the "broken package" scenario where you ship a library but a subpath import fails because the file wasn't generated correctly.
Customizing your Output
If you need to change how the paths are generated (for example, putting everything in a modules/\ folder), the plugin provides a simple transformOutputPath\ hook:
plugins: [
modularLibrary({
relative: "src/", // The base path to strip
transformOutputPath: (path) => \`modules/\${path}\`,
}),
],
Conclusion
The goal of modular-library is to let you focus on writing code instead of managing build artifacts. By automating the sync between your source files and your distribution targets, it makes maintaining a high-performance, tree-shakeable library accessible to everyone.
Check out the source on GitHub and start modularizing your workflow!
Found this helpful? Follow me for more insights on modern JavaScript tooling and library development!
Top comments (0)