React Support

React components and server components

React Support

Packem builds React component libraries, including Server Components, Client Components, and server actions. It understands the "use client" and "use server" directives and scopes the client/server boundaries correctly so the consuming app's bundler (such as Next.js) can transform them as intended.

Quick setup

The fastest way to enable React is the add command:

npx packem add react

This will:

  • Add preset: 'react' to your config.
  • Install react, react-dom, and the Babel dependencies.
  • Detect TypeScript and add @types/react and @types/react-dom if TypeScript is installed (or prompt you to add TypeScript if it is not).

Manual configuration

The React preset configures Babel for JSX transformation:

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

export default defineConfig({
  preset: 'react',
  transformer,
})

For more control you can configure Babel directly through rollup.babel:

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

export default defineConfig({
  transformer,
  externals: ['react', 'react-dom'],
  rollup: {
    babel: {
      presets: [
        ['@babel/preset-react', { runtime: 'automatic' }],
      ],
    },
  },
})

When Babel is used with React, it runs before your main transformer (esbuild/swc/etc.), turning JSX into JavaScript. TypeScript syntax is parsed by the transformer's parser plugins, not transformed by Babel. See Plugins for more on the Babel pipeline, including parallel transforms.

Server and Client Components

Packem supports building server components and server actions with the library directives "use client" and "use server". It generates the corresponding chunks for client and server, scoping the boundaries properly. When the library is integrated into an app such as Next.js, the app bundler can transform the client components and server actions correctly.

How directives are handled:

  • If "use client" or "use server" appears in an entry file, it is preserved at the top and that entry's output file becomes a client component.
  • If "use client" or "use server" appears in a file that is used as a dependency of an entry, that file is split into a separate chunk and the directive is hoisted to the top of that chunk.
// src/button.tsx
'use client'

import { useState } from 'react'

export function Button() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

The directive on the entry above is preserved in the output, marking dist/button.js as a client component.

Shared modules across runtimes

When you build multiple runtime bundles (for example default and react-server together), some modules must remain a single shared instance across both. Use the shared module convention [name].shared-runtime.[ext] so the module is bundled into one chunk shared by every runtime bundle:

'use client'

// src/app-context.shared-runtime.js
export const AppContext = React.createContext(null)
// src/index.js
import { AppContext } from './app-context.shared-runtime'
// src/index.react-server.js
import { AppContext } from './app-context.shared-runtime'

app-context.shared-runtime is bundled into a separate chunk with only one instance, shared among the different runtime bundles. See Multi-Runtime for how the react-server and other runtime entries are wired up.

CSS in React libraries

Packem processes CSS Modules and preprocessors imported by your components. See the CSS Processing guide and the React with CSS Modules example.

Next steps

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