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

Make depedenciesMeta inject by default for workspace packages? #4965

Open
1 task
deokseong-kim-toss opened this issue Jul 1, 2022 · 20 comments
Open
1 task

Comments

@deokseong-kim-toss
Copy link

deokseong-kim-toss commented Jul 1, 2022

Describe the user story

We maintain many packages with monorepo, but we often make mistake "missing peers"

  • packages/a
    • deps: workspace:b
  • packages/b
    • peerDeps: something

expect: mssing peers 'something' in 'b'
result: nothing

dependenciesMeta.*.inject option helps, but it is quite annoying write inject when every deps. It also cause another human error.

Describe the solution you'd like

npm options like "use-inject-workspace = true"

Describe the drawbacks of your solution

I don't fully understand why inject should be in package.json instead a pnpm option, use-inject-workspace makes inject not explicit.

Describe alternatives you've considered

use-inject-workspace = dependencies
use-inject-workspace = dependencies,devDependencies

or

add inject when add workspace as dependency?

Question:
Sorry for question. I wonder why pnpm don't use inject for all dependencies. Does it have performance drawback?

@zkochan
Copy link
Member

zkochan commented Jul 2, 2022

I wonder why pnpm don't use inject for all dependencies. Does it have performance drawback?

The main reason is that when you use inject and you rebuild the injected dependency, you somehow need to resync that dependency.

@blowsie
Copy link

blowsie commented Jul 28, 2022

I would agree with this decision, if a workspace package specifies a peerDependency, it is simply ignored when you install it from another workspace package, without any error or warning.

@NullVoxPopuli
Copy link
Contributor

can the resync somehow happen automatically?

I'm using dependenciesMeta.injected right now to help out with a deep peer dependency, and my library that forwards that peer needs to be built, and those built assets aren't present in the injected version until I run install again.

Since this will be a common scenario for me (in a monorepo), I'd like this to somehow be more ergonomic

@zkochan
Copy link
Member

zkochan commented Oct 9, 2022

Currently the packages will be automatically synced if they are built via a prepare script. But they are not resynced when someone rebuilds them. Probably this should be fixed.

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Oct 22, 2022

anyone have ideas for how to re-sync dependencies when using turborepo? I could prefix all my scripts with pnpm install, but that'd only work once, because without changes detected, turbo would skip the prefixed pnpm install

I opened an issue here on turbo's repo: vercel/turbo#2306
just for cross-referencing

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Jan 26, 2023

@zkochan I had an idea for how we can reasonably do this / implement this feature.
It's not 100% fool proof, so it may need to be opt-in via .npmrc option, but the gist is:

  • analyze package.json#files (or package.json#exports)

  • only symlink those files entries (+ package.json of course)
    -> this way, when the library updates its dist (or whatever folder), because the folders are symlinked, updates are automatic, and we don't need to re-run pnpm install

    thoughts?

@zkochan
Copy link
Member

zkochan commented Feb 9, 2023

only symlink those files entries (+ package.json of course)

This will not work with symlinks.

This will only work with hard links (that we use now) or copies. Symlinks are ignored when node.js resolves dependencies. So even though the symlink to project-b will be inside project-a's node_modules, the dependencies of project-b will be resolved from the node_modules of project-b because that is where the symlink points.

@NullVoxPopuli
Copy link
Contributor

would the same idea work with hard links? instead of file-based hard-links, hard-link folders, based on package.json#files / dirname(package.json#exports)?

Do hardlinks still work if say, the whole dist folder is deleted, and re-generated by rollup?

@zkochan
Copy link
Member

zkochan commented Feb 9, 2023

No, hard links are only possible upon files.

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Feb 10, 2023

Has node rejected the idea of resolving symlinks?
Maybe we can change node.

Edit: found this: symlink alternative and the rationale for node not resolving symlinks

But wait, this is all unrelated, we need the symlink in the repo-root .pnpm directory, not node_modules.
How does the .pnpm directory get used it resolution? Is that up to pnpm to configure? If so, i don't think the node issue 3402 would apply?

@zkochan
Copy link
Member

zkochan commented Feb 10, 2023

Node.js should resolve symlinks to their real locations. Otherwise, node.js would not work with pnpm.

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Feb 10, 2023

How do you mean?, you said:

Symlinks are ignored when node.js resolves dependencies.

@zkochan
Copy link
Member

zkochan commented Feb 16, 2023

For example, let's consider these two projects:

a
  index.js
  node_modules
    react (v17)

b
  index.js
  node_modules
    a --> ../../a
    react (v16)

If b/index.js will require a, a will resolve react from a/node_modules/react, not from b/node_modules/react. Because the real location of a is not inside b/node_modules/a but inside a. Node.js is looking for dependencies in the real location.

@NullVoxPopuli
Copy link
Contributor

does this behavior apply to all files or just the package root?
maybe if b's a is a real folder, with hard-link to a's package.json, and then symlinking a dist folder for the other contents?

I think I need to test this out in a monorepo. I'll report back with that

@NullVoxPopuli
Copy link
Contributor

I got distracted, but in the mean time, @simonihmig made a util that would make re-syncing easier -- I commented about maybe adding it to pnpm here: #6088 (comment)

@NullVoxPopuli
Copy link
Contributor

Added a README to this project: https://github.com/NullVoxPopuli/pnpm-sync-dependencies-meta-injected

it at least allows folks to regain some productivity 😅
and has a watch mode

@NullVoxPopuli
Copy link
Contributor

@zkochan would it make sense to internalize this library as a daemon, or... how should we proceed?

@zkochan
Copy link
Member

zkochan commented Feb 11, 2024

What do you mean by initializing it as a daemon? You mean adding it to pnpm as a new command?

Unfortunately, I cannot really dogfood this as I only used injected deps with Bit, which automatically writes to the "injected" dists when compiling. For now, if your package works, you can transfer it to the pnpm org and we can reference it from the docs.

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Feb 11, 2024

What do you mean by initializing it as a daemon?

without build time integration, something needs to be running to watch output directories (package.json#files, for example), and if those change, re-sync them to the injected folders.

you can transfer it to the pnpm org and we can reference it from the docs.

sounds good, I'll make a demo tomorrow wednesday of with and without the tool to show how it works and add that to the readme before transfer

@NullVoxPopuli
Copy link
Contributor

@zkochan -- how is transferring supposed to work? should I transfer it to your user account first?

image

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

No branches or pull requests

4 participants