Skip to content

Fix #3741: avoid duplicate-source re-export in motion/react that crashed Turbopack#3743

Open
mattgperry wants to merge 1 commit into
mainfrom
fix-3741-turbopack-oom
Open

Fix #3741: avoid duplicate-source re-export in motion/react that crashed Turbopack#3743
mattgperry wants to merge 1 commit into
mainfrom
fix-3741-turbopack-oom

Conversation

@mattgperry
Copy link
Copy Markdown
Collaborator

The bug

motion@12.40.0 causes Next.js 16.2.6's Turbopack dev server to OOM during compilation on Windows. Switching to framer-motion in the same project compiles fine. Symptoms from the reporter:

Fatal JavaScript out of memory: MemoryChunk allocation failed during deserialization.
Fatal process out of memory: Failed to reserve virtual memory for CodeRange.
FATAL ERROR: JavaScript heap out of memory.

Fixes #3741

The cause

packages/motion/src/react.ts had two re-export statements pulling from the same module:

export { motion, m } from "framer-motion"
export * from "framer-motion"

After Rollup, the published motion/dist/es/react.mjs looked like:

export * from 'framer-motion';
export { m, motion } from 'framer-motion';

This duplicate-source re-export pattern is the only structural difference between motion/react and importing framer-motion directly — and it's where Turbopack's module-graph analyser appears to chew through memory on Windows. The named line was added in commit aacf1e0e3 to make IDE auto-import suggest motion and m (#3432); the wildcard already covered them, so the pattern was effectively a duplicate.

The fix

Re-export motion and m through a namespace import + local const aliases. The compiled react.mjs becomes:

import * as fm from 'framer-motion';
export * from 'framer-motion';

const motion = fm.motion;
const m = fm.m;

export { m, motion };

Per the ES spec, local exports shadow the names that export * would have pulled in, so motion and m come from the explicit bindings and everything else from the wildcard. There's now a single from 'framer-motion' chain in the module graph for Turbopack to follow — no duplicate to choke on. The explicit export { m, motion } keeps the IDE auto-import fix from #3432 intact.

Verification

  • yarn build succeeds. Compiled motion/dist/es/react.mjs and react.d.ts are clean (single wildcard, no duplicate from 'framer-motion').
  • yarn test passes — 797 tests, 7 skipped, 0 new failures.
  • IDE auto-import for motion and m from motion/react is preserved (explicit named exports still in the .d.ts output).

Caveat

The OOM is environment-specific (Windows + Next.js 16 Turbopack + pnpm) and I couldn't reproduce it locally on macOS. The fix targets the only meaningful structural difference between motion and framer-motion from a bundler's perspective: the duplicate-source re-export pattern. If the reporter can re-test against this branch and confirm the OOM is gone, we can land confidently.

🤖 Generated with Claude Code

The previous `motion/src/react.ts` had two re-export statements pulling
from the same module:

    export { motion, m } from "framer-motion"
    export * from "framer-motion"

When compiled to ESM and loaded by Next.js 16's Turbopack on Windows,
this duplicate-source pattern caused the dev server to OOM during
module-graph analysis (#3741). Importing `framer-motion` directly worked
fine, since framer-motion's own index never re-exports from the same
source twice.

Switching to an `import * as fm from "framer-motion"` + `const` alias
keeps the explicit `motion`/`m` exports that IDE auto-import relies on
(#3432) without the duplicate-source pattern. Per the ES spec, local
declarations shadow the names from `export * from "framer-motion"`, so
the compiled output now has a single wildcard re-export plus two local
const bindings — a shape Turbopack handles cleanly.

Fixes #3741

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR fixes a Turbopack OOM crash by removing a duplicate-source re-export pattern in packages/motion/src/react.ts. The previous file had both export { motion, m } from "framer-motion" and export * from "framer-motion" pointing at the same source module, which caused Turbopack's module-graph analyser to exhaust memory on Windows.

  • Replaces the duplicate named re-export with a namespace import (import * as fm) and local export const aliases, so the compiled .mjs has a single from 'framer-motion' edge in the module graph while still emitting explicit named exports for motion and m (preserving IDE auto-import from [BUG] vscode intellisense import: not listing motion from motion/react #3432).
  • All other entry points (react-m.ts, react-mini.ts, react-client.ts) use plain export * with a single source and are unaffected.

Confidence Score: 5/5

Safe to merge — the change is a minimal, targeted rewrite of a single 16-line file with no behavioral change for consumers.

The fix correctly eliminates the duplicate-source re-export by using a namespace import plus local const aliases. Per the ES spec, the explicit export const motion and export const m declarations shadow the wildcard, so consumers see identical public exports. The typeof fm.motion type annotations preserve declaration-file fidelity. The compiled CJS and ESM outputs are both clean. The other entry points in the motion package are unaffected.

No files require special attention.

Important Files Changed

Filename Overview
packages/motion/src/react.ts Replaces duplicate-source re-export pattern with namespace import + local const aliases to fix Turbopack OOM; fix is mechanically correct per ES spec and preserves IDE auto-import behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before (caused Turbopack OOM)"]
        B_consumer["Consumer\nimport { motion } from 'motion/react'"]
        B_react["motion/react\nexport { motion, m } from 'framer-motion'\nexport * from 'framer-motion'"]
        B_fm["framer-motion"]
        B_consumer --> B_react
        B_react -->|"edge 1: named re-export"| B_fm
        B_react -->|"edge 2: wildcard re-export (duplicate!)"| B_fm
    end

    subgraph After["After (fix)"]
        A_consumer["Consumer\nimport { motion } from 'motion/react'"]
        A_react["motion/react\nimport * as fm from 'framer-motion'\nexport const motion = fm.motion\nexport const m = fm.m\nexport * from 'framer-motion'"]
        A_fm["framer-motion"]
        A_consumer --> A_react
        A_react -->|"single module-graph edge"| A_fm
    end
Loading

Reviews (1): Last reviewed commit: "Fix Turbopack OOM by avoiding duplicate-..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] motion@12.40.0 causes Next.js 16.2.6 Turbopack dev server to run out of memory on Windows

1 participant