The minimal setup to package and reuse your React components
Tags: react, npm, javascript, tutorial
Published: 2022-09-29 19:11:33

---
title: The minimal setup to package and reuse your React components
published: true
description: How to use npm to package your react components to use in another project.
tags: react, npm, javascript, tutorial 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/snneu1s2v2pmbv5ib71z.png
# Use a ratio of 100:42 for best results.
---
Creating an npm package for sharing React components may seem overwhelming at first. At least that's how I felt and it took me some time to learn how to do it. One thing that particularly confused me was that everyone seemed to do it a little differently.

This article contains what I believe is the bare minimum to create an npm package with React components.

## Init your package
```bash
npm init
```
First, create a new folder (eg. `my-components`) and run `npm init` to bootstrap a package.json file.

## Install the dependencies needed for transpiling
```bash
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react
```
To publish React components as an npm package **you need to transpile your javascript to ES5**. As far as I know, there is no way around that, even if you only want to use it in ES6 projects.

You will need `@babel/core` for transpilation, `@babel/cli` to run the `babel` command, and the configuration presets `@babel/preset-env` (for modern Javascript) and `@babel/preset-react` (for jsx).

## Configure Babel
```
 📂my-components
  ┃ …
 +┃ 📜.babelrc
```
To configure Babel with the two installed presets, create a `.babelrc` with the below content:
```json
{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}
```

## Create a folder for your code
```
 📂my-components
  ┃ …
 +┣ 📂src
 +┃ ┗ 📜index.js
```
It’s good practice to create a `src` folder for all your source code. The `index.js` file will be the main entry point of your package (actually not this one but the transpiled version of it). If you don’t have something else in mind, you can export this simple button component, for example. Just copy the code to `src/index.js`:
```javascript
import React from 'react';

export function Button(props) {
  const {
    children,
    ...elementProps
  } = props;
  return <button type="button" {...elementProps}>{children}</button>
}
```

## Setup scripts and the main entry point in your package.json
```json
-  "main": "index.js",
+  "main": "lib/index.js",
   "scripts": {
     …
+    "transpile": "babel src -d lib --copy-files",
+    "prepublishOnly": "npm run transpile"
   },
```
To transpile your code you will have to call `babel` on the `src` folder and specify an output directory using either `--out-dir` or just `-d`. The last argument `--copy-files` will also copy files that are not compiled, like images for example.

This will transpile the entire `src` directory and save the results to the output directory. A [good place](https://stackoverflow.com/questions/39553079/difference-between-lib-and-dist-folders-when-packaging-library-using-webpack) to store your transpiled files is a folder named `lib`.

Babel will overwrite *but not delete* any existing files or directories in the output directory. To be sure the `lib` folder doesn’t contain old files you can delete it before transpiling. To do this automatically you can install [rimraf](https://www.npmjs.com/package/rimraf) and add it to the transpile script like this:

```bash
npm install --save-dev rimraf
```

```json
-    "transpile": "babel src -d lib --copy-files",
+    "transpile": "rimraf lib && babel src -d lib --copy-files",
```

You can now `npm run transpile` and take a look at the transpiled code in `lib`.

The second script’s name (`prepublishOnly`) is a magic one. It will automatically run before your package gets published. This will make sure you don’t forget transpiling when you publish your package.

Finally set the main entry point of the package to the transpiled index file `lib/index.js`

## Included files and peer dependencies

Before the package is ready to be published you might want to define what’s inside and what isn’t. You can exclude files with a `.npmignore` file or create a whitelist with the `files` property in `package.json`. In this case the whitelist is definitely the better option:

```json
+  "files": [
+    "lib",
+    "readme.md"
+  ],
```

With this whitelist only the `lib` folder (and `package.json`) will be shipped in the final package. I also included `readme.md` because it is quite common to have one. Feel free to create this file in the root of your project if you want.

By adding `peerDependencies` to your `package.json` you can require that certain host packages need to be installed when using your package. If the peer dependencies are not met a warning is shown to the user.

```json
+  "peerDependencies": {
+    "react": ">=17.0.2",
+    "react-dom": ">=17.0.2",
+    "prop-types": ">=15.7.2"
+  },
```

This will require that at least `react 17.0.2`, `react-dom 17.0.2` and `prop-types 15.7.2` must be installed to use your package.

Ok, that’s it, your package is ready for publishing.

## Publish/install your package
Basically there are two options to consume your package. You can publish and install it from a NPM registry or link it locally with `npm link`.

### Publish your package to a NPM registry
You can publish your package with the command `npm publish`. 

Per default your package will get published to [npmjs.com](https://www.npmjs.com/) and everyone can install it. If you want your package to stay private, you need a [paid plan](https://www.npmjs.com/products). Or you can install and host your own registry with something like [Verdaccio](https://verdaccio.org/docs/installation).

As you can’t publish a package with the same version twice, you need to bump the version in your `package.json` before publishing an update of your package. 

`npm version <newversion>` is a handy command for that and it also updates `package-lock.json` and `npm-shrinkwrap.json`. You can call it with a full new version number like `1.0.1` or bump either the `major`, `minor` or `patch` part of the version. See the [`npm version`](https://docs.npmjs.com/cli/v8/commands/npm-version) and [semantic versioning](https://semver.org/lang/de/) to learn more.

To update your package from `1.0.0` to `1.0.1` just run these two commands:
```bash
npm version patch
npm publish
```

I have [published](https://www.npmjs.com/package/@receter/my-components) the package from this example to my user scope on npm. 

To do this I had to prefix the name of the package with my username:
```json
-  "name": "my-components",
+  "name": "@receter/my-components",
```

And when I first published it, I had to confirm that I really want my package to be public by using `--access public`. Per default all scoped packages on npm are private.
```bash
npm publish --access public
```

To use the package you can just install it like any other package in your React project:
```bash
npm install @receter/my-components
```

And import the button like this:
```javascript
import { Button } from '@receter/my-components'
```

### Using `npm link`
[`npm link`](
https://docs.npmjs.com/cli/v8/commands/npm-link) is especially useful for testing/developing your package. Npm will create a symlink to your package in `node_modules` and any changes you make to the linked package are available immediately.

To link your package you have to follow these two steps:

1. Run `npm link` in the folder of the package you want to link to. This will register your package locally.
2. In the project where you want to use the package run `npm link <name-of-the-package>`

If you use nvm or another node version management tool: Be sure to use the same node version for `npm link` in the package folder as you do in your project.

To remove the link run `npm unlink <name-of-the-package>`

**Important:** If you have already installed a version of `<name-of-the-package>`, `npm link …` will replace the installed package with the symlink. This is probably what you want, but note that `npm unlink` will not only remove the symlink but also the dependency in your `package.json`.

So in this case you need to explicitly tell `npm unlink` not to save the changes and run `npm install` afterwards to install the original package again.

```bash
npm unlink --no-save <name-of-the-package>
npm install
```

Another thing to note is that you have to transpile your files before you can actually see changes made in `src`. You can automate this by calling babel with the `--watch` option. Just add another script like this:

```json   
   "scripts": {
+      "watch": "babel src -d lib --copy-files --watch",
       …
   }
```

Now you can run `npm run watch` in your package directory and see all changes you make to your components live in your project!

Ok, that’s it for now. If you have any questions feel free to ask me.

You can find the code for my example on github:
https://github.com/receter/my-components
https://www.npmjs.com/package/@receter/my-components

How do you share components between your projects? What do you do differently and why? Or do you use a service like [BIT](https://bit.dev/)? Please let me know!