Multi-Runtime

Target multiple runtimes with conditional exports

Multi-Runtime

Packem can build a single source tree into runtime-specific bundles by reacting to the special export conditions in your package.json. Conditions like node, browser, react-server, and edge-light are treated as distinct platforms, each with its own input source file and output bundle.

Overview

Packem supports the following runtimes out of the box:

  • default
  • node
  • browser
  • react-server
  • edge-light

For special platform conditions such as react-server and edge-light, Packem provides an override input source file convention: name a source file with the runtime suffix and Packem will compile it as a separate bundle for that condition.

:::note The edge-light export injects a process.env.EdgeRuntime variable that is true; for every other runtime it resolves to false. :::

Project Structure

multi-runtime-example/
├── src/
│   ├── index.ts                 # default / import condition
│   ├── index.react-server.ts    # react-server condition
│   └── index.edge-light.ts      # edge-light condition
├── package.json
├── packem.config.ts
└── tsconfig.json

Source Files

src/index.ts

export function getRuntime(): string {
  return 'node'
}

src/index.react-server.ts

// Compiled into a dedicated react-server bundle
export function getRuntime(): string {
  return 'react-server'
}

src/index.edge-light.ts

// process.env.EdgeRuntime is true in this bundle
export function getRuntime(): string {
  return process.env.EdgeRuntime ? 'edge-light' : 'node'
}

Configuration

The conditional exports map drives the whole build. Packem reads it, matches the special conditions to the suffixed source files, and emits one bundle per condition.

package.json

{
  "name": "@myorg/multi-runtime",
  "version": "1.0.0",
  "type": "module",
  "files": ["dist"],
  "exports": {
    ".": {
      "react-server": "./dist/index.react-server.mjs",
      "edge-light": "./dist/index.edge-light.mjs",
      "import": "./dist/index.mjs"
    }
  },
  "scripts": {
    "build": "packem build"
  },
  "devDependencies": {
    "@visulima/packem": "^2"
  }
}

packem.config.ts

import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'

export default defineConfig({
  transformer,
  declaration: true
})

Per-Entry Runtime

When you configure entries explicitly, each entry carries its own runtime value. The supported runtimes are browser, bun, deno, edge-light, electron, node, react-native, react-server, and workerd.

import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'

export default defineConfig({
  transformer,
  entries: [
    { input: 'src/index.ts', runtime: 'node' },
    { input: 'src/index.edge-light.ts', runtime: 'edge-light' }
  ]
})

Build Output

$ packem build

dist/index.mjs                 # default / node
dist/index.react-server.mjs    # react-server condition
dist/index.edge-light.mjs      # edge-light condition (EdgeRuntime === true)

Notes

  • Only the special platform conditions (react-server, react-native, edge-light) get their own input override file; the remaining conditions resolve against the default source.
  • Combine this with Shared Modules when several runtime bundles must share a single instance of a module.
  • See the Multi-Runtime guide for the full conditional-exports reference.
Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues