When you run npm ls:
[email protected]
+-- [email protected]
`-- [email protected] -> ../common-components
`-- [email protected]
[email protected] is installed in the root of the example app — correct, satisfies the peer dependency.
The extra [email protected] under common-components is not actually installed again in a separate copy; it’s just how npm shows the peer dependency link (even though it's using the root version).
In other words: npm ls reports it under both packages, but in reality there’s only one copy used.
my-api is being used at runtime1. Use require.resolve(CommonJS) or import.meta.url(ESM)
Since your project is ESM ("type": "module"), you can do:
// In App.tsx or any example file
import * as MyApi from 'my-api';
console.log('my-api path:', import.meta.resolve ? await import.meta.resolve('my-api') : MyApi);
This will show you the absolute path where my-api is being imported from.
If both common-components and common-components-example resolve to the same path, there’s only one copy in use.
2. Compare references at runtime
A more React/JS way:
import * as MyApi from 'my-api';
import { something } from '../common-components/src/SomeComponent';
console.log('Same my-api instance?', MyApi === something.__myApiInstance);
If your library common-components exposes a reference to my-api internally (or you temporarily attach it to window), you can compare the objects.
If they are strictly equal (===), then both the library and your app are using the same copy.
3. Quick hack with node_modules paths
Run this in your example app:
node -p "require.resolve('my-api')"
node -p "require.resolve('../common-components/node_modules/my-api')"
common-components is not installing a separate copy in its own node_modules.