From 7e07e84481478bf3f84bab8861fe1da5afe3d0f0 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Wed, 15 Jul 2026 15:48:23 +0200 Subject: [PATCH 1/3] feat: add vite-plus support as a "build system" https://viteplus.dev doesn't quite fit into the boxes we currently use in this package, since it's a sort of package manager wrapper, a monorepo/build tool, and it even has `vp build` and `vp dev`. But it seems we can get most of this working by just registering it as a "build system": - It's detected. We need this to show a pretty logo, capture usage in telemetry, and to run `vp install` automatically in our build system. - The monorepo tooling should just work. This is used by Netlify CLI's `netlify dev --filter foo` to construct the right underlying `vp` command. --- package-lock.json | 33 ++++ .../logos/vite-plus/icon-color-dark.svg | 1 + .../logos/vite-plus/icon-color-light.svg | 1 + packages/build-info/package.json | 1 + .../build-info/src/build-systems/index.ts | 2 + .../src/build-systems/vite-plus.test.ts | 165 ++++++++++++++++++ .../build-info/src/build-systems/vite-plus.ts | 101 +++++++++++ 7 files changed, 304 insertions(+) create mode 100644 packages/build-info/assets/logos/vite-plus/icon-color-dark.svg create mode 100644 packages/build-info/assets/logos/vite-plus/icon-color-light.svg create mode 100644 packages/build-info/src/build-systems/vite-plus.test.ts create mode 100644 packages/build-info/src/build-systems/vite-plus.ts diff --git a/package-lock.json b/package-lock.json index 8322ed4107..0596c797ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4981,6 +4981,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4994,6 +4995,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5005,6 +5007,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5018,6 +5021,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5031,6 +5035,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5044,6 +5049,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5057,6 +5063,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5070,6 +5077,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5083,6 +5091,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5096,6 +5105,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5109,6 +5119,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5122,6 +5133,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5135,6 +5147,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5148,6 +5161,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5161,6 +5175,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5174,6 +5189,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5187,6 +5203,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5200,6 +5217,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5213,6 +5231,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5226,6 +5245,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5239,6 +5259,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5252,6 +5273,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5265,6 +5287,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5278,6 +5301,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5291,6 +5315,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12851,6 +12876,7 @@ }, "node_modules/fsevents": { "version": "2.3.2", + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15885,6 +15911,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lockparse": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/lockparse/-/lockparse-0.5.2.tgz", + "integrity": "sha512-iu19W86kvrT2MLpvyXoIn/351Rb3PO7v7ljgFRQYj8tGpBRvNO9cZEI8x/7GGN+WN6BbrWpXc5CPrgPUjgX6Iw==", + "license": "MIT" + }, "node_modules/lodash": { "version": "4.18.1", "license": "MIT" @@ -23143,6 +23175,7 @@ "@iarna/toml": "^2.2.5", "dot-prop": "^9.0.0", "find-up": "^7.0.0", + "lockparse": "^0.5.2", "minimatch": "^10.2.4", "read-pkg": "^9.0.0", "semver": "^7.3.8", diff --git a/packages/build-info/assets/logos/vite-plus/icon-color-dark.svg b/packages/build-info/assets/logos/vite-plus/icon-color-dark.svg new file mode 100644 index 0000000000..a7c3ce4897 --- /dev/null +++ b/packages/build-info/assets/logos/vite-plus/icon-color-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/build-info/assets/logos/vite-plus/icon-color-light.svg b/packages/build-info/assets/logos/vite-plus/icon-color-light.svg new file mode 100644 index 0000000000..bbbbf6f688 --- /dev/null +++ b/packages/build-info/assets/logos/vite-plus/icon-color-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/build-info/package.json b/packages/build-info/package.json index 72a1db1177..c15f1004a8 100644 --- a/packages/build-info/package.json +++ b/packages/build-info/package.json @@ -48,6 +48,7 @@ "@iarna/toml": "^2.2.5", "dot-prop": "^9.0.0", "find-up": "^7.0.0", + "lockparse": "^0.5.2", "minimatch": "^10.2.4", "read-pkg": "^9.0.0", "semver": "^7.3.8", diff --git a/packages/build-info/src/build-systems/index.ts b/packages/build-info/src/build-systems/index.ts index e8f50932bf..1f8bce9777 100644 --- a/packages/build-info/src/build-systems/index.ts +++ b/packages/build-info/src/build-systems/index.ts @@ -10,6 +10,7 @@ import { NPM, PNPM, Yarn } from './package-managers.js' import { Pants } from './pants.js' import { Rush } from './rush.js' import { Turbo } from './turbo.js' +import { VitePlus } from './vite-plus.js' export const buildSystems = [ Bazel, @@ -23,6 +24,7 @@ export const buildSystems = [ Pants, Rush, Turbo, + VitePlus, // JavaScript Package managers that offer building from a workspace PNPM, diff --git a/packages/build-info/src/build-systems/vite-plus.test.ts b/packages/build-info/src/build-systems/vite-plus.test.ts new file mode 100644 index 0000000000..9bb6ae0dac --- /dev/null +++ b/packages/build-info/src/build-systems/vite-plus.test.ts @@ -0,0 +1,165 @@ +import { join } from 'path' + +import { beforeEach, describe, expect, test } from 'vitest' + +import { mockFileSystem } from '../../tests/mock-file-system.js' +import { NodeFS } from '../node/file-system.js' +import { Project } from '../project.js' + +beforeEach((ctx) => { + ctx.fs = new NodeFS() +}) + +const NPM_LOCKFILE = JSON.stringify({ + name: 'fixture', + version: '1.0.0', + lockfileVersion: 3, + requires: true, + packages: { + '': { name: 'fixture', version: '1.0.0', devDependencies: { 'vite-plus': '^0.2.0' } }, + 'node_modules/vite-plus': { + version: '0.2.4', + resolved: 'https://registry.npmjs.org/vite-plus/-/vite-plus-0.2.4.tgz', + integrity: 'sha512-fixture', + }, + }, +}) + +const PNPM_LOCKFILE = `lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + vite-plus: + specifier: ^0.2.0 + version: 0.2.4 + +packages: + + vite-plus@0.2.4: + resolution: {integrity: sha512-fixture} +` + +const YARN_LOCKFILE = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +vite-plus@^0.2.0: + version "0.2.4" + resolved "https://registry.yarnpkg.com/vite-plus/-/vite-plus-0.2.4.tgz#fixture" + integrity sha512-fixture +` + +test('detects vite-plus via a devDependency and reports the declared version without a lock file', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { 'vite-plus': '^0.2.0' } }), + }) + const detected = await new Project(fs, cwd).detectBuildSystem() + + expect(detected[0]?.id).toBe('vite-plus') + expect(detected[0]?.name).toBe('Vite Plus') + expect(detected[0]?.version).toBe('^0.2.0') +}) + +test('detects vite-plus via a regular dependency', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ dependencies: { 'vite-plus': '0.2.4' } }), + }) + const detected = await new Project(fs, cwd).detectBuildSystem() + + expect(detected[0]?.id).toBe('vite-plus') + expect(detected[0]?.version).toBe('0.2.4') +}) + +test('does not detect vite-plus without the dependency', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { vite: '^6.0.0' } }), + }) + const detected = await new Project(fs, cwd).detectBuildSystem() + + expect(detected.find(({ id }) => id === 'vite-plus')).toBeUndefined() +}) + +describe.each([ + { lockfileName: 'package-lock.json', lockfileContents: NPM_LOCKFILE }, + { lockfileName: 'pnpm-lock.yaml', lockfileContents: PNPM_LOCKFILE }, + { lockfileName: 'yarn.lock', lockfileContents: YARN_LOCKFILE }, +])('with a $lockfileName lock file', ({ lockfileName, lockfileContents }) => { + test('resolves the locked version', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { 'vite-plus': '^0.2.0' } }), + [lockfileName]: lockfileContents, + }) + const detected = await new Project(fs, cwd).detectBuildSystem() + + expect(detected[0]?.id).toBe('vite-plus') + expect(detected[0]?.version).toBe('0.2.4') + }) +}) + +test('detects vite-plus from a monorepo base directory with the dependency at the root', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ + workspaces: ['apps/*'], + devDependencies: { 'vite-plus': '^0.2.0' }, + }), + 'package-lock.json': NPM_LOCKFILE, + 'apps/web/package.json': JSON.stringify({ name: 'web' }), + }) + const detected = await new Project(fs, join(cwd, 'apps/web'), cwd).detectBuildSystem() + + const vitePlus = detected.find(({ id }) => id === 'vite-plus') + expect(vitePlus?.version).toBe('0.2.4') +}) + +test('provides vp run workspace commands for a package', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ workspaces: ['apps/*'], devDependencies: { 'vite-plus': '^0.2.0' } }), + 'apps/web/package.json': JSON.stringify({ + name: 'web', + scripts: { dev: 'vite', build: 'vite build', lint: 'oxlint' }, + }), + }) + const [vitePlus] = await new Project(fs, cwd).detectBuildSystem() + + expect(vitePlus.id).toBe('vite-plus') + expect(await vitePlus.getCommands('apps/web')).toEqual([ + { type: 'dev', command: 'vp run --filter web dev' }, + { type: 'build', command: 'vp run --filter web build' }, + { type: 'unknown', command: 'vp run --filter web lint' }, + ]) +}) + +test('returns no commands for a package without a name', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ workspaces: ['apps/*'], devDependencies: { 'vite-plus': '^0.2.0' } }), + 'apps/web/package.json': JSON.stringify({ scripts: { build: 'vite build' } }), + }) + const [vitePlus] = await new Project(fs, cwd).detectBuildSystem() + + expect(await vitePlus.getCommands('apps/web')).toEqual([]) +}) + +test('falls back to the declared version when the lock file does not contain the package', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { 'vite-plus': '^0.2.0' } }), + 'package-lock.json': JSON.stringify({ + name: 'fixture', + version: '1.0.0', + lockfileVersion: 3, + requires: true, + packages: { + '': { name: 'fixture', version: '1.0.0' }, + }, + }), + }) + const detected = await new Project(fs, cwd).detectBuildSystem() + + expect(detected[0]?.id).toBe('vite-plus') + expect(detected[0]?.version).toBe('^0.2.0') +}) diff --git a/packages/build-info/src/build-systems/vite-plus.ts b/packages/build-info/src/build-systems/vite-plus.ts new file mode 100644 index 0000000000..850f126dab --- /dev/null +++ b/packages/build-info/src/build-systems/vite-plus.ts @@ -0,0 +1,101 @@ +import { parse, type PackageJsonLike } from 'lockparse' +import type { PackageJson } from 'read-pkg' + +import { NPM_BUILD_SCRIPTS, NPM_DEV_SCRIPTS } from '../get-commands.js' + +import { BaseBuildTool, type Command } from './build-system.js' + +const PACKAGE_NAME = 'vite-plus' + +/** Lock files `lockparse` can read (bun.lockb is binary and unsupported) */ +const LOCK_FILES = ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lock'] + +export class VitePlus extends BaseBuildTool { + id = 'vite-plus' + name = 'Vite Plus' + runFromRoot = true + + logo = { + default: '/logos/vite-plus/icon-color-light.svg', + light: '/logos/vite-plus/icon-color-light.svg', + dark: '/logos/vite-plus/icon-color-dark.svg', + } + + /** Retrieves a list of possible commands for a package */ + async getCommands(packagePath: string): Promise { + const { scripts, name } = await this.project.fs.readJSON( + this.project.resolveFromPackage(packagePath, 'package.json'), + ) + + if (name && scripts && Object.values(scripts).length) { + return Object.keys(scripts).map((target) => { + let type: Command['type'] = 'unknown' + + if (NPM_DEV_SCRIPTS.includes(target)) { + type = 'dev' + } + + if (NPM_BUILD_SCRIPTS.includes(target)) { + type = 'build' + } + + return { + type, + command: `vp run --filter ${name} ${target}`, + } + }) + } + return [] + } + + /** + * Vite Plus has no unique config file (vite.config.* is shared with plain Vite), so + * it's detected through a dependency on the `vite-plus` package, declared anywhere + * from the base directory up to the repository root. + */ + async detect(): Promise { + const pkgJsonPaths = await this.project.fs.findUpMultiple('package.json', { + cwd: this.project.baseDirectory, + stopAt: this.project.root, + }) + + for (const pkgJsonPath of pkgJsonPaths) { + const pkgJson = await this.project.fs.readJSON(pkgJsonPath) + const declared = pkgJson.devDependencies?.[PACKAGE_NAME] ?? pkgJson.dependencies?.[PACKAGE_NAME] + if (declared) { + // Unlike other build systems, report the exact locked version when resolvable: + // consumers install the vp CLI version matching the project's lock file. + // Note that, since vite-plus is also used as a package manager (... wrapper), we can't just *install* first and + // then read the installed version 🔁. + this.version = (await this.resolveLockedVersion(pkgJson)) ?? declared + return this + } + } + } + + private async resolveLockedVersion(pkgJson: Partial): Promise { + const lockfilePath = await this.project.fs.findUp(LOCK_FILES, { + cwd: this.project.baseDirectory, + stopAt: this.project.root, + }) + if (!lockfilePath) { + return undefined + } + + const content = await this.project.fs.gracefullyReadFile(lockfilePath) + if (!content) { + return undefined + } + + try { + const fileName = this.project.fs.basename(lockfilePath) + // npm-shrinkwrap.json shares the package-lock.json format + const typeOrFileName = fileName === 'npm-shrinkwrap.json' ? 'npm' : fileName + const { packages } = await parse(content, typeOrFileName, pkgJson as PackageJsonLike) + return packages.find((pkg) => pkg.name === PACKAGE_NAME)?.version + } catch { + // an unparsable lock file shouldn't fail detection; fall back to the declared range + return undefined + } + } +} From e6f1c750d7da4d8c9f6914f3855100ad6ec776b9 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Wed, 15 Jul 2026 16:32:18 +0200 Subject: [PATCH 2/3] feat: default to `vp build`, `vp dev` when vite-plus is present --- .../build-info/src/frameworks/vite.test.ts | 57 +++++++++++++++++++ packages/build-info/src/frameworks/vite.ts | 21 ++++++- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 packages/build-info/src/frameworks/vite.test.ts diff --git a/packages/build-info/src/frameworks/vite.test.ts b/packages/build-info/src/frameworks/vite.test.ts new file mode 100644 index 0000000000..770802ca26 --- /dev/null +++ b/packages/build-info/src/frameworks/vite.test.ts @@ -0,0 +1,57 @@ +import { beforeEach, describe, expect, test } from 'vitest' + +import { mockFileSystem } from '../../tests/mock-file-system.js' +import { NodeFS } from '../node/file-system.js' +import { Project } from '../project.js' + +beforeEach((ctx) => { + ctx.fs = new NodeFS() +}) + +describe('vite', () => { + test('detects a vite project', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { vite: '^7.0.0' } }), + }) + const detected = await new Project(fs, cwd).detectFrameworks() + + expect(detected?.[0].id).toBe('vite') + expect(detected?.[0].build.command).toBe('vite build') + expect(detected?.[0].build.directory).toBe('dist') + expect(detected?.[0].dev?.command).toBe('vite') + }) + + test('uses the vp command surface for a vite-plus project', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { 'vite-plus': '^0.2.0' } }), + }) + const detected = await new Project(fs, cwd).detectFrameworks() + + expect(detected?.[0].id).toBe('vite') + expect(detected?.[0].build.command).toBe('vp build') + expect(detected?.[0].build.directory).toBe('dist') + expect(detected?.[0].dev?.command).toBe('vp dev') + }) + + test('prefers the vp command surface when both vite and vite-plus are present', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ devDependencies: { vite: '^7.0.0', 'vite-plus': '^0.2.0' } }), + }) + const detected = await new Project(fs, cwd).detectFrameworks() + + expect(detected?.[0].id).toBe('vite') + expect(detected?.[0].build.command).toBe('vp build') + expect(detected?.[0].dev?.command).toBe('vp dev') + }) + + test('is not detected when a vite-based meta-framework is present', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ + devDependencies: { 'vite-plus': '^0.2.0', '@sveltejs/kit': '^2.0.0', svelte: '^5.0.0' }, + }), + }) + const detected = await new Project(fs, cwd).detectFrameworks() + + expect(detected?.find(({ id }) => id === 'vite')).toBeUndefined() + }) +}) diff --git a/packages/build-info/src/frameworks/vite.ts b/packages/build-info/src/frameworks/vite.ts index ac27237b8f..8a5b57855e 100644 --- a/packages/build-info/src/frameworks/vite.ts +++ b/packages/build-info/src/frameworks/vite.ts @@ -1,9 +1,9 @@ -import { BaseFramework, Category, Framework } from './framework.js' +import { BaseFramework, Category, DetectedFramework, Framework } from './framework.js' export class Vite extends BaseFramework implements Framework { readonly id = 'vite' name = 'Vite' - npmDependencies = ['vite'] + npmDependencies = ['vite', 'vite-plus'] excludedNpmDependencies = [ '@remix-run/react', '@remix-run/dev', @@ -40,4 +40,21 @@ export class Vite extends BaseFramework implements Framework { light: '/logos/vite/default.svg', dark: '/logos/vite/default.svg', } + + async detect(): Promise { + const detected = await super.detect() + + // Vite Plus projects drive Vite through the vp CLI (`vp migrate` may even remove + // the direct vite dependency), so prefer its command surface when present + const deps = { + ...this.detected?.packageJSON?.dependencies, + ...this.detected?.packageJSON?.devDependencies, + } + if (detected && deps['vite-plus']) { + this.dev.command = 'vp dev' + this.build.command = 'vp build' + } + + return detected + } } From d563c7ab885af4da97534d5c0acbfb0ebb7acfb8 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Thu, 16 Jul 2026 08:38:27 +0200 Subject: [PATCH 3/3] fix: find lockfile from package.json dir --- .../src/build-systems/vite-plus.test.ts | 25 +++++++++++++++++++ .../build-info/src/build-systems/vite-plus.ts | 8 +++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/build-info/src/build-systems/vite-plus.test.ts b/packages/build-info/src/build-systems/vite-plus.test.ts index 9bb6ae0dac..0e8fc6507f 100644 --- a/packages/build-info/src/build-systems/vite-plus.test.ts +++ b/packages/build-info/src/build-systems/vite-plus.test.ts @@ -117,6 +117,31 @@ test('detects vite-plus from a monorepo base directory with the dependency at th expect(vitePlus?.version).toBe('0.2.4') }) +test('resolves against the lock file of the package.json with vite-plus dep', async ({ fs }) => { + const cwd = mockFileSystem({ + 'package.json': JSON.stringify({ + workspaces: ['apps/*'], + devDependencies: { 'vite-plus': '^0.2.0' }, + }), + 'package-lock.json': NPM_LOCKFILE, + 'apps/web/package.json': JSON.stringify({ name: 'web' }), + // stray nested lock file that does not lock the root's dependencies + 'apps/web/package-lock.json': JSON.stringify({ + name: 'web', + version: '1.0.0', + lockfileVersion: 3, + requires: true, + packages: { + '': { name: 'web', version: '1.0.0' }, + }, + }), + }) + const detected = await new Project(fs, join(cwd, 'apps/web'), cwd).detectBuildSystem() + + const vitePlus = detected.find(({ id }) => id === 'vite-plus') + expect(vitePlus?.version).toBe('0.2.4') +}) + test('provides vp run workspace commands for a package', async ({ fs }) => { const cwd = mockFileSystem({ 'package.json': JSON.stringify({ workspaces: ['apps/*'], devDependencies: { 'vite-plus': '^0.2.0' } }), diff --git a/packages/build-info/src/build-systems/vite-plus.ts b/packages/build-info/src/build-systems/vite-plus.ts index 850f126dab..e10cae320b 100644 --- a/packages/build-info/src/build-systems/vite-plus.ts +++ b/packages/build-info/src/build-systems/vite-plus.ts @@ -67,15 +67,15 @@ export class VitePlus extends BaseBuildTool { // consumers install the vp CLI version matching the project's lock file. // Note that, since vite-plus is also used as a package manager (... wrapper), we can't just *install* first and // then read the installed version 🔁. - this.version = (await this.resolveLockedVersion(pkgJson)) ?? declared + this.version = (await this.resolveLockedVersion(pkgJson, pkgJsonPath)) ?? declared return this } } } - private async resolveLockedVersion(pkgJson: Partial): Promise { + private async resolveLockedVersion(pkgJson: Partial, pkgJsonPath: string): Promise { const lockfilePath = await this.project.fs.findUp(LOCK_FILES, { - cwd: this.project.baseDirectory, + cwd: this.project.fs.dirname(pkgJsonPath), stopAt: this.project.root, }) if (!lockfilePath) { @@ -94,7 +94,7 @@ export class VitePlus extends BaseBuildTool { const { packages } = await parse(content, typeOrFileName, pkgJson as PackageJsonLike) return packages.find((pkg) => pkg.name === PACKAGE_NAME)?.version } catch { - // an unparsable lock file shouldn't fail detection; fall back to the declared range + // An unparsable lock file shouldn't fail detection; fall back to the declared range return undefined } }