Conversation
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.
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.
|
For example, even when a user has configured Vite+ to prefer the system-installed pnpm, |
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({ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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 ❤️
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. |
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 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 ❤️ |
Do you mean users whose installed package manager doesn't automatically use the correct version when they execute the corresponding binary?
Actually, rather than 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. |
My main point is how For example, a user is running npm 11 in system-first mode, and the template has no package-manager declaration, but
“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 ❤️ |
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 createalways downloaded a managed package-manager release before scaffolding, even when that family was configured to use the system installation. The generateddevEngines.packageManager.versioncould therefore disagree with the executable used for installation. With npm, this can fail withEBADDEVENGINES; the same incorrect pinning also affects pnpm, Yarn, and Bun.Resolve the selected family through
vp env currentbefore 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
dlxcommand. Selectnpx --yesfrom the resolved Yarn version, matching the existingvp dlxfallback; Yarn 2+ continues to useyarn 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 exposesshthrough 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=2and 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.