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

Monorepo project dedupes dependencies even when not specified #9948

Open
7 tasks done
filipw01 opened this issue Sep 1, 2022 · 16 comments
Open
7 tasks done

Monorepo project dedupes dependencies even when not specified #9948

filipw01 opened this issue Sep 1, 2022 · 16 comments
Labels
feat: deps optimizer Esbuild Dependencies Optimization p4-important Violate documented behavior or significantly improves performance (priority)

Comments

@filipw01
Copy link
Contributor

filipw01 commented Sep 1, 2022

Describe the bug

I am using a monorepo package and an app consuming it. They both use different versions of a dependency

Vite uses the version specified in app, even when importing it from the internal package

I expect Vite to use version of a package that is specified in internal package's package.json for the package and the version in app's package.json for app code (not the package code)

For me personally it happens with yarn 3, but I reproduced it on stackblitz using pnpm
To represent the issue I used:
[email protected] for package that is using default export
[email protected] for app that is using named export

Reproduction

https://stackblitz.com/edit/github-zdg7ym-1hbqbp?file=package%2Findex.jsx

System Info

Note, this is my local system info where it failed with yarn, I wasn't able to run it in stackblitz

  System:
    OS: macOS 13.0
    CPU: (10) x64 Apple M1 Max
    Memory: 469.47 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 14.18.2 - ~/Library/Caches/fnm_multishells/926_1661596049762/bin/node
    Yarn: 3.2.3 - ~/Library/Caches/fnm_multishells/926_1661596049762/bin/yarn
    npm: 8.5.4 - ~/Library/Caches/fnm_multishells/926_1661596049762/bin/npm
  Browsers:
    Brave Browser: 104.1.42.86
    Chrome: 104.0.5112.101
    Firefox: 103.0.2
    Safari: 16.0
  npmPackages:
    @vitejs/plugin-react: 3.1.0 => 3.1.0
    vite: 4.1.2 => 4.1.2

Used Package Manager

yarn

Logs

Click to expand! Error in browser ```shell Uncaught SyntaxError: import not found: default ```

Validations

@filipw01
Copy link
Contributor Author

filipw01 commented Sep 1, 2022

Most likely related to an issue that didn't have reproduction #8440

@FezVrasta
Copy link

This seems related to the package manager more than Vite?

@filipw01
Copy link
Contributor Author

filipw01 commented Sep 1, 2022

I don’t think so. I already reproduced it with 2 different package managers (pnpm and yarn 3), the first two I tried. This issue might also be related to #3254

@filipw01
Copy link
Contributor Author

I added rollup as a counterexample. It handles two different package versions just fine. Can someone confirm this is a bug? I can try to work on that

@bluwy
Copy link
Member

bluwy commented Mar 30, 2023

This might be fixed by #11410, which I'm working on rebasing it.

@bluwy bluwy added p3-significant High priority enhancement (priority) feat: deps optimizer Esbuild Dependencies Optimization and removed pending triage labels Mar 30, 2023
@gdosherjc
Copy link

Just wanted to pop in and confirm I'm seeing the same issue. Seems like bluwy is working on it though :)

Here is a summary of my pnpm workspace's packages dependencies. If I need to make a reproduction repo I can

apps/web-app:
    [email protected]
    subPackageA@workspace
    subPackageB@workspace
// dev dependencies
    "@vitejs/plugin-legacy": "^4.0.0",
    "@vitejs/plugin-vue2": "^1.1.2",
    "vite": "4.3.0-beta.4",

packages/subPackageA
-- [email protected]

packages/subPackageB
-- [email protected]

When running vite:

Expectation: In subPackageB, I'd expect it to be using [email protected] as that is what is defined in that packages package.json

Actual: Whatever version of somePackage that is installed in the application is what will be used for all packages. So when the web-app is set to @1.x, both subPackageA and subPackageB use that (even though subPackageB depends on v0.x.

Note: This only happens in dev mode. When I run vite build and then vite preview, both packages resolve how I'd expect and are working.

@sjmarshy
Copy link

sjmarshy commented Jul 3, 2023

Hi, I'm currently running into this issue!

Is there a workaround or solution in the meantime that hasn't been mentioned here?

I'm not sure what the status of the fix is, but the linked MR has been closed and no new ones are linked so I can't easily follow up elsewhere

@bluwy
Copy link
Member

bluwy commented Jul 13, 2023

Sorry, I haven't finished it up since I last worked on that. The whole code path to deduplicate the packages turned out to be harder than expected if we want to preserve the performance. At the moment, I think this can be workaround (following gdosherjc's comment) with something like:

optimizeDeps: {
  include: [
    'subPackageA > somePackage'
    'subPackageB > somePackage'
  ]
}

So it keeps two reference. I have not tested this though.

@paul-sachs
Copy link

I think I'm also running into this same issue. In my case, I'm trying to migrate to @tanstack/react-query@5 from v4. I couldn't get the workarounds working at all, though it may be me not quite understanding how the ">" character is being interpreted here.

I've made a monorepo package called "@shared/query" which reexports the api from react-query. I've tried the following but nothing changed:

