Files
danandGitHub 4ebf4bd6aa Only track pending imports for real promises (#95789)
Extracted from https://github.com/vercel/next.js/pull/95468.

Fixes a module with `then` export hanging the module tracking during the
build.

---

`trackPendingImport` needs to track actually async modules (top-level
await).

Before this change, this codepath was happy to adopt any thenable. But
since thenables may not be Promises, this could break things downstream,
hence why we had `Promise.resolve` there.

However, we don't *want* to adopt arbitrary thenables here. **Tracking
is for top-level awaited modules.** For example, `module.exports = new
Promise(() => {})` has a `.then` but we don't want to track that. It's
not TLA.

This is why, to catch real top-level await modules, we narrow the check
to `instanceof Promise`.

We add tests for:

- A client module with a `then` function export (**hangs** on Turbopack
before this PR with CC on)
- Exporting a literal Promise (works before and after, but worth testing
for future regressions)
2026-07-15 10:49:05 +01:00

21 lines
793 B
TypeScript

import { nextTestSetup } from 'e2e-utils'
describe('client-module-then-export', () => {
const { next } = nextTestSetup({
files: __dirname,
skipStart: true,
})
// A client module that exports a function named `then` has thenable
// exports, even though it is not an async module. If module tracking
// mistakes it for a pending async module, awaiting it calls the `then`
// export instead of settling, and the build hangs in the cache warming
// phase. A module whose exports object literally is a promise
// (promise-exports.js) must not hang the build either, even though the
// promise never settles.
it('builds pages that render client modules that export `then`', async () => {
const { exitCode } = await next.build()
expect(exitCode).toBe(0)
})
})