| 1 | import * as Effect from "effect/Effect"; |
| 2 | import * as FileSystem from "effect/FileSystem"; |
| 3 | import * as Stdio from "effect/Stdio"; |
| 4 | import * as Stream from "effect/Stream"; |
| 5 | import * as NodeV8 from "node:v8"; |
| 6 | import { PlatformServices, runMain } from "../../Util/PlatformServices.ts"; |
| 7 | import { viteBuildInProcess } from "./Sources/Vite.ts"; |
| 8 | import 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 | |
| 28 | const 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 | |
| 34 | const 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. |
| 60 | runMain(program.pipe(Effect.provide(PlatformServices)), { |
| 61 | disableErrorReporting: true, |
| 62 | }); |