vercel/next.js

Turbopack does not handle CommonJS modules properly when "type": "commonjs" is specified in package.json

Opened this issue · 1 comments

Link to the code that reproduces this issue

https://github.com/saoudi-h/commonjs-issue-next-turbopack

To Reproduce

Create a Next.js app using npx create-next-app.
Install Jotai (pnpm install jotai) or any other library that specifies "type": "commonjs" in its package.json.
Run the application with Turbopack enabled (next dev --turbopack).
Import the library into your project and attempt to use it.

Current vs. Expected behavior

Current Behavior: The application throws an error due to an incompatibility between the "type": "commonjs" field in the library's package.json and Turbopack's handling of ESModules. This breaks the development server and prevents the application from running.

Expected Behavior: Turbopack should handle CommonJS modules seamlessly, as per the Node.js module resolution standards, regardless of the "type" field in package.json.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32695
  Available CPU cores: 16
Binaries:
  Node: 20.11.1
  npm: 10.2.4
  Yarn: 1.22.19
  pnpm: 8.15.3
Relevant Packages:
  next: 15.1.1 // Latest available version is detected (15.1.1).
  eslint-config-next: 15.1.1
  react: 19.0.0
  react-dom: 19.0.0
  typescript: 5.7.2
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Turbopack

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

This issue was initially observed in a discussion in the Jotai repository. The maintainer pointed out that Turbopack does not respect the "type": "commonjs" field, leading to incompatibilities with libraries that follow the Node.js module conventions. While workarounds like patching the affected library or modifying its package.json exist, the root cause seems to be Turbopack's handling of CommonJS modules.

It would be great to address this issue as it could impact many libraries and developers using Turbopack in their Next.js projects.

Hmm, It looks like this is a bug in the transform we do when a 'use client' directive is encountered. I think what's happening is that we're creating a virtual file that uses ESM import/export syntax, but it's called proxy.js (not proxy.mjs), so the "type": "commonjs" makes turbopack "correctly" upset at the ESM syntax.


if we look at the full error message, we can notice it's happening in a that file doesn't actually exist in node_modules:

./node_modules/<SNIP>/jotai/esm/react.mjs/proxy.js
                                         ^^^^^^^^^
                                       this bit here! 
    

Specified module format (CommonJs) is not matching the module format of the source code (EcmaScript Modules)
The CommonJs module format was specified in the package.json that is affecting this source file or by using an special extension, but Ecmascript import/export syntax is used in the source code.
The module was automatically converted to an EcmaScript module, but that is in conflict with the specified module format. Either change the "type" field in the package.json or replace EcmaScript import/export syntax with CommonJs syntas in the source file.
In some cases EcmaScript import/export syntax is added by an transform and isn't actually part of the source code. In these cases revisit transformation options to inject the correct syntax.

here's the bit that adds the proxy.js suffix to the exiting module path
https://github.com/vercel/next.js/blob/c92e84529620e732309671baf93b9ae6b68e7544/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs/#L148-L152