Skip to content

fix(dynamic): stub non-compilable dynamic imports to Promise.resolve({}) - #222

Open
techfreaque wants to merge 1 commit into
vercel-labs:mainfrom
techfreaque:fix-dynamic-tsx-stub
Open

fix(dynamic): stub non-compilable dynamic imports to Promise.resolve({})#222
techfreaque wants to merge 1 commit into
vercel-labs:mainfrom
techfreaque:fix-dynamic-tsx-stub

Conversation

@techfreaque

Copy link
Copy Markdown

Problem

In --dynamic mode, two categories of dynamic import() calls crashed or emitted SC1090:

1. .tsx files (JSX): dynamicImportProgramTargetOf did not exclude .tsx files, so they were treated as compilable program modules. The native compiler cannot lower JSX — these imports should resolve to an empty namespace.

2. Program modules with no compilation story: when a module IS in the TypeScript checker's program (dep !== null) but has no %init produced — e.g. a module explicitly excluded from the compiled graph, or one that transitively imports features the native compiler cannot lower — lowerOwnModuleImport fell through to an unconditional SC1090. There was no graceful fallback.

Fix

lower-modules.tsdynamicImportProgramTargetOf returns null for .tsx files, keeping them out of the compiled module graph (they won't be visited by appendDynamicImportModules and won't get a %dynns builder).

lower-island.tslowerOwnModuleImport: when dep !== null (checker resolved to a source file) but builder === null (no compilation story) in --dynamic mode, stubs the import to Promise.resolve({}) — a JSVAL promise that settles to an empty object. Callers that destructure the namespace receive undefined for every export, which is the correct behavior when the module is intentionally not compiled natively.

Non-goals

This PR does not add a mechanism for users to explicitly exclude specific modules from compilation — that is a separate feature. It fixes the two structural cases where the compiler should already know the answer (.tsx = not compilable, builder === null = not in compiled graph).

Verification

Dynamic imports of .tsx files and modules not in the compiled graph now produce Promise.resolve({}) in --dynamic builds instead of SC1090. packages/compiler builds clean.

@vercel

vercel Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

@techfreaque is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread packages/compiler/src/frontend/lowering/lower-modules.ts Outdated
Two related gaps in --dynamic mode:

1. .tsx files (JSX): `dynamicImportProgramTargetOf` now returns null for
   .tsx files, keeping them out of the compiled module graph. The
   `lowerOwnModuleImport` path then stubs the import to
   `Promise.resolve({})` via the new `dep !== null && L.dynamic` branch.

2. Program modules with no builder: when a module IS in the checker's
   program (dep !== null) but has no compilation story — no %init was
   produced, e.g. a module that was explicitly excluded from the compiled
   graph — the compiler previously emitted SC1090 unconditionally. In
   --dynamic mode, this now stubs to `Promise.resolve({})` instead.
   Callers that destructure the namespace receive `undefined` for every
   export, which is the correct behavior when the module is not
   reachable from the native binary.

These two changes together cover the common --dynamic pattern of lazy
module loading where some targets are intentionally not compiled
natively (JSX widgets, server-only modules).
@techfreaque
techfreaque force-pushed the fix-dynamic-tsx-stub branch from 09dbf0b to 1c90ad0 Compare August 23, 2026 20:47
@techfreaque

Copy link
Copy Markdown
Author

Fixed in 1c90ad0 — extended the guard to .endsWith(".tsx") || .endsWith(".jsx") so ESM .jsx files also resolve to the empty namespace stub at runtime rather than reaching the native compiler's JSX crash.

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.

1 participant