import { Callout } from "../../../../../components/Callout";
import { Tabs, Tab } from "../../../../../components/Tabs";

# Bundling packages in a Monorepo

Unlike [internal](/repo/docs/handbook/sharing-code/internal-packages) packages, external packages can be deployed to [npm](https://www.npmjs.com) _and_ used locally. In this guide, we'll bundle a package to both [ECMAScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (`esm`) and [CommonJS modules](https://en.wikipedia.org/wiki/CommonJS) (`cjs`), the most commonly used formats on npm.

## Setting up a build script

Let's start with a package created using our [internal packages](/repo/docs/handbook/sharing-code/internal-packages) tutorial.

There, we created a `math-helpers` package which contained a few helper functions for adding and subtracting. We've decided that this package is good enough for npm, so we're going to bundle it.

At the end of that tutorial, we had a package set up under `/packages`, which looked like this:

```
├── apps
│   └── web
│       └── package.json
├── packages
│   └── math-helpers
│       ├── src
│       │   └── index.ts
│       ├── tsconfig.json
│       └── package.json
├── package.json
└── turbo.json
```

We're going to add a `build` script to `math-helpers`, using a bundler. If you're unsure which one to choose, we recommend [`tsup`](https://tsup.egoist.dev/).

<Tabs items={['tsup']} storageKey="selected-bundler">
  <Tab>

First install, `tsup` inside `packages/math-helpers` using your [package manager](/repo/docs/handbook/package-installation).

```json filename="packages/math-helpers/package.json"
{
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts"
  }
}
```

`tsup` outputs files to the `dist` directory by default, so you should:

1. Add `dist` to your `.gitignore` files to make sure they aren't committed by `git`.
2. Add `dist` to the outputs of `build` in your `turbo.json`.

```json filename="turbo.json"
{
  "pipeline": {
    "build": {
      "outputs": ["dist/**"]
    }
  }
}
```

That way, when `tsup` is run the outputs can be [cached](/repo/docs/core-concepts/caching) by Turborepo.

Finally, we should update our package entrypoints. Inside `package.json`, change `main` to point at `./dist/index.js` for clients using CommonJS modules (`cjs`), `module` to point at `./dist/index.mjs` for clients using ECMAScript modules (`esm`), and `types` to the type definition file - `./dist/index.d.ts`:

```json filename="packages/math-helpers/package.json"
{
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts"
}
```

<Callout>

It is not required to bundle to both `cjs` and `esm`. However, it is recommended, as it allows your package to be used in a wider variety of environments.

If you run into errors by using `main`, `module` and `types`, take a look at the [tsup docs](https://tsup.egoist.dev/#bundle-formats).

Bundling is a complicated topic, and we don't have space here to cover everything!

</Callout>

  </Tab>
</Tabs>

### Building our package before our app

Before we can run `turbo run build`, there's one thing we need to consider. We've just added a [task dependency](/repo/docs/core-concepts/monorepos/running-tasks) into our monorepo. The `build` of `packages/math-helpers` needs to run **before** the `build` of `apps/web`.

Fortunately, we can use `dependsOn` to easily configure this.

```json filename="turbo.json"
{
  "pipeline": {
    "build": {
      "dependsOn": [
        // Run builds in workspaces I depend on first
        "^build"
      ]
    }
  }
}
```

Now, we can run `turbo run build`, and it'll automatically build our packages _before_ it builds our app.

## Setting up a dev script

There's a small issue with our setup. We are building our package just fine, but it's not working great in dev. Changes that we make to our `math-helpers` package aren't being reflected in our app.

That's because we don't have a `dev` script to rebuild our packages while we're working. We can add one easily:

<Tabs items={['tsup']} storageKey="selected-bundler">
  <Tab>

```json filename="packages/math-helpers/package.json"
{
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "npm run build -- --watch"
  }
}
```

This passes the `--watch` flag to `tsup`, meaning it will watch for file changes.

  </Tab>
</Tabs>

If we've already set up [dev scripts](/repo/docs/handbook/dev) in our `turbo.json`, running `turbo run dev` will run our `packages/math` dev task in parallel with our `apps/web` dev task.

## Summary

Our package is now in a spot where we can consider deploying to npm. In our [versioning and publishing](/repo/docs/handbook/publishing-packages/versioning-and-publishing) section, we'll do just that.