optimizeDeps: {
  exclude: ["@shared/query > @tanstack/react-query"]
}

Maybe I'm doing something wrong... 🤷

The workaround that did work was to rename the dependency itself, which you can do with pnpm with something like this in your package.json:

{
  "new-tanstack-react-query": "npm:@tanstack/[email protected]",
}

Then you just need to update references to new-tanstack-react-query within @shared/query which is pretty light touch.

@gdosherjc
Copy link

Checking back in on this as it seems to have fizzled out. Is there anything we could do to make progress on this? I could perhaps poke around at it but it sounds like @bluwy already has and hit some walls. I wonder if he/someone might have some extra context that would be valuable (or even just pointers on where to look, haven't dug into this codebase before).

I tried following the workaround steps from @bluwy but I can't quite get it to work. Adding that package to the include list does output a separate subPackageA___somePackage file in the node_modules/.vite/deps folder, but subPackageA is still using the regular one :(

I'm also not sure either of the proposed workarounds really scale. Having to know/remember to add these packages to the vite config would be tricky and annoying.

@markmckim
Copy link

markmckim commented May 30, 2024

I'm also hitting this issue - one possible additional fact which may help with diagnosis....

If I have:

libA
libB
libC

and they each import somePackage (different versions)

It seems to always be using the version from libC (providing a file from libC actually imports somePackage in a file somewhere).

It's almost as if the dependency optimiser is running through the libs alphabetically and using the package name as a unique key but ignoring the version number differences - and if libC is the last package alphabetically then its the one that overrides the previous optimised versions.

I've tried a few different scenarios and this theory seems to hold up for my tests so far.

Not a very scientific test but hopefully adds some additional context.

We are in a large monorepo with quite a few different libs so manually tracking duplicated dependencies and adding them to Vite config is not really feasible for us either.

@GeordiD
Copy link

GeordiD commented Jun 5, 2024

I pulled down the repo and started digging into the code, and I was able to at least reproduce this in the playground. Here's my branch with steps to reproduce / further explanation: GeordiD#1

I've been poking through the code but not really finding where exactly the optimization is happening. I can see the deps is empty here, but by L121 it's populated with only one copy of pluralize. I just lose the code path somewhere in the ESBuild context. Any pointers on where I should be looking would be very helpful 🙏

(Or if there is active work on it and I just need to be patient that's fine too. Just trying to scratch my own itch and help out / learn more if I could)

@GeordiD
Copy link

GeordiD commented Jun 6, 2024

Ok tracked down where we're losing the extra dependency: here

All the dependencies go through this with their package name as the id field (so pluralize). It then sets the depImports with that id as the key for the path to the dependency file. Since pluralize@7 and pluralize@8 both have the same id (pluralize), whichever gets through this loop second wins. This deps is passed through the rest of optimize deps and (i think) is what becomes the .vite/deps folder.

At this point, I'm not sure what to do. I think maybe there should be some check if the paths for the resolved value doesn't match what's already in there we should do something different, but 🤷 . My understanding (just from guessing really) is packages find things in this .vite/deps folder by package name, so I don't think we can just make a [email protected] and [email protected] as separate deps. I really don't know, and recognize the limit of my domain knowledge here.

@bluwy bluwy added p4-important Violate documented behavior or significantly improves performance (priority) and removed p3-significant High priority enhancement (priority) labels Jun 6, 2024
@markmckim
Copy link

@bluwy - Is this ticket on any roadmap / plan to be addressed any time soon?

We have recently moved approx 30 teams over to a single Nx / Vite monorepo and this one is becoming a major issue for us unfortunately. A large number of our teams are using different versions of the same packages and it's becoming increasingly difficult to mitigate these impacts on a daily basis.

Appreciate the time / effort you and others have already spent investigating this though!

@jeegurda
Copy link

jeegurda commented Sep 29, 2024

Hi, i recreated this issue with a minimal setup, using npm, standard folder structure and a very basic Vite setup: https://stackblitz.com/edit/vitejs-vite-aej4uh?file=src%2Fmain.ts
Hopefully this provides a clearer picture than the original example and few similar issues.

  1. The versions that are reported at dev build (npm run dev):
3.10.1
3.10.1

Note: sometimes the output would be:

4.17.21
4.17.21

but that's beside the point: it's the same package referenced twice

  1. Now shut the server down and run the prod build with a preview (npm run build && npm run preview). The versions would be as expected:
3.10.1
4.17.21

This is definitely a Vite issue, since having nested packages is a valid setup that is correctly handled by Node, Rollup (as reported before), Webpack etc. For a quick sanity check i also recreated this with webpack and everything is handled correctly in both dev and prod builds, you can also check it here if you wish.

The main problem with this behavior is that running prod and dev builds yields different results, which i believe makes Vite unusable in monorepo (or workspaces) setups. I tried tinkering with optimizeDeps options, but with no results.

@Jsignr
Copy link

Jsignr commented Oct 10, 2024

Hi, has anyone found a solution to this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: deps optimizer Esbuild Dependencies Optimization p4-important Violate documented behavior or significantly improves performance (priority)
Projects
None yet
Development

No branches or pull requests

10 participants