Skip to content

Commit f206096

Browse files
fix(optimizer): fall back to yarn.lock for lockfile hash (#23667)
Co-authored-by: sapphi-red <green@sapphi.red>
1 parent a4bfdb1 commit f206096

6 files changed

Lines changed: 63 additions & 7 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo@1.0.0:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!/node_modules/

‎packages/vite/src/node/__tests__/optimizer/fixtures/lockfile-hash/yarn-state/node_modules/.yarn-state.yml‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo@1.0.0:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import fs from 'node:fs'
2+
import os from 'node:os'
3+
import path from 'node:path'
4+
import { beforeAll, expect, test } from 'vitest'
5+
import { getLockfileHash } from '../../optimizer'
6+
import { getHash } from '../../utils'
7+
8+
const fixturesDir = path.join(import.meta.dirname, 'fixtures/lockfile-hash')
9+
let root: string
10+
11+
beforeAll(() => {
12+
// Copy outside the repo so lookup does not find the repo's own lockfile.
13+
root = fs.mkdtempSync(
14+
path.join(fs.realpathSync(os.tmpdir()), 'vite-lockfile-hash-'),
15+
)
16+
fs.cpSync(fixturesDir, root, { recursive: true })
17+
return () => {
18+
fs.rmSync(root, { recursive: true, force: true })
19+
}
20+
})
21+
22+
test('falls back to yarn.lock when no lockfile is found in node_modules', () => {
23+
const fixture = path.join(root, 'yarn-lock')
24+
const content = fs.readFileSync(path.join(fixture, 'yarn.lock'))
25+
26+
expect(getLockfileHash(fixture)).toBe(getHash(content))
27+
})
28+
29+
test('prefers lockfiles in node_modules over yarn.lock', () => {
30+
const fixture = path.join(root, 'yarn-state')
31+
const content = fs.readFileSync(
32+
path.join(fixture, 'node_modules/.yarn-state.yml'),
33+
)
34+
35+
expect(getLockfileHash(fixture)).toBe(getHash(content))
36+
})

‎packages/vite/src/node/optimizer/index.ts‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,9 @@ export async function loadCachedDepOptimizationMetadata(
418418
} catch {}
419419
// hash is consistent, no need to re-bundle
420420
if (cachedMetadata) {
421-
if (cachedMetadata.lockfileHash !== getLockfileHash(environment)) {
421+
if (
422+
cachedMetadata.lockfileHash !== getLockfileHash(environment.config.root)
423+
) {
422424
environment.logger.info(
423425
'Re-optimizing dependencies because lockfile has changed',
424426
{
@@ -1299,6 +1301,18 @@ const lockfileFormats = [
12991301
})
13001302
const lockfilePaths = lockfileFormats.map((l) => l.path)
13011303

1304+
// Only used when none of the formats above is found, so it never changes which
1305+
// lockfile is hashed for projects that already have one of them.
1306+
// e.g. Yarn with `nodeLinker: pnpm` writes neither `.yarn-state.yml` nor `.pnp.cjs`.
1307+
const fallbackLockfileFormats = [
1308+
{
1309+
path: 'yarn.lock',
1310+
checkPatchesDir: '.yarn/patches',
1311+
manager: 'yarn',
1312+
},
1313+
]
1314+
const fallbackLockfilePaths = fallbackLockfileFormats.map((l) => l.path)
1315+
13021316
function getConfigHash(environment: Environment): string {
13031317
// Take config into account
13041318
// only a subset of config options that can affect dep optimization
@@ -1344,14 +1358,16 @@ function getConfigHash(environment: Environment): string {
13441358
return getHash(content)
13451359
}
13461360

1347-
function getLockfileHash(environment: Environment): string {
1348-
const lockfilePath = lookupFile(environment.config.root, lockfilePaths)
1361+
export function getLockfileHash(root: string): string {
1362+
const lockfilePath =
1363+
lookupFile(root, lockfilePaths) ?? lookupFile(root, fallbackLockfilePaths)
13491364
let content = lockfilePath ? fs.readFileSync(lockfilePath, 'utf-8') : ''
13501365
if (lockfilePath) {
13511366
const normalizedLockfilePath = lockfilePath.replaceAll('\\', '/')
1352-
const lockfileFormat = lockfileFormats.find((f) =>
1353-
normalizedLockfilePath.endsWith(f.path),
1354-
)!
1367+
const lockfileFormat = [
1368+
...lockfileFormats,
1369+
...fallbackLockfileFormats,
1370+
].find((f) => normalizedLockfilePath.endsWith(f.path))!
13551371
if (lockfileFormat.checkPatchesDir) {
13561372
// Default of https://github.com/ds300/patch-package
13571373
const baseDir = lockfilePath.slice(0, -lockfileFormat.path.length)
@@ -1373,7 +1389,7 @@ function getDepHash(environment: Environment): {
13731389
configHash: string
13741390
hash: string
13751391
} {
1376-
const lockfileHash = getLockfileHash(environment)
1392+
const lockfileHash = getLockfileHash(environment.config.root)
13771393
const configHash = getConfigHash(environment)
13781394
const hash = getHash(lockfileHash + configHash)
13791395
return {

0 commit comments

Comments
 (0)