How do you stop duplicate dependencies from sneaking into a bundle?

Hey folks, I’m trying to lock down our frontend bundle because we keep shipping two copies of the same library after a minor dependency bump, and it’s a real risk for subtle state bugs (two singletons) plus a bigger payload.

// Vite/Rollup build snippet
export default {
  resolve: {
    dedupe: ["react", "zustand"],
    alias: {
      "zustand": require.resolve("zustand"),
    },
  },
};

What’s the most reliable way you’ve found to enforce a single instance across transitive deps in real projects without breaking installs or spending all day chasing lockfile edge cases?

1 Like

dedupe/alias is a nice seatbelt, but the thing that actually keeps “two singletons” from showing up after a random bump is making the package manager pick one version on purpose.

In practice I’ve had the least drama with (1) an override/resolution in the package manager, and (2) a CI check that fails the build when duplicates appear. pnpm overrides / Yarn resolutions / npm overrides, then a dumb little script that greps pnpm list (or yarn why) output for multiple versions of the same package and errors out. I’m not 100% sure how clean this stays with workspaces + linked local packages, but it’s been way less whack-a-mole than trying to solve it purely in Vite config.

Your Vite config is still worth keeping though — it’s like taping down the rug so nobody trips, but the override is the part that stops someone from bringing a second rug into the house in the first place.

1 Like

Your Vite dedupe/alias helps, but the more reliable way to stop this happening is preventing the second copy from ever landing in node_modules in the first place. That means using your package manager’s override/resolution mechanism so transitive deps can’t quietly pull a second semver line, then making CI fail the moment the lockfile drifts. In practice, I’ve had the least drama with overrides (npm/pnpm) or resolutions (Yarn) for the handful of packages that are “singleton-y” (React, state libs, anything with global registries), plus a CI check that asserts there’s only one version installed. Otherwise, you only notice after the bundle ships and you get the “why are there two stores? ” bug report. Example snippets:

// package.json (npm >= 8.3)
{ "overrides": { "zustand": "4.5.2", "react": "18.3.1" } }

// package.json (pnpm)
{ "pnpm": { "overrides": { "zustand": "4.5.2", "react": "18.3.1" } } }

// package.json (Yarn classic/berry)
{ "resolutions": { "zustand": "4.5.2", "react": "18.3.1" } }

And then in CI, something blunt like:

pnpm why zustand
pnpm why react

Or:

npm ls zustand
npm ls react

…and treat “multiple versions present” as a hard failure. That’s the bit that actually enforces it over time; dedupe/alias is more like a seatbelt after the crash has already started.

1 Like