Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolveExtensions not honoring .web.tsx when listed after .tsx for node_modules dependencies #4053

Closed
Bram-dc opened this issue Jan 27, 2025 · 2 comments

Comments

@Bram-dc
Copy link

Bram-dc commented Jan 27, 2025

I originally reported this issue to Vite, but the problem seems to originate in esbuild. (original issue)

When setting resolveExtensions to prioritize .web.tsx after .tsx, esbuild still picks up .tsx variants first in node_modules, even though it behaves correctly in local src code. Placing all .web entries before the non-web ones works around the issue, but it seems resolveExtensions is ignoring the intended ordering for packages in node_modules. It does work fine in files in the ./src directory for example.

Expected Behavior
Listing .web.tsx after .tsx in resolveExtensions should correctly pick up the .web.tsx variant for files in node_modules, just like it does for local src code.

Observed Behavior
When .web.tsx is listed after .tsx in resolveExtensions, esbuild still resolves to the .tsx file for dependencies in node_modules, rather than the .web.tsx variant.

Reproduction
Here is a minimal script demonstrating the behavior (see commented sections for the workaround). It uses expo-image from node_modules to illustrate the resolution bug. The github example has been narrowed down to exclude vite and uses esbuild only. https://github.com/Bram-dc/vite-react-native-web

You can switch around the commented resolveExtensions and also try the hotfix (lines 65-69)

@Bram-dc Bram-dc changed the title resolveExtensions not honoring .web.tsx when listed after .tsx, only for node_modules dependencies resolveExtensions not honoring .web.tsx when listed after .tsx for node_modules dependencies Jan 27, 2025
@Bram-dc
Copy link
Author

Bram-dc commented Jan 27, 2025

What is also important to notice that it resolved Test.web.tsx correctly all the time.

@evanw
Copy link
Owner

evanw commented Feb 6, 2025

Some background: The behavior of TypeScript files in node_modules was changed in v0.18.0 to behave differently than files outside node_modules after some feedback from the TypeScript team, among other reasons. The problem is that people sometimes accidentally publish the TypeScript source code alongside the JavaScript generated by tsc, the TypeScript compiler. This can happen if *.ts is not added to .npmignore before publishing to npm. If esbuild preferred .ts over .js in node_modules, then esbuild would potentially be introducing bugs by preferring TypeScript code to JavaScript code as the run-time behavior of TypeScript code depends on values from tsconfig.json, which may not even have been included in the published package. See #3019 for discussion and more details.

That said, this should be working as this package contains src/ExpoImage.tsx and src/ExpoImage.web.tsx but not src/ExpoImage.jsx or src/ExpoImage.web.jsx. The problem is due to an esbuild bug regarding how TypeScript extensions are sorted after JavaScript extensions. Specifically esbuild is checking to see what loader each extension maps to using an equality check instead of a suffix check, so .web.tsx isn't treated as TypeScript by the sort comparison because there is no loader specified for it (only for .tsx). A temporary workaround for this could be to use --loader:.web.tsx=tsx, although you could also reorder things manually as you discovered in your reproduction.

I'll fix the sorting comparison in the next release.

Note to myself: I briefly investigated whether this behavior should be reconsidered given that node has started supporting running TypeScript files directly. However, it looks like they are not planning to support this for files inside of node_modules at this time, so esbuild should probably keep this behavior for now.

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

No branches or pull requests

2 participants