# Create and publish npm module library with esbuild typescript and react

Type: blog post
Language: en-US
Canonical URL: https://simonboisset.com/en/blog/publish-npm-library-with-esbuild
Published: October 2, 2022
Summary: Introduction As an open source enthusiast, I like to share my code and give everyone the opportunity to use it. For that npm is my first choice. But there ar...

## Introduction

As an open source enthusiast, I like to share my code and give everyone the opportunity to use it. For that npm is my first choice. But there are some conditions to have a good library release on npm.

The first recommendation to follow is to support common js as Matteo Collina said :

<blockquote>Here is my recommendation to all my fellow npm module authors: don’t drop support for CJS and go esm-only. The community is not ready to migrate just yet.
Matteo Collina (@matteocollina) <a href="https://twitter.com/matteocollina/status/1560658851682168834?ref_src=twsrc%5Etfw">August 19, 2022</a></blockquote>

For long time you needed to use js bundler like rollup, webpack and babel.

But that time is over because of a new generation of bundler. esbuild is one of them.

Today we will see how to create and publish a react library on npm with esbuild.

You can go to [this repository](https://github.com/simonboisset/remix-feature-routes) for an example of this post.

## Initialization

Create your folder project and initialize it.

```bash
yarn init
```

Your package.json file should be defined :

```json
{
  "name": "my-react-library",
  "version": "1.0.0"
}
```

Now we will install our dependencies.

## Install dev dependencies

```bash
yarn add -D react react-dom typescript @types/react @types/react-dom
```

> Don't forget to add react as a peer dependency if you are writing a react library with hooks or components.

```json
"peerDependencies": {
   "react": ">=16"
 },
```

## Typescript config

Add `tsconfig.json` file.

```json
{
  "include": ["src"],
  "compilerOptions": {
    "module": "esnext",
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "declaration": true,
    "strict": true,
    "moduleResolution": "node",
    "jsx": "react",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "emitDeclarationOnly": true,
    "outDir": "dist",
    "rootDir": "src"
  }
}
```

> we don't need to build file with typescript because we will use esbuild for that. That's why `emitDeclarationOnly` is set to true

## Write your module

Now you can write what you want. For example we will just write a function component to export.

Create src `folder` then `index.tsx` inside it.

```tsx
export const MyComponent = () => {
  return <div>Hello word</div>;
};
```

## Build your library

Now we need to build our package to CJS before publish it to npm.

### Configure esbuild

Add esbuild :

```bash
yarn add -D esbuild esbuild-node-externals
```

Create an esbuild script for the bundle. Add a file `esbuild.js` :

```js
const esbuild = require("esbuild");
const { nodeExternalsPlugin } = require("esbuild-node-externals");
esbuild
  .build({
    entryPoints: ["./src/index.ts"],
    outfile: "dist/index.js",
    bundle: true,
    minify: true,
    treeShaking: true,
    platform: "node",
    format: "cjs",
    target: "node14",
    plugins: [nodeExternalsPlugin()],
  })
  .catch(() => process.exit(1));
```

### Add a build commande

And finally add a script in your package.json :

```json
 "scripts": {
    "build": "rm -rf dist && node esbuild.js && tsc"
  },
```

Now you can run :

```bash
yarn build
```

## Npm publish

> Before publishing you need to be [authenticated](https://docs.npmjs.com/creating-a-new-npm-user-account)

Add these lines to your package.json :

```json
 "main": "dist/index.js",
  "files": [
    "dist"
  ],
```

Then publish it :

```bash
npm publish
```

Congratulations, you have published your own library.

## Publish package with Github action

Finally we just want to publish package when we trigger a github action. For that we have to add a file to `.github/workflows/publish.yml`:

```yml
name: Publish
on:
  workflow_dispatch:
    inputs:
      release:
        description: "major | minor | patch"
        required: true
        default: "patch"
        type: choice
        options:
          - major
          - minor
          - patch
jobs:
  publish-new-version:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout main
        uses: actions/checkout@v2
      - name: Use Node
        uses: actions/setup-node@v1
        with:
          node-version: "14"
          registry-url: https://registry.npmjs.org/
      - name: Install dependencies
        run: yarn
      - name: Build
        run: yarn build
      - name: Publish New Version
        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
        run: |
          git config --local user.email "myEmail"
          git config --local user.name "myUsername"
          yarn version --new-version ${{github.event.inputs.release}} --no-git-tag-version
          yarn publish --access public
          PACKAGE_VERSION=$(node -p "require('./package.json').version")
          git commit -a -m "v${PACKAGE_VERSION}"
          git push
```

### Add secret npm token

To run your action you need to add NPM_TOKEN environement variable.

Go to you npm account and generate an access token for CI :
![Npm access token](https://directus.services.lezo.dev/assets/213a95c1-1ce9-45b4-bc5c-bd23c8ea2dca)

Copy past this token in Github secret of your repository :
![Github action secret](https://directus.services.lezo.dev/assets/9bc983ff-e328-475b-ae4c-37799b7ee0f3)

Now run your github action and take a coffe.
![Trigger github action](https://directus.services.lezo.dev/assets/cb86ea78-a42a-43a3-b068-f513139573b7)

---

I'm Simon Boisset, freelance fullstack developer. I mainly work with React, React Native and Node.js. I'm available for development or consulting missions. Feel free to contact me on [my website](https://simonboisset.com).

## Related links
- [Blog index](https://simonboisset.com/en/blog)
- [Website](https://simonboisset.com/en)
