Link to the code that reproduces this issue
https://github.com/cultureamp/turbopack-sidecar-treeshaking-repro
To Reproduce
npm install
npm run build – ❌ Turbopack (Next's default bundler) — build FAILS at prerender: "Error: Sidecar medium not found"
npm run build:webpack – ✅ webpack — same config, builds fine
Current vs. Expected behavior
With experimental.optimizePackageImports containing both react-focus-on and react-focus-lock, a production Turbopack build tree-shakes react-focus-lock's side-effect-only sidecar module out of the bundle. That module's sole purpose is a registration side-effect (exportSidecar(mediumSidecar, FocusTrap)); with it gone, rendering any focus trap throws:
Error: Sidecar medium not found
react-focus-lock's package.json marks the module side-effectful via a sideEffects allowlist (["**/sidecar.js", "**/index.js"]), so it should be retained. webpack retains it; Turbopack drops it when the import is rewritten by optimizePackageImports.
Expected
optimizePackageImports should not cause a module in the target package's sideEffects allowlist to be dropped. Turbopack should honour sideEffects for side-effect-only (bare) imports even when the barrel import is rewritten by the optimization.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.5.0: Tue Jun 9 22:28:34 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T6041
Available memory (MB): 49152
Available CPU cores: 14
Binaries:
Node: 26.5.0
npm: 11.17.0
Yarn: N/A
pnpm: 10.34.5
Relevant Packages:
next: 16.3.0-canary.102 // Latest available version is detected (16.3.0-canary.102).
eslint-config-next: N/A
react: 19.2.8
react-dom: 19.2.8
typescript: N/A
Next.js Config:
output: N/A
Note: Above-linked repro repo is on Next 16.2.11, but I've verified it still reproduces with the current canary.
Which area(s) are affected? (Select all that apply)
Turbopack
Which stage(s) are affected? (Select all that apply)
next build (local)
Additional context
- Reproduces only in a production Turbopack build;
next dev, next build --webpack, unit tests, and Storybook all pass — so it typically surfaces only in deployed apps.
- Impact is broad:
optimizePackageImports is widely used (Next enables it by default for many packages; design systems add their own), and most modal/popover/menu components transitively use react-focus-on / react-focus-lock.
react-remove-scroll uses the same sidecar pattern and is likely affected the same way.
Link to the code that reproduces this issue
https://github.com/cultureamp/turbopack-sidecar-treeshaking-repro
To Reproduce
npm installnpm run build– ❌ Turbopack (Next's default bundler) — build FAILS at prerender:"Error: Sidecar medium not found"npm run build:webpack– ✅ webpack — same config, builds fineCurrent vs. Expected behavior
With
experimental.optimizePackageImportscontaining bothreact-focus-onandreact-focus-lock, a production Turbopack build tree-shakes react-focus-lock's side-effect-onlysidecarmodule out of the bundle. That module's sole purpose is a registration side-effect (exportSidecar(mediumSidecar, FocusTrap)); with it gone, rendering any focus trap throws:react-focus-lock's
package.jsonmarks the module side-effectful via asideEffectsallowlist (["**/sidecar.js", "**/index.js"]), so it should be retained. webpack retains it; Turbopack drops it when the import is rewritten byoptimizePackageImports.Expected
optimizePackageImportsshould not cause a module in the target package'ssideEffectsallowlist to be dropped. Turbopack should honoursideEffectsfor side-effect-only (bare) imports even when the barrel import is rewritten by the optimization.Provide environment information
Which area(s) are affected? (Select all that apply)
Turbopack
Which stage(s) are affected? (Select all that apply)
next build (local)
Additional context
next dev,next build --webpack, unit tests, and Storybook all pass — so it typically surfaces only in deployed apps.optimizePackageImportsis widely used (Next enables it by default for many packages; design systems add their own), and most modal/popover/menu components transitively usereact-focus-on/react-focus-lock.react-remove-scrolluses the same sidecar pattern and is likely affected the same way.