diff --git a/packages/vite/package.json b/packages/vite/package.json index 4afe92d0e43eef..ed039f9b1fcff6 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -73,6 +73,7 @@ }, "//": "READ CONTRIBUTING.md to understand what to put under deps vs. devDeps!", "dependencies": { + "@voidzero-dev/vite-task-client": "^0.1.1", "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 53bdd1ca7c1b4a..ebd09428bfc781 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -6,6 +6,11 @@ import { inspect, promisify } from 'node:util' import { performance } from 'node:perf_hooks' import { createRequire } from 'node:module' import crypto from 'node:crypto' +import { + getEnv, + ignoreInput, + ignoreOutput, +} from '@voidzero-dev/vite-task-client' import colors from 'picocolors' import picomatch from 'picomatch' import { @@ -1401,6 +1406,14 @@ export async function resolveConfig( let configFileDependencies: string[] = [] let mode = inlineConfig.mode || defaultMode + // When `NODE_ENV` isn't set locally, ask Vite Task for it; the runner + // also records the env in the build's cache key. + if (process.env.NODE_ENV === undefined) { + const nodeEnv = getEnv('NODE_ENV') + if (nodeEnv !== undefined) { + process.env.NODE_ENV = nodeEnv + } + } const isNodeEnvSet = !!process.env.NODE_ENV const packageCache: PackageCache = new Map() @@ -2581,6 +2594,11 @@ async function loadConfigFromBundledFile( `.vite-temp/${path.basename(fileName)}.${hash}.mjs`, ) : `${fileName}.${hash}.mjs` + + // Tell Vite Task to ignore this transient file as both input and output, + // so the read-write of this file doesn't affect the cache fingerprints. + ignoreInput(tempFileName) + ignoreOutput(tempFileName) await fsp.writeFile(tempFileName, bundledCode) try { return (await import(pathToFileURL(tempFileName).href)).default diff --git a/packages/vite/src/node/env.ts b/packages/vite/src/node/env.ts index 9ca5d4d29e4a1f..e80c23cd5cfe6f 100644 --- a/packages/vite/src/node/env.ts +++ b/packages/vite/src/node/env.ts @@ -2,6 +2,7 @@ import fs from 'node:fs' import path from 'node:path' // eslint-disable-next-line n/no-unsupported-features/node-builtins -- our supported nodejs range supports `parseEnv` but in experimental state, which is fine import { parseEnv } from 'node:util' +import { getEnvs } from '@voidzero-dev/vite-task-client' import { type DotenvPopulateInput, expand } from 'dotenv-expand' import colors from 'picocolors' import { arraify, createDebugger, normalizePath, tryStatSync } from './utils' @@ -82,6 +83,12 @@ export function loadEnv( } } + // Vite Task may know prefixed envs not present here; fetch them and let + // the runner record each glob in the build's cache key. + for (const prefix of prefixes) { + Object.assign(env, getEnvs(`${prefix}*`)) + } + // check if there are actual env variables starting with VITE_* // these are typically provided inline and should be prioritized for (const key in process.env) { diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 14186ddef51a71..c88de8003208d3 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -3,6 +3,7 @@ import fsp from 'node:fs/promises' import path from 'node:path' import { promisify } from 'node:util' import { performance } from 'node:perf_hooks' +import { ignoreInput, ignoreOutput } from '@voidzero-dev/vite-task-client' import colors from 'picocolors' import { init, parse } from 'es-module-lexer' import { isDynamicPattern } from 'tinyglobby' @@ -397,6 +398,14 @@ export async function loadCachedDepOptimizationMetadata( const depsCacheDir = getDepsCacheDir(environment) + // When run inside Vite Task, the dep optimizer cache is both read and + // written under this directory (metadata + pre-bundled deps). Tell Vite + // Task to treat it as neither a build input nor a build output: the + // lockfile hash stored in the metadata already drives re-optimization, + // and the cache is process-local scratch space, not a build artifact. + ignoreInput(depsCacheDir) + ignoreOutput(depsCacheDir) + if (!force) { let cachedMetadata: DepOptimizationMetadata | undefined try { diff --git a/packages/vite/src/node/plugins/prepareOutDir.ts b/packages/vite/src/node/plugins/prepareOutDir.ts index 6f5f16544cabdc..e41d7a15dda846 100644 --- a/packages/vite/src/node/plugins/prepareOutDir.ts +++ b/packages/vite/src/node/plugins/prepareOutDir.ts @@ -1,5 +1,6 @@ import fs from 'node:fs' import path from 'node:path' +import { ignoreInput } from '@voidzero-dev/vite-task-client' import colors from 'picocolors' import type { Plugin } from '../plugin' import { getResolvedOutDirs, resolveEmptyOutDir } from '../watch' @@ -51,6 +52,11 @@ function prepareOutDir( const { publicDir } = environment.config const outDirsArray = [...outDirs] for (const outDir of outDirs) { + // When run inside Vite Task, `emptyDir` below reads the entries of + // `outDir`. Without this, those reads would be recorded as build inputs + // and mix with the writes that follow, tripping Vite Task's read-write + // overlap check. + ignoreInput(outDir) if (emptyOutDir !== false && fs.existsSync(outDir)) { // skip those other outDirs which are nested in current outDir const skipDirs = outDirsArray diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index 25752ba1c146a8..ac34549420e126 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -4,6 +4,7 @@ import sirv from 'sirv' import compression from '@polka/compression' import connect from 'connect' import corsMiddleware from 'cors' +import { disableCache } from '@voidzero-dev/vite-task-client' import type { Connect } from '#dep-types/connect' import type { HttpServer, @@ -126,6 +127,10 @@ export type PreviewServerHook = ( export async function preview( inlineConfig: InlineConfig = {}, ): Promise { + // The preview server is a long-running, interactive process whose + // responses cannot be replayed from a cache. + disableCache() + const config = await resolveConfig( inlineConfig, 'serve', diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 0ec61e2d4683cd..722c19d2aba421 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -12,6 +12,7 @@ import colors from 'picocolors' import chokidar from 'chokidar' import launchEditorMiddleware from 'launch-editor-middleware' import { determineAgent } from '@vercel/detect-agent' +import { disableCache } from '@voidzero-dev/vite-task-client' import type { SourceMap } from 'rolldown' import type { ModuleRunner } from 'vite/module-runner' import type { FSWatcher, WatchOptions } from '#dep-types/chokidar' @@ -483,6 +484,10 @@ export async function _createServer( previousForceOptimizeOnRestart?: boolean }, ): Promise { + // The dev server is a long-running, interactive process whose outputs + // (network responses, HMR updates) cannot be replayed from a cache. + disableCache() + const config = isResolvedConfig(inlineConfig) ? inlineConfig : await resolveConfig(inlineConfig, 'serve') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51b98504ab8859..adc04d6f734a40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -241,6 +241,9 @@ importers: packages/vite: dependencies: + '@voidzero-dev/vite-task-client': + specifier: ^0.1.1 + version: 0.1.1 lightningcss: specifier: ^1.32.0 version: 1.32.0 @@ -4683,6 +4686,10 @@ packages: '@vitest/utils@4.1.7': resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + '@voidzero-dev/vite-task-client@0.1.1': + resolution: {integrity: sha512-9zGnSzvzUOKNoMf4zxaDeAyerkvnsXBRWfbTkwhwHsVJFug3j48Et8kr+ulHf3KRdcLr07Np+xDuCvHYVK1k7w==} + engines: {node: '>=18'} + '@voidzero-dev/vitepress-theme@4.8.4': resolution: {integrity: sha512-o7R2g9OPu5iLW3R4PNkj+JRSIncO8f1hTY0YvO13OMP/kytKUn8MLhy4kTvx+IMRSLeqrGfrBpze/OEPKzcLUQ==} peerDependencies: @@ -10723,6 +10730,8 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 + '@voidzero-dev/vite-task-client@0.1.1': {} + '@voidzero-dev/vitepress-theme@4.8.4(focus-trap@8.0.1)(vite@packages+vite)(vitepress@2.0.0-alpha.17)(vue@3.5.35)': dependencies: '@docsearch/css': 4.5.4