Creating React TypeScript component library - basic rollup.js setup
Tags: typescript, react, library, rollupjs
Published: 2021-07-20 10:00:02

## Intro
I have worked on several custom front-end projects and often thought about using the same styles and/or components, so other developers could use consistent UI.

Too long I was afraid of creating a separate library, so usually, I was ending up including the components directly in the project files.

That's not the case here!

## What is it about?
This is the first article I have created in a series "Creating React TypeScript component library with rollup.js from scratch".
Hopefully, the title explains the article's contents.

It's all about configuration and installing proper libraries. I won't give it too much attention, just quickly explain what is necessary and why.

If you want to see the whole code as it is at the end of this tutorial, just feel free to visit [this repo](https://github.com/kraftdorian/react-ts-rollup-starter-lib/tree/1.1.0) at my GitHub account.
Also, give it a star if you want!

### Important note
This article is based on these sources:
* https://blog.harveydelaney.com/creating-your-own-react-component-library
* https://github.com/a-tarasyuk/rollup-typescript-babel

## A few words about the versions
As I am writing this article I'm using:
* node v14.17.0
* npm v6.14.10

## Let's start!
### Armory
Obviously, we need some new directory for our library:
```bash
mkdir my-ui-library
cd my-ui-library
```

Then, we initialize it (you will be prompted to type some stuff. If you don't want to be that specific, then you can use default values by constantly pressing <kbd>ENTER</kbd>):
```bash
npm init
```

In the end, make sure you set this file as your main script in package.json (it doesn't exist now, but we will build it!):
```json
"main": "dist/index.js"
```

### 2021-11-24 UPDATE - TypeScript compiler only
If you want to use TypeScript compiler only, please have a look at this [rollup.config.js](https://github.com/kraftdorian/react-ts-rollup-starter-lib/blob/master/rollup.config.js) instead, as well as the updated [package.json](https://github.com/kraftdorian/react-ts-rollup-starter-lib/blob/master/package.json).

Don't forget to create [tsconfig.json](https://github.com/kraftdorian/react-ts-rollup-starter-lib/blob/master/tsconfig.json) as well.

Then, feel free to jump straight to the Finale section.

More details about the original issue are available [here](https://github.com/kraftdorian/react-ts-rollup-starter-lib/issues/3).

### Arrival (of dev dependencies!) - compile with babel *(legacy section)*

We will compile our TypeScript components with Babel.
Types will be generated with TypeScript's compiler.

It's important to save these deps in dev dependencies - the project where we will put our library doesn't need to have them!

```bash
npm i --save-dev rollup rollup-plugin-peer-deps-external @rollup/plugin-node-resolve @rollup/plugin-babel @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/plugin-transform-runtime @babel/runtime @babel/plugin-proposal-class-properties typescript tslib rimraf
```

### The Grid (where we will work)
How we are able to build our library? Just specify the *build* script:
```json
"build": "rimraf dist && tsc --emitDeclarationOnly && rollup --config",
"tsc": "tsc"
```

If you're stuck here, feel free to check this [package.json](https://github.com/kraftdorian/react-ts-rollup-starter-lib/blob/1.1.0/package.json).

At this point, we need to somehow run *tsc* to initialize our TypeScript config. If for some reason *tsc* is not available for you, try adding it to package.json scripts.

```bash
npm run tsc -- --init
```

We don't need all the config options that *tsc* has created.
You can go ahead and grab the ones I prepared in this [tsconfig.json](https://github.com/kraftdorian/react-ts-rollup-starter-lib/blob/master/tsconfig.json).
You can read more about tsconfig [here](https://www.typescriptlang.org/tsconfig).

The important thing above is, we want to include our TypeScript files, but exclude node_modules and our built files directory.

```json
"include": [
  "src/**/*.ts",
  "src/**/*.tsx"
],
"exclude": [
  "node_modules",
  "dist"
]
```

As for Babel, we need to configure it in the babel.config.json file:
```json
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-typescript",
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/proposal-class-properties",
    "@babel/proposal-object-rest-spread"
  ]
}
```

### Arena (rollup.js vs TypeScript)
Simply place this configuration in your rollup.config.js at the project root:

```js
import babel from "@rollup/plugin-babel";
import resolve from "@rollup/plugin-node-resolve";
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import pkg from "./package.json";

// Array of extensions to be handled by babel
const EXTENSIONS = [".ts", ".tsx"];

// Excluded dependencies - dev dependencies
const EXTERNAL = Object.keys(pkg.devDependencies);

export default {
  input: ["src/index.ts"],  // What files we build?
  output: {
    dir: "dist",  // Directory where rollup.js will put the built files
    sourcemap: true,  // We want a source map to trace the original code
    format: "esm",  // Built files will follow ES Module format
    preserveModules: true  // This one is important for treeshaking features of our library
  },
  plugins: [
    peerDepsExternal(),  // https://rollupjs.org/guide/en/#peer-dependencies
    resolve(),  // Resolves node modules
    babel({
      extensions: EXTENSIONS,  // Compile our TypeScript files
      babelHelpers: "runtime",  // EDIT(2021-11-18): "inline" is not recommended. Please see the details in https://github.com/kraftdorian/react-ts-rollup-starter-lib/issues/1
      include: EXTENSIONS.map(ext => `src/**/*${ext}`),
      plugins: ["@babel/plugin-transform-runtime"]
    })
  ],
  external: EXTERNAL  // https://rollupjs.org/guide/en/#peer-dependencies
};
```

Next, create some simple TypeScript file:
```ts
// @/src/index.ts

const Component = () => {};

export default Component;
```

### Finale
Congrats, you've made it to this place!
Now, simply run this npm script:

```bash
npm run build
```

If everything is good, you will see:
![Console output after build](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jyvrcwwo389eey5hhtrb.png)

These files will appear in the *dist* directory:
![dist directory contents](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hj2vtnxsqwkksvmqf7h9.png)

## Summary
We have just created a basic project that allows us to compile TypeScript to JavaScript with Babel, and the types are generated by the TypeScript compiler.

For further reference, all files I have presented here you can find in my repository:
https://github.com/kraftdorian/react-ts-rollup-starter-lib/tree/1.1.0

## 2021-11-18 UPDATE
### Changed
1. Use "runtime" instead of "inline" in rollup.config.js as the "inline" helpers are not recommended.
Please visit https://github.com/kraftdorian/react-ts-rollup-starter-lib/issues/1 for more details.

Article cover photo: https://unsplash.com/photos/-LFxVNhopfs