nextjs - ✅(Solved) Fix Turbopack `resolveAlias` doesn't resolve package subpath exports for transitive dependencies [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#88540Fetched 2026-04-08 02:04:32
View on GitHub
Comments
0
Participants
1
Timeline
11
Reactions
0
Author
Participants
Timeline (top)
referenced ×4subscribed ×3cross-referenced ×2issue_type_added ×1

Fix Action

Fix / Workaround

Workaround: use require.resolve() to get the actual file path and convert to a relative path

PR fix notes

PR #2210: feat: Integrate icu-minify into next-intl

Description (problem / solution / changelog)

<details> <summary>Prompt</summary>
i've implemented @packages/icu-minify/README.md. we now want to get this into next-intl

what i imagine is an integration like this:

- in @packages/use-intl/ we have this import for intl-messageformat. mainly the one in @packages/use-intl/src/core/createBaseTranslator.tsx is crucial, the others are secondary.
- currently, compile and format happens both in @packages/use-intl/src/core/createBaseTranslator.tsx
- use-intl should continue working like it does currently
- however, in next-intl we can plug in icu-minify parser in @packages/next-intl/src/plugin/catalog/catalogLoader.tsx. this will compile all messages at build time. something to potentially later investigate is that we might need caching here to avoid recompiling all messages for every single reload, e.g. if a single message changes
- and then, we should only use the runtime feature of icu-minify when rendering messages that were precompiled in the catalog loader
- to do this, in PluginConfig in @packages/next-intl/src/plugin/types.tsx we could add a flag like messages.precompile: true.
- when this is done, the catalog loader should precompile
- now the challenge is to get the runtime from icu-minify in. we want this to work in useTranslations (across react-server and react-client, check @packages/next-intl/package.json) as well as getTranslations.
- the way i believe we can get this working is that in use-intl, we currently have two exports: /core and /react. i think we could add two more /format-message/compile-and-format and then /format-message/format (naming tbd, if you have better ideas let me know). now the first one would be the existing logic with intl-messageformat and the latter would utilize icu-minify.
- now, in @packages/use-intl/src/core/createBaseTranslator.tsx we need to call into 'use-intl/format-message/compile-and-format'. we need to ensure this is not compiled away when running build, you should check the dist folder when you're at this point. and then the trick is: in next-intl, we can register a webpack or turbopack alias that when the plugin precompile flag is on, then we change the import to only the /format variant. and tada, that should do the trick
- side note: you might need to refactor createBaseTranslator a bit for the compile/format part to be moved to a new module/import, so the rest of the code can be shared
- maybe use-intl could remove the dependency on intl-messageformat and we only depend on icu-minify? just to have a single codepath. but: evaluate if this has perf tradeoff. and also something to explore in future

- work in new branch, commit regularly and keep a plan.md with what you're doing and what you've done

i know this is a significant ask. write down a plan how to tackle this in multiple steps and ask me as much questions upfront so i can give this to a cloud agent afterward to autonomously implement. if i've overlooked something based on your perspective, let me know
</details>

Changed files

  • CONTRIBUTORS.md (modified, +1/-1)
  • docs/src/pages/api/og-image.tsx (modified, +79/-81)
  • examples/example-app-router-extracted/next.config.ts (modified, +2/-1)
  • packages/icu-minify/.size-limit.ts (modified, +4/-4)
  • packages/icu-minify/README.md (modified, +3/-3)
  • packages/icu-minify/compile.d.ts (renamed, +1/-1)
  • packages/icu-minify/package.json (modified, +7/-7)
  • packages/icu-minify/rollup.config.js (modified, +7/-2)
  • packages/icu-minify/src/compile.tsx (renamed, +0/-0)
  • packages/icu-minify/src/format.tsx (modified, +5/-6)
  • packages/icu-minify/test/roundtrip.test.ts (modified, +135/-151)
  • packages/next-intl/.size-limit.ts (modified, +7/-7)
  • packages/next-intl/package.json (modified, +1/-0)
  • packages/next-intl/rollup.config.js (modified, +4/-1)
  • packages/next-intl/src/extractor/ExtractionCompiler.test.tsx (modified, +2/-1)
  • packages/next-intl/src/extractor/format/codecs/JSONCodec.tsx (modified, +4/-0)
  • packages/next-intl/src/extractor/types.tsx (modified, +1/-0)
  • packages/next-intl/src/navigation/shared/utils.tsx (modified, +3/-2)
  • packages/next-intl/src/plugin/catalog/catalogLoader.tsx (modified, +88/-3)
  • packages/next-intl/src/plugin/getNextConfig.tsx (modified, +34/-1)
  • packages/next-intl/src/plugin/types.tsx (modified, +4/-0)
  • packages/use-intl/.size-limit.ts (modified, +1/-1)
  • packages/use-intl/format-message.d.ts (added, +2/-0)
  • packages/use-intl/format-message/format-only.d.ts (added, +2/-0)
  • packages/use-intl/package.json (modified, +16/-3)
  • packages/use-intl/rollup.config.js (modified, +6/-2)
  • packages/use-intl/src/core/createBaseTranslator.tsx (modified, +54/-154)
  • packages/use-intl/src/core/createTranslator.format-only.test.tsx (added, +235/-0)
  • packages/use-intl/src/core/format-message/compile-format.tsx (added, +136/-0)
  • packages/use-intl/src/core/format-message/format-only.tsx (added, +33/-0)
  • packages/use-intl/src/core/format-message/index.tsx (added, +5/-0)
  • packages/use-intl/src/core/format-message/types.tsx (added, +21/-0)
  • packages/use-intl/src/react/useTranslations.test.tsx (modified, +2/-2)
  • packages/use-intl/vitest.config.mts (modified, +17/-1)
  • pnpm-lock.yaml (modified, +6466/-4010)
  • rfcs/002-icu-message-precompilation.md (modified, +89/-158)

