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

feat: Initial pnpm support #1273

Merged
merged 21 commits into from
Nov 3, 2022
Merged

Conversation

chawyehsu
Copy link
Contributor

@chawyehsu chawyehsu commented Jul 30, 2022

This PR is going to implement the first-class support for the pnpm package manager.

Thanks to @mikrostew for the well-written volta-cli/rfcs#46, I've been able to implement this feature initially. Most of the critical functionalities have been implemented, except for the global package management. Due to a lack of further details on how to intercept pnpm to relocate its global package installs to fit Volta's current layout.

Implemented

  • pnpm shim
  • pnpm fetch / install / pin
  • pnpm hooks
  • per project pnpm manipulation
  • volta run with --pnpm and --no-pnpm

Not Implemented

  • global package manipulation/management via pnpm

In fact the argument parser for_pnpm() has been introduced to try to intercept pnpm args, but I found that there is no proper way to make pnpm's global installs whose original location is <path to pnpm home>/global/5/node_modules fit Volta's current global package image layout <path to volta home>/tools/image/packages. Hence I intercepted all --global pnpm commands and marked them as unimplemented.

Trackers

RFC: volta-cli/rfcs#46
Tracking issue: #737

This is currently a draft PR, please leave your review or comment if you have any ideas to improve the PR to push forward.

Demo

❯ .\target\debug\volta.exe list
⚡️ Currently active tools:

    Node: v16.16.0 (default)
    npm: v8.15.1 (default)
    pnpm: v7.7.1 (default)
    Yarn: v1.22.19 (default)
    Tool binaries available:
        cleancss (default)
        yarn-deduplicate (default)

See options for more detailed reports by running `volta list --help`.
DESKTOP in volta on  feature/pnpm [?] is 📦 v1.0.8 via 🦀 v1.62.0
❯ .\target\debug\pnpm.exe -h
Version 7.7.1
Usage: pnpm [command] [flags]
       pnpm [ -h | --help | -v | --version ]

Manage your dependencies:
      add                  Installs a package and any packages that it depends on. By default, any new package is installed as a prod dependency
      import               Generates a pnpm-lock.yaml from an npm package-lock.json (or npm-shrinkwrap.json) file
   i, install              Install all dependencies for a project
  it, install-test         Runs a pnpm install followed immediately by a pnpm test
  ln, link                 Connect the local project to another one
      prune                Removes extraneous packages
  rb, rebuild              Rebuild a package
  rm, remove               Removes packages from node_modules and from the project's package.json
      unlink               Unlinks a package. Like yarn unlink but pnpm re-installs the dependency after removing the external link
  up, update               Updates packages to their latest version based on the specified range

Review your dependencies:
      audit                Checks for known security issues with the installed packages
  ls, list                 Print all the versions of packages that are installed, as well as their dependencies, in a tree-structure
      outdated             Check for outdated packages

Run your scripts:
      exec                 Executes a shell command in scope of a project
      run                  Runs a defined package script
      start                Runs an arbitrary command specified in the package's "start" property of its "scripts" object
   t, test                 Runs a package's "test" script, if one was provided

Other:
      pack
      publish              Publishes a package to the registry
      root

Manage your store:
      store add            Adds new packages to the pnpm store directly. Does not modify any projects or files outside the store
      store prune          Removes unreferenced (extraneous, orphan) packages from the store
      store status         Checks for modified packages in the store

Options:
  -r, --recursive          Run the command for each project in the workspace.
DESKTOP in volta on  feature/pnpm [!] is 📦 v1.1.0-alpha.1 via 🦀 v1.62.0
❯ .\target\debug\pnpm.exe dlx create-vite vite-project --template vanilla
.../../../.pnpm-store/v3/tmp/dlx-31720   |   +6 +
Packages are hard linked from the content-addressable store to the virtual store.
  Content-addressable store is at: D:\.pnpm-store\v3
  Virtual store is at:             ../../../../../.pnpm-store/v3/tmp/dlx-31720/node_modules/.pnpm
