Skip to content

fix(create): honor system package manager versions - #2699

Open
SaKaNa-Y wants to merge 7 commits into
voidzero-dev:mainfrom
SaKaNa-Y:fix/create-system-package-manager-version
Open

SaKaNa-Y wants to merge 7 commits into
voidzero-dev:mainfrom
SaKaNa-Y:fix/create-system-package-manager-version

Conversation

@SaKaNa-Y

@SaKaNa-Y SaKaNa-Y commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Important

Please take a moment to read this. Thank you!

I should include a brief explanation of the problem in my own words in every PR. If that explanation is missing, please @mention me and do not merge this PR until I have added it. You may also leave this PR unaddressed (because this means I have not fulfilled my responsibilities as the author).

If my explanation is unclear or difficult to follow, please ask me to clarify or provide reproduction steps or supporting evidence.

I welcome suggestions and counterarguments, especially questions about anything I may have overlooked. (Your feedback helps me learn and improve. 🙏)

I hold myself to this standard for every PR, regardless of its size.

vp create always downloaded a managed package-manager release before scaffolding, even when that family was configured to use the system installation. The generated devEngines.packageManager.version could therefore disagree with the executable used for installation. With npm, this can fail with EBADDEVENGINES; the same incorrect pinning also affects pnpm, Yarn, and Bun.

Resolve the selected family through vp env current before scaffolding. When it selects a system executable, use that version and binary directory. Keep managed downloads and the missing-system fallback, locate the global resolver through the shared directory API, and preserve local-only creation when it is absent. Narrow scaffold metadata to the fields consumers actually need.

System Yarn Classic also needs a compatible template runner: Yarn 1 has no dlx command. Select npx --yes from the resolved Yarn version, matching the existing vp dlx fallback; Yarn 2+ continues to use yarn dlx. This runner choice does not change the selected package-manager family or version.

The Unix external-template fixture sets npm's script shell to /bin/sh. The snapshot runner exposes sh through a symlink, while fspy identifies system shells by their canonical parent directory for macOS compatibility. Real npx execution and generated-file assertions remain covered.

Verification

  • 647 create, workspace, and migration unit tests pass, including Yarn 1/2/4 runner selection and differing ambient/system versions.

  • All 15 system package-manager snapshots pass with --test-threads=2 and cover all four families, managed selection, missing-system fallback, and a real npm dependency installation.

  • The default-concurrency run hit seven 50-second timeouts; the lower-concurrency run passed without changing timeouts or expectations.

  • New local/global snapshots verify Yarn Classic external-template execution and, separately, its version pin in a built-in template.

  • Format, lint, type checks, and whitespace checks pass.

  • npm version-pin mismatch reproduced before the fix and corrected afterward.

  • After setting the canonical script shell, all 15 system package-manager snapshots pass again; JavaScript syntax and whitespace checks pass. All three macOS snapshot shards pass in CI, including both previously failing external-template cases. The final CI run passes across macOS, Linux, and Windows.

Limitations

Executable fixtures are Unix-only. The external-template cases verify real execution and generated files; they do not assert every subsequent migration step.

Use the selected system executable and version when scaffolding so the generated package-manager pin agrees with installation. Preserve managed downloads and local-only creation, and cover system selection, fallback, and npm installation.
Use the resolved Yarn version to select the existing npx fallback for Classic, which has no dlx command. Preserve Yarn 2+ template execution and cover runner selection, external scaffolding, and the built-in template version pin.
@SaKaNa-Y
SaKaNa-Y marked this pull request as ready for review September 15, 2026 13:47
The external-template regressions reached an npm shell launcher that crashes under fspy on macOS CI with an arm64/arm64e loader mismatch. Provision a fixed real npm and expose its npx JavaScript entry through a test-owned Node launcher. Keep both CLI flavors, real template execution, existing assertions, and snapshot expectations.
Avoid the system env interpreter as well as npm shell launchers under macOS file tracing. Use a temporary short symlink to the selected Node executable so the shebang stays within the tracer parser limit, assert that bound, and remove the symlink directory on exit.
Verify that external scaffolding actually enters the fixture-provided npx executable with the expected arguments. Include launcher-entry information when scaffolding fails so runner selection failures can be distinguished from downstream process failures.
The snapshot runner exposes sh through a symlink, but fspy recognizes system shells by their /bin or /usr/bin parent. npm resolves its default sh through PATH, bypassing the macOS injectable-shell substitution.

Set npm_config_script_shell to /bin/sh for the Unix external-template fixture. Remove the unnecessary custom npx launcher and its temporary interpreter; keep real template execution and generated-file assertions.
@SaKaNa-Y

Copy link
Copy Markdown
Contributor Author

