-
Notifications
You must be signed in to change notification settings - Fork 0
add effect to the mix #2
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
base: main
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This is further amplified by how it only aliases root entrypoints of packages whilst not respecting module I opened a PR to remove the I'm curious to hear from the next.js maintainers what the intended behavior here is exactly so this can be fixed sustainably. |
Repro for https://x.com/thefubhy/status/1936485841871773793
Background
A recent change in t3.chat introduced Effect (v3.15.5) into the codebase. We're also using uploadthing, which internally uses Effect 3.14.21 (https://github.com/pingdotgg/uploadthing/blob/091b97bcf8bb604ff2f39c19d6cb310c378eaf38/packages/uploadthing/package.json#L161). Uploadthing does not expose effectful APIs to its consumers, hence it's a dependency and not a peer-dependency (a decision we'll probably revise in the next major version). This leads to a potential of multiple versions of effect being included for a single project. While this has some downsides, this is common for many packages (I bet you can find many versions of the same package if you scroll through your lockfile), and should not cause any issues as libraries like uploadthing should be able to use Effect internally without users knowing or caring what version the library might be using.
When it comes to Effect however, they enforce strict version compliance when executing Effects. An effect created by one version of Effect, must be executed by the same version of Effect:
Note
Effect will in the future log at warning level instead of crashing the program Effect-TS/effect#5064. This reproducer also has this patch applied to not crash the app prematurely
To prevent this, we added
pnpm.overrides
to force a single version of Effect in the t3chat repo:Despite this, module caching led the "old version" included by Uploadthing (3.14.21) to be kept around and included in the deployed output causing the app to crash during chat generations.
I was willing to call it a day here, and conclude the issue being cache related. I had several proof of this being the case for t3chat, both locally by running
rm -rf node_modules .next
after changing branches as well as remotely when redeploying an erroneous deployment without build cache. But this is not the end of it, and the Effect folks went ahead and dug deeper.The issue at hand
This repo tries to reproduce the issue. While I was not able to reproduce the bad cache behaviors causing the issue with
pnpm.overrides
enabled, I was able to reproduce the core cause of the issue. If we look at the error message from the original tweet by Theo:This indicates that some bits of UploadThing code executed Effects passed from the application layer. This however, is not the case. No piece of Effect code from the app layer is ever touching the uploadthing layer, so how are Effect's versioned 3.16.5 being executed by Effect 3.14.21?
The reproducer
tl;dr - run
pnpm preview
It appears the version of Effect being picked up is non-deterministic. If we look closer to the Next.js compiler (thanks @fubhy for helping out debugging this bit) we can see that they are doing some form of barrel import optimizations by creating aliases for certain modules ( https://github.com/vercel/next.js/blob/canary/packages/next/src/build/create-compiler-aliases.ts#L163-L165), in particular Effect (https://github.com/vercel/next.js/blob/1f47f8f4809dd43b3223e2fe9d13f7aa1cd47caf/packages/next/src/server/config.ts#L1034-L1053). An example of such generated alias may look like this:
pnpm puts transitive dependencies inside a nested
node_modules/.pnpm
folder:But what next isn't taking into account here is that we have 2 versions. As soon as the compiler first generates this alias, all future references will use this aliased path no matter where the source is. So the uploadthing library will sometimes get v3.14.5 and sometimes v3.16.8. With normal module resolution algorithms, the uploadthing code should always resolve the
3.14
entrypoints, and the application code should always resolve the3.16
entrypoints.#3 applies a patch to remove this alias generation and voila... the mismatched version log goes away!