.../../../.pnpm-store/v3/tmp/dlx-31720   | Progress: resolved 6, reused 6, downloaded 0, added 6, done

Scaffolding project in D:\workspace\repos\chawyehsu\volta\vite-project...

Done. Now run:

  cd vite-project
  pnpm install
  pnpm run dev

DESKTOP in volta on  feature/pnpm [!?] is 📦 v1.1.0-alpha.1 via 🦀 v1.62.0 took 5s
❯ cd vite-project
DESKTOP in volta\vite-project on  feature/pnpm [!?] via ⬢ v16.16.0
❯ ..\target\debug\pnpm.exe i
Packages: +14
++++++++++++++
Packages are copied from the content-addressable store to the virtual store.
  Content-addressable store is at: D:\.pnpm-store\v3
  Virtual store is at:             node_modules/.pnpm
node_modules/.pnpm/[email protected]/node_modules/esbuild: Running postinstall script, done in 318ms
Progress: resolved 34, reused 0, downloaded 14, added 14, done

devDependencies:
+ vite 3.0.4
DESKTOP in volta\vite-project on  feature/pnpm [!?] via ⬢ v16.16.0
❯ ..\target\debug\volta.exe pin node pnpm
success: pinned [email protected] (with [email protected]) in package.json
success: pinned [email protected] in package.json
DESKTOP in volta\vite-project on  feature/pnpm [!?] via ⬢ v16.16.0 took 3s
❯ cat .\package.json
{
  "name": "vite-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^3.0.0"
  },
  "volta": {
    "node": "16.16.0",
    "pnpm": "7.7.1"
  }
}
DESKTOP in volta\vite-project on  feature/pnpm [!?] via ⬢ v16.16.0
❯ ..\target\debug\pnpm.exe --version
7.7.1
DESKTOP in volta\vite-project on  feature/pnpm [!?] via ⬢ v16.16.0
❯

Signed-off-by: Chawye Hsu <[email protected]>
@chawyehsu chawyehsu mentioned this pull request Jul 30, 2022
@hustcer
Copy link

hustcer commented Aug 14, 2022

Thanks for the PR

@hustcer
Copy link

hustcer commented Aug 16, 2022

Any update on this?

@chriskrycho
Copy link
Contributor

@chawyehsu this is excellent to see! 👏🏼 I approved CI to run. @charlespierce or @mikrostew if either of you has time to look and see what needs to be done for the global intercept, that would be fantastic. 🤩

Signed-off-by: Chawye Hsu <[email protected]>
@chawyehsu chawyehsu marked this pull request as ready for review August 16, 2022 16:57
@chawyehsu
Copy link
Contributor Author

@chriskrycho Thanks! I fixed tests on Unix according to the CI result.

@chriskrycho
Copy link
Contributor

The GH setting is such that I’ll have to reapprove every time, so I'll try to keep an eye on this to keep rerunning it – sorry about the hassle on that front!

@chawyehsu
Copy link
Contributor Author

chawyehsu commented Aug 17, 2022

I didn't notice there is a --features mock-network flag to turn on all tests including sandboxed smoke tests. I was only using cargo test --all until I saw the CI arguments.

I'll try to fix them today when I have a couple of hours to figure out.

Copy link
Contributor

@charlespierce charlespierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! Apologies for taking a bit longer to get to it than I expected, it's been a very busy couple of weeks at work 😅

I haven't finished reading through the meatiest parts (resolving, parsing, etc.), but left a few minor style comments on the surrounding infrastructure. Will follow-up later in the week with a review on the core parts, as well as some potential thoughts on the FIXME comments.

Super excited for this to land!

crates/volta-core/src/hook/serial.rs Outdated Show resolved Hide resolved
crates/volta-core/src/tool/package/manager.rs Outdated Show resolved Hide resolved
crates/volta-core/src/tool/package/metadata.rs Outdated Show resolved Hide resolved
crates/volta-layout/src/v3.rs Show resolved Hide resolved
crates/volta-migrate/src/v3/config.rs Outdated Show resolved Hide resolved
crates/volta-core/src/project/mod.rs Outdated Show resolved Hide resolved
src/command/run.rs Outdated Show resolved Hide resolved
@ScreamZ
Copy link

ScreamZ commented Aug 23, 2022

Any news on this boyz ? Need it

@chawyehsu
Copy link
Contributor Author

@ScreamZ Sorry no ETA, let's wait for the team back from their main work.

Copy link
Contributor

@charlespierce charlespierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again! Took a look through the meat of the code and it's all reasonable. Also points to a lot of things it would be good for us to clean up re: Adding package support (lots of boilerplate).

Left a few (mostly minor) suggestions. For the ones in parser.rs, I think it's totally reasonable to resolve them with FIXME comments, as I see the overall global interception isn't totally wired up yet anyway.

.vscode/settings.json Outdated Show resolved Hide resolved
crates/volta-core/src/platform/tests.rs Show resolved Hide resolved
crates/volta-core/src/run/parser.rs Outdated Show resolved Hide resolved
crates/volta-core/src/run/parser.rs Outdated Show resolved Hide resolved
@@ -87,6 +88,10 @@ impl PackageManager {
if let PackageManager::Yarn = self {
command.env("npm_config_global_folder", self.source_root(package_root));
}

// FIXME: Find out if there is a good way to redirect pnpm global installs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for leaving this comment! Totally reasonable to leave this as a follow-up, I know we've done some research and it's possible, so we should be able to add that on later.

Copy link
Contributor Author

@chawyehsu chawyehsu Sep 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my research, I think there will be much work to implement global commands manipulation for pnpm. pnpm relies on absolute path symlinks heavily (binaries generation, symlinked node_modules structure), this makes it very difficult for volta to install and update global packages via pnpm without a layout change. I don't know if there is a proper way to update those generated symlinks after moving packages from the temp directory to the image directory to ensure they won't be broken. Related annotation in e830d3d#diff-80dfff59af9a37069dea094c900c30eafd02dd51c2dea21d150a017d1a86c9d3R90.

src/cli.rs Outdated Show resolved Hide resolved
@@ -622,6 +674,7 @@ impl SandboxBuilder {
ok_or_panic! { fs::create_dir_all(node_cache_dir()) };
ok_or_panic! { fs::create_dir_all(node_inventory_dir()) };
ok_or_panic! { fs::create_dir_all(package_inventory_dir()) };
ok_or_panic! { fs::create_dir_all(pnpm_inventory_dir()) };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random question: Since we aren't doing a migration (and all users will be without this directory to start out once this is released), do these tests work if this is left out? Ideally we would leave this directory uncreated and allow it to be automatically created as needed. Totally reasonable if the tests don't support that at the moment, however.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just for the sandbox tests. The inventory directory is ensured to exist by the fetch function in production, https://github.com/volta-cli/volta/pull/1273/files#diff-cecf323599e6ac86e26655f65f1935e8d8435f00e05003ad7e228a9dc29d056cR92-R94

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is not needed - I removed this line and the tests still pass (for me locally on OSX).

crates/volta-core/src/tool/pnpm/resolve.rs Outdated Show resolved Hide resolved
crates/volta-core/src/tool/pnpm/fetch.rs Outdated Show resolved Hide resolved
crates/volta-layout/src/v3.rs Show resolved Hide resolved
Copy link
Contributor

@mikrostew mikrostew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also need to add the pnpm and pnpx shims to the get_shim_list_deduped() fn in crates/volta-core/src/shim.rs, for Unix systems to get the new shims (looks like Windows is fine though).

Otherwise I agree with @charlespierce, it seems reasonable not to block on pnpm globals and leave that unimplemented for now.

Sorry there is so much boilerplate needed to onboard a new package manager.

crates/volta-core/src/run/parser.rs Outdated Show resolved Hide resolved
crates/volta-core/src/run/parser.rs Outdated Show resolved Hide resolved
@chawyehsu
Copy link
Contributor Author

chawyehsu commented Oct 5, 2022

pnpx has been deprecated, hence I didn't implement the shimming for it.

it seems reasonable not to block on pnpm globals and leave that unimplemented for now.

It's easy to unblock global commands by simply commenting out the global commands guard in crates/volta-core/src/run/pnpm.rs, this will leave pnpm global packages out of volta's control, however. Blocking global commands may bring inconvenience while allowing the unimplemented to be executed outside volta's layout may get package migration issues in the future. In fact, for me, I may choose to not block global commands but this causes the UX issue that volta can not list global packages installed by pnpm.

@avaly
Copy link

avaly commented Nov 2, 2022

Could we get this PR merged as-is with a disclaimer that pnpm support is experimental for now, until the global commands can be properly implemented?

We'd really like to use this in our workflows for local development and Docker builds, so the missing global commands support is not really impacting us.

@runspired
Copy link

I second that: pnpm ships often enough that running volta install pnpm@<version-project-uses> many times a day has become annoying :D

@chawyehsu
Copy link
Contributor Author

Hi folks, thanks for all your interest, response, and emoji reactions to this. Undoubtedly, I hope we could make this happen as possible, Volta and pnpm are both great tools for me to be involved in the ecosystem, and I'm happy with them.

Therefore I made the PR to try to improve these everyday tooling things a little bit more productive and efficient, with a micro goal of hunting some bounties because of my state of out-of-work. The waiting time was a little longer than I expected, expected two months at most for rolling this out. But it's definitely up to the Volta team, I'm not one of its members hence I ain't able to push it to go further. The team is so busy I guess, let's wait a bit more time and we will see.

If you have a strong demand for it right now, you may build a nightly version based on my branch. It's also the base of the local build that I'm currently using.

Copy link
Contributor

@charlespierce charlespierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exciting! A couple of small changes to make sure we're not impacting the performance of the existing flows with unused code or extra data copying.

To the release strategy, I agree with the plan of merging this and then releasing experimental support. Then we can take another look at the global command interception and look to get that working to remove the experimental label.

crates/volta-core/src/tool/package/manager.rs Outdated Show resolved Hide resolved
crates/volta-core/src/run/pnpm.rs Outdated Show resolved Hide resolved
crates/volta-core/src/tool/package/manager.rs Outdated Show resolved Hide resolved
@chawyehsu
Copy link
Contributor Author

Changes are applied.

A side note here: When a user updates to a version of Volta that has first-class pnpm support, if they have installed pnpm (as a package) before they might need to uninstall it manually by npm uninstall -g pnpm in order to make the new pnpm shim be available.

Copy link
Contributor

@charlespierce charlespierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great callout re: existing pnpm installed as a package! We'll probably want to think a bit about how we want to message that before publishing the release as the latest version. I can make the build however, which will allow people to try it out.

@charlespierce
Copy link
Contributor

Thank you @chawyehsu!

@charlespierce charlespierce merged commit 7827ade into volta-cli:main Nov 3, 2022
@chawyehsu
Copy link
Contributor Author

chawyehsu commented Nov 4, 2022

Glad that! CI artifacts are now available to try https://github.com/volta-cli/volta/actions/runs/3383641697

@ScreamZ
Copy link

ScreamZ commented Nov 7, 2022

Just tried, seems to work, now we need a way to auto-update volta ahah v1.1.0 released

@smblee
Copy link

smblee commented Nov 9, 2022

Also tested the artifact above and it works 🥳 What does the official release cycle look like for this binary to be available?

@PindaPixel
Copy link

Does this take pnpm/node version compatibility into account?

@chawyehsu
Copy link
Contributor Author

Does this take pnpm/node version compatibility into account?

@PindaPixel Didn't have any extra implementation for the node version compatibility, the compatibility check will be passed to pnpm.

@smblee
Copy link

smblee commented Nov 14, 2022

Hey @charlespierce just wanted to check on when this PR will be officially released

@michaelhays
Copy link

@smblee See this comment; there's no ETA as of now.

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

Successfully merging this pull request may close these issues.