fix(serve): honor build.outDir from vite.config.ts#703
Open
YevheniiKotyrlo wants to merge 1 commit into
Open
Conversation
6ea7422 to
39bdca0
Compare
`one serve` was resolving outDir from CLI args only, falling through to
the literal 'dist' string when no --outDir flag was passed. Projects
that set a custom `build.outDir` in vite.config.ts (e.g. 'build-out')
would build correctly via `one build` — which loads the vite config and
already respects `build.outDir` at cli/build.ts:370 — but `one serve`
would then crash with ENOENT looking for `./dist/buildInfo.json`
instead of `./build-out/buildInfo.json`.
Layer the resolution chain in serve.ts:startWorker to match the build
command:
1. --outDir CLI flag (highest precedence)
2. cwd has buildInfo.json — preserves the "cd into output dir then
run" UX even when vite.config sets a non-default outDir
3. vite.config's build.outDir — read via a new
`loadViteBuildOutDir()` helper in `vite/loadConfig.ts`
4. 'dist' fallback
Step 3 uses Vite's own `loadConfigFromFile` directly rather than the
existing `loadUserOneOptions` wrapper. The wrapper calls
`getUserOneOptions()` which throws when `globalThis.__oneOptions` is
unset, and the One plugin only sets that on the metro-CLI path
(`if (process.env.IS_VXRN_CLI)`). On the vxrn-as-vite-plugin path
(`bundler: 'vite'` in one()) the throw fires every time, the catch
swallows it, and the fallback to 'dist' happens — i.e., the wrapper
silently does nothing for projects that use Vite-native bundling.
The new helper bypasses that by calling `loadConfigFromFile` directly
and reading `loaded.config.build.outDir` from the resolved config —
no `__oneOptions` handshake needed.
The vite.config load is wrapped in try/catch so deploy bundles that
ship only `dist/` (without a vite.config.ts) keep working.
Includes a vitest unit test for `loadViteBuildOutDir` with two
fixtures (with-outdir / without-outdir) covering both branches.
The helper accepts an optional `configRoot` argument so tests can
target a fixture directory without `chdir`-ing the worker.
Validated end-to-end on Windows MSVC + Bun 1.3.13:
- vite.config has `build: { outDir: 'build-out' }`, no dist/, no
--outDir flag → patched serve resolves to 'build-out',
`curl http://localhost:3000/` returns HTTP 200.
- Same setup with the unpatched serve.mjs → ENOENT for
`dist\buildInfo.json` (reproduces the issue).
- --outDir flag override path: server starts on resolved outDir.
- cwd-has-buildInfo path: server starts using cwd as outDir.
- default fallback: resolves to 'dist' as before this PR.
39bdca0 to
9395993
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #701.
one servenow honorsbuild.outDirfromvite.config.ts, matching whatone buildalready does atpackages/one/src/cli/build.ts:370.Problem
packages/one/src/serve.ts:194-195resolvedoutDirfrom CLI args only:The vite config's
build.outDirwas never consulted, so projects with a non-default outDir had to pass--outDir <dir>explicitly to everyone serveinvocation.Fix
Layer the resolution to match the build command:
--outDirCLI flag (highest precedence)buildInfo.json→'.'— preserves the "cd into output dir then run" UX even when vite.config sets a non-default outDirvite.config'sbuild.outDir, read via a newloadViteBuildOutDir()helper inpackages/one/src/vite/loadConfig.ts'dist'fallbackWhy a new helper instead of reusing
loadUserOneOptionsThe first cut of this PR called the existing
loadUserOneOptions('serve', true)wrapper. That throws viagetUserOneOptionswhenglobalThis.__oneOptionsis unset, and the One plugin only sets__oneOptionson the metro-CLI path (if (process.env.IS_VXRN_CLI)). On the vxrn-as-vite-plugin path (bundler: 'vite'inone()options) the throw fired every time, the catch swallowed it, and the resolution silently fell through to'dist'— i.e., the first cut was a no-op for Vite-native projects.The new
loadViteBuildOutDir()calls Vite's ownloadConfigFromFiledirectly, readsloaded.config.build.outDir, and never touches__oneOptions. Works for both bundler modes.The vite.config load is wrapped in
try/catchso deploy bundles that ship onlydist/(withoutvite.config.ts) keep working.Test plan
Validated end-to-end on Windows MSVC + Bun 1.3.13 against the
curex/onedownstream consumer:bunx tsc --noEmitclean.loadViteBuildOutDirwith two fixtures (with-outdirreturning'build-out';without-outdirreturningundefined). Passes 2/2 in 220ms.build: { outDir: 'build-out' }, nodist/, no--outDir: patchedserve.mjsstarted on port 3000,curl http://localhost:3000/returned HTTP 200. Resolution went through the new vite-config path.serve.mjs: failed withENOENT: no such file or directory, open 'C:\…\dist\buildInfo.json'— the exact reported bug. Confirms the fix is load-bearing.--outDir build-outflag wins (highest precedence): server starts on resolved outDir; verified by curl returning 200.cd build-out && one serveUX preserved: server starts via the cwd-buildInfo.jsonbranch.'dist'correctly (verified by ENOENT against./dist/buildInfo.jsonwhen dist/ is empty — the resolution chain reached the default as designed).Notes
cli/build.ts:370(viteLoadedConfig?.config?.build?.outDir ?? 'dist') — same field path, but resolved without theloadUserOneOptionswrapper for the Vite-native compatibility reason above.