For example, even when a user has configured Vite+ to prefer the system-installed pnpm, vp create still obtains a Vite+-managed pnpm version and writes it to devEngines.packageManager.version in the new project's package.json. The same version-pinning issue also affects npm, Yarn, and Bun. With npm, this mismatch can trigger EBADDEVENGINES and cause dependency installation to fail.

@liangmiQwQ
liangmiQwQ self-requested a review September 19, 2026 07:11
@liangmiQwQ

Copy link
Copy Markdown
Collaborator

Executable fixtures are Unix-only.

Is that possible to run fixtures on Windows?

}
// Use the same mode and system-tool lookup as the subsequent `vp install`.
// A system-first mode can still fall back to managed when no system tool exists.
const result = await runCommandSilently({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm thinking about whether it will be better to run <pm> --version.

Vite+ allows users who only use local-cli. For these users, it's more likely to have the problems this PR want to fix, but they can't be affected by this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You have a good point, I hadn’t considered users who only use the local CLI. I tested this workflow: local create successfully installs dependencies using the managed npm version, but subsequently running system npm in the generated project fails with the same EBADDEVENGINES version mismatch described in this PR. So local CLI users can encounter this conflict too, and this PR’s fallback logic doesn’t address that scenario.

@liangmiQwQ liangmiQwQ left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not sure whether the direction is right. IMO, following devEngines.packageManager.version's version spec should be expected even if users are using their own package manager. Also, pms that used by Vite+'s local cli are always its own, and I'm worried about maintaining an expection would be a bit off. I'm not sure whether this will be hold off for now.

BTW, I am incredibly grateful for your contributions; I was deeply moved by your responsible attitude toward the PR ❤️

@liangmiQwQ
liangmiQwQ requested a review from fengmk2 September 19, 2026 10:58
@SaKaNa-Y

SaKaNa-Y commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Executable fixtures are Unix-only.

Is that possible to run fixtures on Windows?

Sorry, this was an oversight on my part. These tests should cover Windows too. Once we’ve discussed and agreed on how to address this issue, I’ll add the necessary Windows support and test coverage.

@SaKaNa-Y

SaKaNa-Y commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Not sure whether the direction is right. IMO, following devEngines.packageManager.version's version spec should be expected even if users are using their own package manager. Also, pms that used by Vite+'s local cli are always its own, and I'm worried about maintaining an expection would be a bit off. I'm not sure whether this will be hold off for now.

BTW, I am incredibly grateful for your contributions; I was deeply moved by your responsible attitude toward the PR ❤️

I agree that existing package-manager version requirements declared by a project should be respected. My question is mainly about new projects that don’t have such a declaration yet. In the scenario this PR aims to fix, the user has already selected system-first mode, but create generates a requirement for the managed package-manager version selected by Vite+, which conflicts with the system version used for the subsequent installation.

In this case, shouldn’t the initial requirement match the version of the system package manager the user has chosen to use?

I also think your concern about introducing an exception to the local CLI’s behavior is worth discussing.

Thank you for the thoughtful review ❤️

@liangmiQwQ
liangmiQwQ removed the request for review from fengmk2 September 20, 2026 12:51
@liangmiQwQ

Copy link
Copy Markdown
Collaborator

My question is mainly about new projects that don’t have such a declaration yet.

Do you mean users whose installed package manager doesn't automatically use the correct version when they execute the corresponding binary?

create generates a requirement for the managed package-manager version selected by Vite+

Actually, rather than selected by Vite+, I think latest is semantically better here. But if users set to system-first mode, I agree that Vite+ should honor users' installed package manager.

Anyway, I might try to find a way to solve the problem I mentioned (Vite+'s local cli pm ownership), but not very soon. After that, I think this can be continued. I'll tell you when I'm ready.

@SaKaNa-Y

Copy link
Copy Markdown
Contributor Author

My question is mainly about new projects that don’t have such a declaration yet.

Do you mean users whose installed package manager doesn't automatically use the correct version when they execute the corresponding binary?

My main point is how create should choose the initial package-manager version requirement when a new project doesn’t have one yet, rather than just whether the package manager can automatically switch to the declared version.

For example, a user is running npm 11 in system-first mode, and the template has no package-manager declaration, but create writes a requirement for the latest npm version, npm 12. Even if the tool can automatically switch to 12, my question is still: should the initial requirement match the system version the user is already using?

create generates a requirement for the managed package-manager version selected by Vite+

Actually, rather than selected by Vite+, I think latest is semantically better here. But if users set to system-first mode, I agree that Vite+ should honor users' installed package manager.

Anyway, I might try to find a way to solve the problem I mentioned (Vite+'s local cli pm ownership), but not very soon. After that, I think this can be continued. I'll tell you when I'm ready.

“Latest” is indeed more accurate here. From your reply, I think we agree on how the initial version should be selected in system-first mode.

Thank you for continuing to look into this ❤️

This branch has not been deployed

No deployments
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.

2 participants