Skip to content

Conversation

Julusian
Copy link
Contributor

This resolves an issue I was seeing when using a yarn 4 monorepo, where is appeared that npm list disagreed with the layout on disk and produced a tree with deduplications that resulted in a bunch of packages to go missing.

For my project, the output of the npm list command was: https://gist.github.com/Julusian/b4f5fe20db4f211753fa0ef8292901c8.
Looking at this output, the bits worth noting are the locations of balanced-match and brace-expansion. There are 2 of each of them, one where brace-expansion has a _dependencies containing balanced-match but no dependencies, and the other where it has balanced-match in both.

The one where it is in both is apparently a child of cacache being a dependency of the workspace root, but according to yarn and the yarn.lock that cacache dependency should be a few layers deep as a child of something. It is also worth noting here that npm complains "extraneous: [email protected] /home/julus/Projects/companion/companion/node_modules/cacache", so it looks to me that npm got rather confused about where this belongs and so dumped it at the root level.

Because it was at the root level, collectAllDependencies would never see the proper brace-expansion, only the one with deduplicated dependencies, resulting in it not knowing that balanced-match should be packaged and it would be missing at runtime.

I am not sure if this is the best fix, but it resolves my issue. I suspect that this approach is ok as this is simply building the tree of what dependencies there are installed within the workspace, but it isnt doing anything with them at this stage; the later step of actually extracting the production dependency graph is still using the package/project root.


While debugging this, my script for testing was:

import { YarnNodeModulesCollector } from './out/node-module-collector/yarnNodeModulesCollector.js'
import { TmpDir } from 'builder-util'

const tmp = new TmpDir()
try {
	const collector = new YarnNodeModulesCollector('/home/julus/Projects/companion/companion/launcher', tmp)
	const res = await collector.getNodeModules()

	console.log(
		'res',
		res.length,
		res.find((r) => r.name.startsWith('brace-exp')),
		res.find((r) => r.name === 'balanced-match')
	)
} finally {
	tmp.cleanupSync()
}

If you want to try it yourself, it should be enough to clone and run yarn install for the commit https://github.com/bitfocus/companion/tree/91d92c5d6d324e86ce032bec8a92212a042267b6, then run that script against it with the corrected path, and make sure that the console.log logs that it found the packages being verified.

My testing was with electron-builder/app-builder-lib 26.0.19, node 22.18.0, yarn 4.9.2 and npm 10.9.3

Copy link

changeset-bot bot commented Aug 26, 2025

🦋 Changeset detected

Latest commit: 9ea3f47

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
app-builder-lib Patch
dmg-builder Patch
electron-builder-squirrel-windows Patch
electron-builder Patch
electron-forge-maker-appimage Patch
electron-forge-maker-nsis-web Patch
electron-forge-maker-nsis Patch
electron-forge-maker-snap Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@beyondkmp
Copy link
Collaborator

very good catch.

@beyondkmp
Copy link
Collaborator

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants