1import * as Effect from "effect/Effect";
2import * as FileSystem from "effect/FileSystem";
3import * as Stdio from "effect/Stdio";
4import * as Stream from "effect/Stream";
5import * as NodeV8 from "node:v8";
6import { PlatformServices, runMain } from "../../Util/PlatformServices.ts";
7import { viteBuildInProcess } from "./Sources/Vite.ts";
8import type {
9 ViteBuildChildConfig,
10 ViteBuildChildResult,
11} from "./ViteChild.shared.ts";
12
13/**
14 * Entry point of the one-shot Vite *build* child spawned by
15 * `runViteBuildChild` (`ViteChild.ts`), with the project root as its
16 * working directory. Running the build out of process is the isolation
17 * boundary: vite resolves a relative root against live `process.cwd()`,
18 * plugins read cwd freely, and the build's own spawns (via cross-spawn)
19 * `process.chdir` the hosting process transiently — none of which is safe
20 * inside the concurrent engine/test process.
21 *
22 * Protocol: V8-serialized {@link ViteBuildChildConfig} on stdin; the child
23 * writes the V8-serialized {@link ViteBuildChildResult} to
24 * `config.outputPath` and exits 0. Build logs stream over stdout/stderr;
25 * a failed build exits non-zero with the error on stderr.
26 */
27
28const readConfig = Effect.gen(function* () {
29 const stdio = yield* Stdio.Stdio;
30 const chunks = yield* Stream.runCollect(stdio.stdin);
31 return NodeV8.deserialize(Buffer.concat(chunks)) as ViteBuildChildConfig;
32});
33
34const program = Effect.gen(function* () {
35 const config = yield* readConfig;
36 const fs = yield* FileSystem.FileSystem;
37 const { clientDirectory, base, serverBundle, externalWorkspaces } =
38 yield* viteBuildInProcess(config.rootDir, config.env, {
39 main: config.main,
40 compatibilityDate: config.compatibilityDate,
41 compatibilityFlags: config.compatibilityFlags,
42 viteEnvironments: config.viteEnvironments,
43 });
44 const [bundle, workspaces] = yield* Effect.all([
45 serverBundle,
46 externalWorkspaces,
47 ]);
48 const result: ViteBuildChildResult = {
49 clientDirectory,
50 base,
51 serverBundle: bundle,
52 externalWorkspaces: Array.from(workspaces),
53 };
54 yield* fs.writeFile(config.outputPath, NodeV8.serialize(result));
55});
56
57// The parent streams this child's output and turns its exit code into the
58// resource-scoped build error. Do not print a second Effect failure report
59// (the extra `✖` block) from the child itself.
60runMain(program.pipe(Effect.provide(PlatformServices)), {
61 disableErrorReporting: true,
62});