nx/docs/shared/recipes/tips-n-tricks/compile-multiple-formats.md
Jack Hsu 66eaf2fc74
docs(misc): remove /nx-api pages (#31453)
This PR removes the `/nx-api` pages from `nx-dev`. They are already
redirected from `/nx-api` to either `/technologies` or
`/reference/core-api` URLs.

e.g. `/nx-api/nx` goes to `/reference/core-api/nx` and `/nx-api/react`
goes to `/technologies/react/api`

**Changes**:
- Remove old `nx-api.json` from being generated in
`scripts/documentation/generators/generate-manifests.ts` -- this was
used to generate the sitemap
- Remove `pages/nx-api` from Next.js app since we don't need them
- Remove workaround from link checker
`scripts/documentation/internal-link-checker.ts` -- the angular
rspack/rsbuild and other workarounds are gone now that they are proper
docs in `map.json`
- Update Powerpack/Remote Cache reference docs to exclude API documents
(since they are duplicated in the Intro page) --
`nx-dev/models-document/src/lib/mappings.ts`
- All content in `docs` have been updated with new URL structure

**Note:** Redirects are already handled, and Claude Code was used to
verify the updated `docs/` URLs (see report below). The twelve 404s
links were updated by hand.

## Verification Report

https://gist.github.com/jaysoo/c7863fe7e091cb77929d1976165c357a
2025-06-04 16:57:01 -04:00

3.5 KiB

title description
Compile TypeScript Libraries to Multiple Formats Learn how to use Nx with Rollup to compile TypeScript libraries to both ESM and CommonJS formats for maximum compatibility.

Compile Typescript Libraries to Multiple Formats

{% youtube src="https://youtu.be/Vy4d0-SF5cY" title="Packaging Typescript Lbraries" width="100%" /%}

It can be difficult to set up a typescript library to compile to ESM and CommonJS. As of Nx 16.8, you can use the @nx/rollup:rollup executor to take care of it for you.

Use Rollup to Compile your TypeScript Project

If you do not use Rollup already, install the corresponding Nx plugin as follows:

nx add @nx/rollup

Make sure the version of @nx/rollup matches your other @nx/* package versions.

You can then configure Rollup to compile your library by adding a build target to your project.json or package.json file. Here's an example:

{% tabs %} {%tab label="package.json"%}

{
  "name": "my-awesome-lib",
  "nx": {
    "targets": {
      "build": {
        "executor": "@nx/rollup:rollup",
        "options": {
          "main": "packages/my-awesome-lib/src/index.ts"
        }
      }
    }
  }
}

{% /tab%} {%tab label="project.json"%}

{
  "name": "my-awesome-lib",
  "targets": {
    "build": {
      "executor": "@nx/rollup:rollup",
      "options": {
        "main": "packages/my-awesome-lib/src/index.ts"
      }
    }
  }
}

{% /tab%} {% /tabs %}

If you happen to use the @nx/js:tsc executor already, you can also use the Rollup configuration generator from the Nx Rollup plugin to automatically configure your project's build target.

Configure Rollup to Create Multiple Formats

You'll need to specify format, additionalEntryPoints and generateExportsField in the executor options. Here's an example:

{
  "name": "my-awesome-lib",
  "targets": {
    "build": {
      "executor": "@nx/rollup:rollup",
      "options": {
        "main": "packages/my-awesome-lib/src/index.ts",
        "format": ["esm", "cjs"],
        "additionalEntryPoints": ["packages/my-awesome-lib/src/foo.ts"],
        "generateExportsField": true
      }
    }
  }
}

After compiling our package using nx build my-awesome-lib we'll get the following output in our dist folder.

my-awesome-lib
└─ .
   ├─ README.md
   ├─ foo.cjs.d.ts
   ├─ foo.cjs.js
   ├─ foo.esm.js
   ├─ index.cjs.d.ts
   ├─ index.cjs.js
   ├─ index.esm.js
   ├─ package.json
   └─ src
      ├─ foo.d.ts
      ├─ index.d.ts
      └─ lib
         └─ my-awesome-lib.d.ts

And our package.json will look like this:

{
  "name": "my-awesome-lib",
  "version": "0.0.1",
  ...
  "type": "commonjs",
  "main": "./index.cjs.js",
  "typings": "./src/index.d.ts",
  "exports": {
    "./package.json": "./package.json",
    ".": {
      "import": "./index.esm.js",
      "default": "./index.cjs.js"
    },
    "./foo": {
      "import": "./foo.esm.js",
      "default": "./foo.cjs.js"
    }
  },
  "module": "./index.esm.js"
}

Now consumers of your package can access the appropriate format for their codebase and you don't have to worry about maintaining the infrastructure to compile to both formats.