[Bug]: tree shaking breaks with dynamic import() in some situation
- Dominant language
- Go
- Stars
- 40.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
### System Info
```
System:
OS: macOS 15.5
CPU: (10) arm64 Apple M1 Max
Memory: 2.34 GB / 64.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.4.1 - ~/.volta/tools/image/node/24.4.1/bin/node
pnpm: 10.13.1 - ~/.volta/tools/image/pnpm/10.13.1/bin/pnpm
Watchman: 2025.07.28.00 - /opt/homebrew/bin/watchman
npmPackages:
esbuild: ^0.25.8 => 0.25.8
```
### Details
If you have a file `foo.ts` that contains 2 exports:
```ts
// foo.ts
export const bar = 'bar';
export const paz = 'paz';
```
Tree shaking will work (aka the unused variable will be stripped out during compilation) when writing:
```ts
// stripped.ts
import { bar } from './foo';
```
But if the file is lazy loaded using `import()`, `paz` is kept in the bundle:
```ts
// kept.ts
const { bar } = await import('./foo');
import('./foo').then(module => module.bar);
import('./foo').then(({ bar }) => bar);
```
The config I used is a simple one:
```json
{
"bundle": true,
"treeShaking": true,
"splitting": true,
"format": "esm",
"outdir": ".",
"write": false
}
```
### Reproduce link
https://github.com/Ayc0/code-splitting-issue
### Reproduce Steps
You can clone https://github.com/Ayc0/code-splitting-issue and run `node --test tests/esbuild.test.mjs` (requires node 24.4.0+)
Contributor guide
No contributing guide indexed for this repository
Research direction
Clone the linked code-splitting-issue repository and run node --test tests/esbuild.test.mjs with Node 24.4.0 or newer to reproduce the dynamic import cases. Compare the generated bundle with the static import case; done means the unused paz export is removed while bar remains available for each shown import pattern.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, javascript, node.js, typescript
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100