Skip to content

Commit 02e82d0

Browse files
Copilottheoephraim
andauthored
fix: resolve env files from project root in monorepo Vitest workspaces (#542)
* Initial plan * fix: resolve env files from project root in monorepo vitest workspaces When running Vitest from a monorepo root using the `projects` config, varlock now correctly uses each child project's root directory (from Vite's config.root) to find .env.schema and .env files, instead of only looking in process.cwd() (the monorepo root). Changes: - execSyncVarlock: forward `cwd` option to execSync calls and fallback walk-up - vite integration: reloadConfig accepts optional `cwd` parameter - vite plugin config hook: detect project root from config.root and reload with correct cwd when it differs from process.cwd() Agent-Logs-Url: https://github.com/dmno-dev/varlock/sessions/f2ed5ca5-a4f7-4db0-9f9e-10c8807a76cc Co-authored-by: theoephraim <1158956+theoephraim@users.noreply.github.com> * fix: address review feedback - remove unnecessary toString, use path.relative for comparison Agent-Logs-Url: https://github.com/dmno-dev/varlock/sessions/f2ed5ca5-a4f7-4db0-9f9e-10c8807a76cc Co-authored-by: theoephraim <1158956+theoephraim@users.noreply.github.com> * fix: always reload with project root when it differs from cwd When config.root differs from process.cwd(), always reload varlock from the project root — even if the initial module-level load succeeded. This handles monorepo setups where the root also has env files, which would cause the initial load to succeed with the wrong project's config. Agent-Logs-Url: https://github.com/dmno-dev/varlock/sessions/eb9ac880-b592-41ee-9d3d-4b1859e8d3cf Co-authored-by: theoephraim <1158956+theoephraim@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: theoephraim <1158956+theoephraim@users.noreply.github.com>
1 parent 0ea6641 commit 02e82d0

3 files changed

Lines changed: 33 additions & 6 deletions

File tree

.changeset/fix-monorepo-vitest.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"varlock": patch
3+
"@varlock/vite-integration": patch
4+
---
5+
6+
Fix Vitest workspace projects in monorepos: when running Vitest from the monorepo root using the `projects` config, varlock now correctly resolves `.env.schema` and `.env` files from each child package's directory instead of only looking in the monorepo root.

packages/integrations/vite/src/index.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ function resetStaticReplacements() {
5454

5555

5656
let loadCount = 0;
57-
function reloadConfig() {
58-
debug('loading config - count =', ++loadCount);
57+
function reloadConfig(cwd?: string) {
58+
debug('loading config - count =', ++loadCount, cwd ? `(cwd: ${cwd})` : '');
5959
try {
6060
const execResult = execSyncVarlock('load --format json-full --compact', {
6161
env: originalProcessEnv,
62+
...(cwd && { cwd }),
6263
});
6364
process.env.__VARLOCK_ENV = execResult;
6465
varlockLoadedEnv = JSON.parse(process.env.__VARLOCK_ENV) as SerializedEnvGraph;
@@ -140,11 +141,28 @@ See https://varlock.dev/integrations/vite/ for more details.
140141

141142
isDevCommand = env.command === 'serve';
142143

143-
// this gets re-triggered after .env file updates
144-
// TODO: be smarter about only reloading if the env files changed?
145-
if (isFirstLoad) {
144+
// Determine the project root for the current Vite/Vitest project.
145+
// In monorepo setups with Vitest workspace projects, config.root
146+
// points to the child package directory rather than the monorepo root
147+
// where process.cwd() points. We need to reload varlock from the
148+
// correct directory so it can find .env.schema and .env files.
149+
const projectRoot = config.root ? path.resolve(config.root) : undefined;
150+
const rootDiffersFromCwd = !!(projectRoot && path.relative(projectRoot, process.cwd()) !== '');
151+
152+
if (rootDiffersFromCwd) {
153+
// Always reload with the correct project root when it differs from
154+
// cwd. This handles monorepo Vitest workspace setups where each child
155+
// project has its own env files — even if the monorepo root also has
156+
// env files (which would cause the initial module-level load to
157+
// succeed with the wrong project's config).
158+
reloadConfig(projectRoot);
159+
} else if (isFirstLoad) {
146160
isFirstLoad = false;
161+
// Roots match — the module-level reloadConfig() already loaded from
162+
// the correct directory, no need to reload.
147163
} else if (isDevCommand) {
164+
// Dev mode re-trigger (e.g., after .env file updates)
165+
// TODO: be smarter about only reloading if the env files changed?
148166
reloadConfig();
149167
}
150168

packages/varlock/src/lib/exec-sync-varlock.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export function execSyncVarlock(
6262
try {
6363
const result = execSync(`varlock ${command}`, {
6464
...opts?.env && { env: opts.env },
65+
...opts?.cwd && { cwd: opts.cwd },
6566
stdio: 'pipe',
6667
});
6768
return result.toString();
@@ -73,11 +74,13 @@ export function execSyncVarlock(
7374

7475
// if varlock was not found, it either means it is not installed
7576
// or we must find the path to node_modules/.bin ourselves.
76-
// Search from callerDir first (if provided), then from process.cwd().
77+
// Search from cwd (if provided), callerDir, then process.cwd().
7778
// This handles monorepo setups where cwd may be an unrelated workspace
7879
// root while varlock is only installed in a sub-package - the callerDir
7980
// supplied by auto-load.ts points inside that sub-package's node_modules.
81+
const cwdStr = opts?.cwd ? String(opts.cwd) : undefined;
8082
const searchDirs = [
83+
...(cwdStr ? [cwdStr] : []),
8184
...(opts?.callerDir ? [opts.callerDir] : []),
8285
process.cwd(),
8386
];

0 commit comments

Comments
 (0)