Return

RSC Directives and Bundler Limitations

ARCHITECTURE

Situation

The @juun/ui package contained 64 shadcn/ui components with "use client" directives for React Server Components. Attempted to build the package with multiple bundlers (tsup, pkgroll, unbuild, vite) to avoid using transpilePackages in Next.js. All bundlers stripped "use client" directives during the build process, breaking client-side functionality.

Task

  • Build UI package with preserved "use client" directives
  • Remove dependency on transpilePackages configuration
  • Maintain proper RSC boundary markers

Action

1. Tested Multiple Bundlers

tsup (esbuild-based):

  • Configured with component glob patterns
  • Result: "use client" directives stripped with warning: "Module level directives cause errors when bundled"

pkgroll (esbuild-based):

  • Zero-config library bundler
  • Result: Same issue - directives removed during minification

unbuild (Rollup-based):

  • Added path alias resolution for @/ imports
  • Set failOnWarn: false to bypass warnings
  • Result: Directives still stripped by Rollup's tree-shaking

vite (Rollup + esbuild):

  • Library mode with preserveModules: true
  • Configured glob-based entry resolution
  • Result: Same fundamental issue

2. Root Cause Analysis

All modern JavaScript bundlers treat "use client" as:

  • Dead code (no runtime effect)
  • Module-level directive (removed during minification)
  • Unknown pragma (pre-RSC bundler design)

No standard plugin exists to preserve RSC directives across bundlers.

3. Architectural Decision

Migrated all UI components directly into apps/web:

  • 64 componentsapps/web/components/ui/
  • Utilitiesapps/web/lib/utils.ts
  • Hooksapps/web/hooks/
  • Updated imports from @juun/ui/* to @/components/ui/*
  • Removed @juun/ui from transpilePackages
  • Deleted packages/ui/ entirely

Result

  • "use client" directives preserved naturally (no bundling)
  • Eliminated build pipeline complexity
  • Removed workspace package overhead
  • Faster HMR (no cross-package watching needed)
  • Simpler dependency management

This isn't just a monorepo size issue - RSC-aware component libraries cannot be properly bundled with current tooling. The bundler ecosystem lacks support for React Server Components directives. Until bundlers are updated or new RSC-aware build tools emerge, keeping RSC components in-app is the pragmatic choice, regardless of project scale.

This represents a fundamental gap between React's RSC architecture and existing JavaScript bundler design.