Skip to content

Starter template for building JavaScript libraries using Rollup

License

Notifications You must be signed in to change notification settings

mryechkin/rollup-library-starter

Repository files navigation

Rollup Library Starter

Rollup License

Rollup logo

Overview

This is a starter template for JavaScript libraries, using Rollup module bundler. It generates a dual-module package (ESM + CommonJS), ready to be published to NPM.

Read the accompanying blog post for full details on this template.

Usage

To use this template as the base of your project, clone it using git:

git clone https://github.com/mryechkin/rollup-library-starter.git <project-name>
cd <project-name>

Then make it your own:

rm -rf .git && git init && npm init
git add .
git commit -m "Initial commit"

Install dependencies:

npm i

Modify and structure code inside src as needed.

Then, build the package:

npm run build

This will generate a dual-bundle package inside the dist folder, with both esm and cjs versions of the library code (ES Modules, and CommonJS).

Project Structure

This template follows a file structure that generally looks like this:

src/
├── components/
│   ├── Component1/
│   │   ├── Component1.js
│   │   └── index.js
│   ├── Component2/
│   │   ├── Component2.js
│   │   └── index.js
│   └── index.js
├── utils/
│   └── index.js
└── index.js

Above, src is the main folder for all of the library code. Inside it there are components and utils folders, and the main index.js file.

The components and utils folders are there for example purposes, but you can use these as your starting point for organizing your library code.

Barrel File (index.js)

The root-level index.js will be the entry point into the library. Often called a "barrel" file, it exports everything that you'd like to have included in the bundle:

// src/index.js
export * from './components';
export * from './utils';

The above will export everything from components and utils, which in turn each have an index.js of their own.

Having this root index.js file is the only hard requirement for this template, as it's used by Rollup to configure the entry point of the library. When it comes to folders and how they're organized, that is entirely up to your library's needs.

Folders

Inside components, there are two more folders - Component1 and Component2 - one for each individual component in our library. We also have an index.js file to specify all the exports, similar to the root one:

// src/components/index.js
export { default as Component1 } from './Component1';
export { default as Component2 } from './Component2';

The above will re-export the default export of each specified folder (in this case Component1 and Component2). If there were named exports, you can re-export those as well:

// src/components/index.js
export { default as Component1, foo, bar } from './Component1';

The convention for the component folders is to have a main component file Component1.js, and an index.js file with the exports.

For example, for the Button component:

// src/components/Button/Button.js
const Button = (props) => {
  // ...
};

export const VARIANT = {
  PRIMARY: 'primary',
  SECONDARY: 'secondary',
};

export default Button;

Here, we have the main Button component itself as the default export, and the VARIANT constant as a named export.

Then, inside the Button index file, we re-export them:

// src/components/Button/index.js
import Button, { VARIANT } from './Button';

export default Object.assign(Button, {
  VARIANT,
});

Notice the Object.assign() above. This lets us assign the VARIANT constant as a static property on the Button component, allowing for something like this:

import { Button } from 'my-library';

<Button variant={Button.VARIANT.SECONDARY}>I'm a SECONDARY button</Button>;

This convention allows for a clean way to organize your modules, and works great with Rollup. Rollup will also warn you if there are any circular dependencies in your modules.

For more details, see the blog post.

Plugins

This template includes the following Rollup plugins:

And the following Babel plugins:

Rollup Config

For details of all the configuration options used in this template, please see the accompanying blog post.

Usage with Server Components

This template supports usage of the "use client" directive for denoting Client vs Server Component, thanks to the rollup-plugin-preserve-directives plugin.

To mark a component as a Client Component, add 'use client' at the very top of the file:

// src/components/Button.js
'use client';

const Button = (props) => {
  // ...
};

// ...

The rollup-plugin-preserve-directives plugin, together with the preserveModules output option, ensures that the 'use client' directive does not get discarded during build time.

Warning It's important that preserveModules is set to true for this to work as expected.

Note as well that if using the Object.assign() pattern for sub-components, the component MUST be a Client Component, otherwise you may get an error like "Cannot dot into a client module from a server component."

Author

Mykhaylo Ryechkin

Buy Me A Coffee

License

MIT