PR #88880: Turbopack: Resolve aliases from import location for transitive deps

Description (problem / solution / changelog)

When resolveAlias is configured, the alias is currently resolved from project_path instead of from the original import location. This can cause issues when transitive dependencies try to import the aliased package, because the package might only exist in the transitive dependency's node_modules, not in the project root's node_modules.

The bug was introduced in commit f8cd413786. The intent there was to add support for conditional aliases, but it also changed the resolution base from the import site to the project root, which causes this issue.

Use None for the lookup path, which allows the resolver to use the original import location. This means:

  • Direct dependencies continue to work (resolution happens from project root)
  • Transitive dependencies now work (resolution happens from their location)

Fixes: #88540

Changed files

  • crates/next-core/src/next_import_map.rs (modified, +8/-22)
  • test/e2e/resolve-alias-transitive/app/layout.tsx (added, +7/-0)
  • test/e2e/resolve-alias-transitive/app/page.tsx (added, +9/-0)
  • test/e2e/resolve-alias-transitive/next.config.js (added, +15/-0)
  • test/e2e/resolve-alias-transitive/node_modules/wrapper-pkg/index.js (added, +5/-0)
  • test/e2e/resolve-alias-transitive/node_modules/wrapper-pkg/node_modules/test-pkg/foo/alt.js (added, +2/-0)
  • test/e2e/resolve-alias-transitive/node_modules/wrapper-pkg/node_modules/test-pkg/foo/default.js (added, +2/-0)
  • test/e2e/resolve-alias-transitive/node_modules/wrapper-pkg/node_modules/test-pkg/package.json (added, +8/-0)
  • test/e2e/resolve-alias-transitive/node_modules/wrapper-pkg/package.json (added, +5/-0)
  • test/e2e/resolve-alias-transitive/resolve-alias-transitive.test.ts (added, +17/-0)

Code Example

git clone https://github.com/amannn/nextjs-bug-repro-turbo-alias
pnpm install
pnpm run dev
open http://localhost:3000

---

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 24.6.0: Wed Nov  5 21:30:23 PST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_X86_64
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 22.21.1
  npm: 10.9.4
  Yarn: 1.22.22
  pnpm: 10.24.0
Relevant Packages:
  next: 16.1.1-canary.27 // Latest available version is detected (16.1.1-canary.27).
  eslint-config-next: N/A
  react: 19.2.3
  react-dom: 19.2.3
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/amannn/nextjs-bug-repro-turbo-alias

To Reproduce

git clone https://github.com/amannn/nextjs-bug-repro-turbo-alias
pnpm install
pnpm run dev
open http://localhost:3000

Relevant files:

Current vs. Expected behavior

CurrentExpected
Page displays"original""aliased"
Module loadedtest-pkg/foodist/foo.jstest-pkg/foo/altdist/foo-alt.js

The alias works correctly when test-pkg is a direct dependency, but fails when it's a transitive dependency (nested in wrapper-pkg/node_modules).

Provide environment information

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 24.6.0: Wed Nov  5 21:30:23 PST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_X86_64
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 22.21.1
  npm: 10.9.4
  Yarn: 1.22.22
  pnpm: 10.24.0
Relevant Packages:
  next: 16.1.1-canary.27 // Latest available version is detected (16.1.1-canary.27).
  eslint-config-next: N/A
  react: 19.2.3
  react-dom: 19.2.3
  typescript: 5.9.3
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), next build (local), next start (local)

Additional context

Workaround: use require.resolve() to get the actual file path and convert to a relative path

extent analysis

TL;DR

  • The issue can be mitigated by adjusting the resolveAlias configuration in next.config.ts to correctly handle transitive dependencies.

Guidance

  • Review the next.config.ts file and update the resolveAlias configuration to account for the nested dependency structure.
  • Verify that the test-pkg package is correctly resolved when it's a transitive dependency by checking the module loading path in the browser's developer tools.
  • Consider using the suggested workaround of utilizing require.resolve() to obtain the actual file path and converting it to a relative path for more accurate aliasing.
  • Test the updated configuration with both direct and transitive dependencies to ensure the alias works as expected in all scenarios.

Example

// In next.config.ts, update the resolveAlias configuration
module.exports = {
  //...
  resolve: {
    alias: {
      // Adjust the alias to correctly handle transitive dependencies
      'test-pkg': require.resolve('test-pkg/dist/index.js'),
    },
  },
};

Notes

  • The provided example is a simplified illustration and might need adjustments based on the actual project structure and requirements.
  • The issue seems to be related to how Next.js handles aliases with transitive dependencies, particularly with Turbopack.

Recommendation

  • Apply workaround: Utilize require.resolve() to get the actual file path and convert it to a relative path for accurate aliasing, as this approach allows for more flexibility in handling different dependency structures.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Turbopack `resolveAlias` doesn't resolve package subpath exports for transitive dependencies [2 pull requests, 1 participants]