@@ -191,6 +191,16 @@ export interface DepOptimizationMetadata {
|
191 | 191 | * This is checked on server startup to avoid unnecessary re-bundles.
|
192 | 192 | */
|
193 | 193 | hash: string
|
| 194 | +/** |
| 195 | +* This hash is determined by dependency lockfiles. |
| 196 | +* This is checked on server startup to avoid unnecessary re-bundles. |
| 197 | +*/ |
| 198 | +lockfileHash: string |
| 199 | +/** |
| 200 | +* This hash is determined by user config. |
| 201 | +* This is checked on server startup to avoid unnecessary re-bundles. |
| 202 | +*/ |
| 203 | +configHash: string |
194 | 204 | /**
|
195 | 205 | * The browser hash is determined by the main hash plus additional dependencies
|
196 | 206 | * discovered at runtime. This is used to invalidate browser requests to
|
@@ -310,9 +320,11 @@ export function initDepsOptimizerMetadata(
|
310 | 320 | ssr: boolean,
|
311 | 321 | timestamp?: string,
|
312 | 322 | ): DepOptimizationMetadata {
|
313 |
| -const hash = getDepHash(config, ssr) |
| 323 | +const { lockfileHash, configHash, hash } = getDepHash(config, ssr) |
314 | 324 | return {
|
315 | 325 | hash,
|
| 326 | +lockfileHash, |
| 327 | +configHash, |
316 | 328 | browserHash: getOptimizedBrowserHash(hash, {}, timestamp),
|
317 | 329 | optimized: {},
|
318 | 330 | chunks: {},
|
@@ -363,11 +375,21 @@ export async function loadCachedDepOptimizationMetadata(
|
363 | 375 | )
|
364 | 376 | } catch (e) {}
|
365 | 377 | // hash is consistent, no need to re-bundle
|
366 |
| -if (cachedMetadata && cachedMetadata.hash === getDepHash(config, ssr)) { |
367 |
| -log?.('Hash is consistent. Skipping. Use --force to override.') |
368 |
| -// Nothing to commit or cancel as we are using the cache, we only |
369 |
| -// need to resolve the processing promise so requests can move on |
370 |
| -return cachedMetadata |
| 378 | +if (cachedMetadata) { |
| 379 | +if (cachedMetadata.lockfileHash !== getLockfileHash(config, ssr)) { |
| 380 | +config.logger.info( |
| 381 | +'Re-optimizing dependencies because lockfile has changed', |
| 382 | +) |
| 383 | +} else if (cachedMetadata.configHash !== getConfigHash(config, ssr)) { |
| 384 | +config.logger.info( |
| 385 | +'Re-optimizing dependencies because vite config has changed', |
| 386 | +) |
| 387 | +} else { |
| 388 | +log?.('Hash is consistent. Skipping. Use --force to override.') |
| 389 | +// Nothing to commit or cancel as we are using the cache, we only |
| 390 | +// need to resolve the processing promise so requests can move on |
| 391 | +return cachedMetadata |
| 392 | +} |
371 | 393 | }
|
372 | 394 | } else {
|
373 | 395 | config.logger.info('Forced re-optimization of dependencies')
|
@@ -417,7 +439,7 @@ export function toDiscoveredDependencies(
|
417 | 439 | timestamp?: string,
|
418 | 440 | ): Record<string, OptimizedDepInfo> {
|
419 | 441 | const browserHash = getOptimizedBrowserHash(
|
420 |
| -getDepHash(config, ssr), |
| 442 | +getDepHash(config, ssr).hash, |
421 | 443 | deps,
|
422 | 444 | timestamp,
|
423 | 445 | )
|
@@ -975,17 +997,15 @@ function parseDepsOptimizerMetadata(
|
975 | 997 | jsonMetadata: string,
|
976 | 998 | depsCacheDir: string,
|
977 | 999 | ): DepOptimizationMetadata | undefined {
|
978 |
| -const { hash, browserHash, optimized, chunks } = JSON.parse( |
979 |
| -jsonMetadata, |
980 |
| -(key: string, value: string) => { |
| 1000 | +const { hash, lockfileHash, configHash, browserHash, optimized, chunks } = |
| 1001 | +JSON.parse(jsonMetadata, (key: string, value: string) => { |
981 | 1002 | // Paths can be absolute or relative to the deps cache dir where
|
982 | 1003 | // the _metadata.json is located
|
983 | 1004 | if (key === 'file' || key === 'src') {
|
984 | 1005 | return normalizePath(path.resolve(depsCacheDir, value))
|
985 | 1006 | }
|
986 | 1007 | return value
|
987 |
| -}, |
988 |
| -) |
| 1008 | +}) |
989 | 1009 | if (
|
990 | 1010 | !chunks ||
|
991 | 1011 | Object.values(optimized).some((depInfo: any) => !depInfo.fileHash)
|
@@ -995,6 +1015,8 @@ function parseDepsOptimizerMetadata(
|
995 | 1015 | }
|
996 | 1016 | const metadata = {
|
997 | 1017 | hash,
|
| 1018 | +lockfileHash, |
| 1019 | +configHash, |
998 | 1020 | browserHash,
|
999 | 1021 | optimized: {},
|
1000 | 1022 | discovered: {},
|
@@ -1029,10 +1051,13 @@ function stringifyDepsOptimizerMetadata(
|
1029 | 1051 | metadata: DepOptimizationMetadata,
|
1030 | 1052 | depsCacheDir: string,
|
1031 | 1053 | ) {
|
1032 |
| -const { hash, browserHash, optimized, chunks } = metadata |
| 1054 | +const { hash, configHash, lockfileHash, browserHash, optimized, chunks } = |
| 1055 | +metadata |
1033 | 1056 | return JSON.stringify(
|
1034 | 1057 | {
|
1035 | 1058 | hash,
|
| 1059 | +configHash, |
| 1060 | +lockfileHash, |
1036 | 1061 | browserHash,
|
1037 | 1062 | optimized: Object.fromEntries(
|
1038 | 1063 | Object.values(optimized).map(
|
@@ -1187,27 +1212,11 @@ const lockfileFormats = [
|
1187 | 1212 | })
|
1188 | 1213 | const lockfileNames = lockfileFormats.map((l) => l.name)
|
1189 | 1214 |
|
1190 |
| -export function getDepHash(config: ResolvedConfig, ssr: boolean): string { |
1191 |
| -const lockfilePath = lookupFile(config.root, lockfileNames) |
1192 |
| -let content = lockfilePath ? fs.readFileSync(lockfilePath, 'utf-8') : '' |
1193 |
| -if (lockfilePath) { |
1194 |
| -const lockfileName = path.basename(lockfilePath) |
1195 |
| -const { checkes } = lockfileFormats.find( |
1196 |
| -(f) => f.name === lockfileName, |
1197 |
| -)! |
1198 |
| -if (checkes) { |
1199 |
| -// Default of https://.com/ds300/-package |
1200 |
| -const fullPath = path.join(path.dirname(lockfilePath), 'es') |
1201 |
| -const stat = tryStatSync(fullPath) |
1202 |
| -if (stat?.isDirectory()) { |
1203 |
| -content += stat.mtimeMs.toString() |
1204 |
| -} |
1205 |
| -} |
1206 |
| -} |
1207 |
| -// also take config into account |
| 1215 | +function getConfigHash(config: ResolvedConfig, ssr: boolean): string { |
| 1216 | +// Take config into account |
1208 | 1217 | // only a subset of config options that can affect dep optimization
|
1209 | 1218 | const optimizeDeps = getDepOptimizationConfig(config, ssr)
|
1210 |
| -content += JSON.stringify( |
| 1219 | +const content = JSON.stringify( |
1211 | 1220 | {
|
1212 | 1221 | mode: process.env.NODE_ENV || config.mode,
|
1213 | 1222 | root: config.root,
|
@@ -1238,6 +1247,40 @@ export function getDepHash(config: ResolvedConfig, ssr: boolean): string {
|
1238 | 1247 | return getHash(content)
|
1239 | 1248 | }
|
1240 | 1249 |
|
| 1250 | +function getLockfileHash(config: ResolvedConfig, ssr: boolean): string { |
| 1251 | +const lockfilePath = lookupFile(config.root, lockfileNames) |
| 1252 | +let content = lockfilePath ? fs.readFileSync(lockfilePath, 'utf-8') : '' |
| 1253 | +if (lockfilePath) { |
| 1254 | +const lockfileName = path.basename(lockfilePath) |
| 1255 | +const { checkes } = lockfileFormats.find( |
| 1256 | +(f) => f.name === lockfileName, |
| 1257 | +)! |
| 1258 | +if (checkes) { |
| 1259 | +// Default of https://.com/ds300/-package |
| 1260 | +const fullPath = path.join(path.dirname(lockfilePath), 'es') |
| 1261 | +const stat = tryStatSync(fullPath) |
| 1262 | +if (stat?.isDirectory()) { |
| 1263 | +content += stat.mtimeMs.toString() |
| 1264 | +} |
| 1265 | +} |
| 1266 | +} |
| 1267 | +return getHash(content) |
| 1268 | +} |
| 1269 | + |
| 1270 | +function getDepHash( |
| 1271 | +config: ResolvedConfig, |
| 1272 | +ssr: boolean, |
| 1273 | +): { lockfileHash: string; configHash: string; hash: string } { |
| 1274 | +const lockfileHash = getLockfileHash(config, ssr) |
| 1275 | +const configHash = getConfigHash(config, ssr) |
| 1276 | +const hash = getHash(lockfileHash + configHash) |
| 1277 | +return { |
| 1278 | +hash, |
| 1279 | +lockfileHash, |
| 1280 | +configHash, |
| 1281 | +} |
| 1282 | +} |
| 1283 | + |
1241 | 1284 | function getOptimizedBrowserHash(
|
1242 | 1285 | hash: string,
|
1243 | 1286 | deps: Record<string, string>,
|
|
0 commit comments