Skip to content

Commit 1e08de3

Browse files
refactor(cli): delegate build-strategy resolution to the SDK, drop module fallback
resolvePreviewBuildStrategy now forwards directly to the SDK's resolveBuildStrategy: framework detection, per-framework construction, and Bun entrypoint resolution all live in one place. Deletes the CLI's per-framework switch and its createPreviewBuildStrategy. Bun entrypoint resolution is now main-only (or an explicit --entry), everywhere — the deploy path (via the SDK) and the local `app run` path (readBunPackageEntrypoint). Dropping the package.json `module` fallback keeps `run` and `deploy` resolving the same entrypoint, so an app can't run locally but fail to deploy. Tests: framework-detection cases that mocked the SDK strategy classes are removed (detection is the SDK's responsibility and is covered by its own tests); the remaining bun cases use `main` / explicit `--entry`.
1 parent 89be071 commit 1e08de3

4 files changed

Lines changed: 21 additions & 262 deletions

File tree

packages/cli/src/lib/app/bun-project.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import path from "node:path";
33

44
export interface BunPackageJsonLike {
55
main?: unknown;
6-
module?: unknown;
76
packageManager?: unknown;
87
scripts?: unknown;
98
dependencies?: unknown;
@@ -42,15 +41,7 @@ export async function readBunPackageJson(
4241
export function readBunPackageEntrypoint(
4342
packageJson: BunPackageJsonLike | null,
4443
): string | undefined {
45-
if (typeof packageJson?.main === "string") {
46-
return packageJson.main;
47-
}
48-
49-
if (typeof packageJson?.module === "string") {
50-
return packageJson.module;
51-
}
52-
53-
return undefined;
44+
return typeof packageJson?.main === "string" ? packageJson.main : undefined;
5445
}
5546

5647
export async function resolveBunEntrypoint(
@@ -63,7 +54,7 @@ export async function resolveBunEntrypoint(
6354

6455
if (!candidate) {
6556
throw new Error(
66-
"Entrypoint is required. Pass --entry or define package.json main or module.",
57+
"Entrypoint is required. Pass --entry or define package.json main.",
6758
);
6859
}
6960

packages/cli/src/lib/app/preview-build.ts

Lines changed: 11 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@ import { cp, rm, stat } from "node:fs/promises";
22
import path from "node:path";
33

44
import {
5-
AstroBuild,
65
type BuildArtifact,
76
type BuildStrategy,
8-
BunBuild,
9-
NestjsBuild,
10-
NextjsBuild,
11-
NuxtBuild,
127
normalizeArtifactSymlinks,
8+
resolveBuildStrategy,
139
stageStandaloneArtifact,
14-
TanstackStartBuild,
1510
} from "@prisma/compute-sdk";
1611

17-
import { resolveBunEntrypoint } from "./bun-project";
1812
import type { PreviewBuildSettings } from "./preview-build-settings";
1913

2014
export {
@@ -139,99 +133,16 @@ export async function resolvePreviewBuildStrategy(options: {
139133
strategy: BuildStrategy;
140134
buildType: ResolvedPreviewBuildType;
141135
}> {
142-
if (options.buildType !== "auto") {
143-
const strategy = await createPreviewBuildStrategy({
144-
appPath: options.appPath,
145-
entrypoint: options.entrypoint,
146-
buildType: options.buildType,
147-
signal: options.signal,
148-
buildSettings: options.buildSettings,
149-
});
150-
151-
return {
152-
buildType: options.buildType,
153-
strategy,
154-
};
155-
}
156-
157-
for (const buildType of RESOLVED_PREVIEW_BUILD_TYPES) {
158-
// Bun is the fallback because it can build any valid Bun entrypoint.
159-
if (buildType === "bun") continue;
160-
161-
const strategy = await createPreviewBuildStrategy({
162-
appPath: options.appPath,
163-
entrypoint: options.entrypoint,
164-
buildType,
165-
signal: options.signal,
166-
buildSettings: options.buildSettings,
167-
});
168-
169-
if (await strategy.canBuild(options.signal)) {
170-
return {
171-
buildType,
172-
strategy,
173-
};
174-
}
175-
}
176-
177-
return {
178-
buildType: "bun",
179-
strategy: await createPreviewBuildStrategy({
180-
appPath: options.appPath,
181-
entrypoint: options.entrypoint,
182-
buildType: "bun",
183-
signal: options.signal,
184-
buildSettings: options.buildSettings,
185-
}),
186-
};
187-
}
188-
189-
/**
190-
* Constructs the SDK build strategy for a resolved framework. The strategies
191-
* run the framework build (and any `package.json` build script) and stage a
192-
* deployable artifact themselves; the CLI only resolves the Bun entrypoint,
193-
* which supports the `module` field on top of `main`.
194-
*/
195-
async function createPreviewBuildStrategy(options: {
196-
appPath: string;
197-
entrypoint?: string;
198-
buildType: ResolvedPreviewBuildType;
199-
signal?: AbortSignal;
200-
buildSettings?: PreviewBuildSettings;
201-
}): Promise<BuildStrategy> {
202-
switch (options.buildType) {
203-
case "nextjs":
204-
return new NextjsBuild({
205-
appPath: options.appPath,
206-
buildSettings: options.buildSettings,
207-
});
208-
case "nuxt":
209-
return new NuxtBuild({ appPath: options.appPath });
210-
case "astro":
211-
return new AstroBuild({ appPath: options.appPath });
212-
case "nestjs":
213-
return new NestjsBuild({
214-
appPath: options.appPath,
215-
buildSettings: options.buildSettings,
216-
});
217-
case "tanstack-start":
218-
return new TanstackStartBuild({
219-
appPath: options.appPath,
220-
buildSettings: options.buildSettings,
221-
});
222-
case "bun": {
223-
const entrypoint = await resolveBunEntrypoint(
224-
options.appPath,
225-
options.entrypoint,
226-
options.signal,
227-
);
228-
return new BunBuild({
229-
appPath: options.appPath,
230-
entrypoint,
231-
buildSettings: options.buildSettings,
232-
});
233-
}
234-
}
136+
// Detection, per-framework construction, and Bun entrypoint resolution
137+
// (package.json `main`) all live in the SDK now; the CLI forwards. The CLI's
138+
// build types map 1:1 to the SDK's, and `auto` is the SDK default.
139+
return resolveBuildStrategy({
140+
appPath: options.appPath,
141+
buildType: options.buildType,
142+
entrypoint: options.entrypoint,
143+
buildSettings: options.buildSettings,
144+
signal: options.signal,
145+
});
235146
}
236147

237148
/**

packages/cli/tests/app-bun-compat.test.ts

Lines changed: 6 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,8 @@ afterEach(() => {
1111
vi.restoreAllMocks();
1212
});
1313

14-
function mockBuildStrategy(
15-
createInstance: (options: object) => object = () => ({
16-
canBuild: vi.fn(),
17-
execute: vi.fn(),
18-
}),
19-
) {
20-
return vi.fn().mockImplementation(function BuildStrategyMock(
21-
options: object,
22-
) {
23-
return createInstance(options);
24-
});
25-
}
26-
2714
describe("bun compatibility", () => {
28-
it("resolves the Bun entrypoint from package.json module", async () => {
15+
it("does not fall back to package.json module for the Bun entrypoint", async () => {
2916
const cwd = await createTempCwd();
3017

3118
await writeFile(
@@ -50,8 +37,8 @@ describe("bun compatibility", () => {
5037

5138
const { resolveBunEntrypoint } = await import("../src/lib/app/bun-project");
5239

53-
await expect(resolveBunEntrypoint(cwd, undefined)).resolves.toBe(
54-
"index.ts",
40+
await expect(resolveBunEntrypoint(cwd, undefined)).rejects.toThrow(
41+
"Entrypoint is required. Pass --entry or define package.json main.",
5542
);
5643
});
5744

@@ -68,14 +55,14 @@ describe("bun compatibility", () => {
6855
);
6956
});
7057

71-
it("detects a Bun project when package.json uses module instead of main", async () => {
58+
it("detects a Bun project from package.json main and a bun dev script", async () => {
7259
const cwd = await createTempCwd();
7360

7461
await writeFile(
7562
path.join(cwd, "package.json"),
7663
JSON.stringify(
7764
{
78-
module: "index.ts",
65+
main: "index.ts",
7966
devDependencies: {
8067
"@types/bun": "latest",
8168
},
@@ -99,139 +86,9 @@ describe("bun compatibility", () => {
9986
await expect(detectLocalBuildType(cwd)).resolves.toBe("bun");
10087
});
10188

102-
it("passes the module-based Bun entrypoint into the shared deploy/build strategy", async () => {
89+
it("forwards explicit build types to the SDK strategy resolver", async () => {
10390
const cwd = await createTempCwd();
10491

105-
await writeFile(
106-
path.join(cwd, "package.json"),
107-
JSON.stringify(
108-
{
109-
module: "index.ts",
110-
devDependencies: {
111-
"@types/bun": "latest",
112-
},
113-
},
114-
null,
115-
2,
116-
),
117-
"utf8",
118-
);
119-
await writeFile(
120-
path.join(cwd, "index.ts"),
121-
"console.log('hello');\n",
122-
"utf8",
123-
);
124-
125-
const bunBuild = mockBuildStrategy((options: object) => ({
126-
options,
127-
canBuild: vi.fn().mockResolvedValue(true),
128-
execute: vi.fn(),
129-
}));
130-
const nextjsBuild = mockBuildStrategy(() => ({
131-
canBuild: vi.fn().mockResolvedValue(false),
132-
execute: vi.fn(),
133-
}));
134-
const otherFrameworkBuild = mockBuildStrategy(() => ({
135-
canBuild: vi.fn().mockResolvedValue(false),
136-
execute: vi.fn(),
137-
}));
138-
139-
vi.doMock("@prisma/compute-sdk", async (importOriginal) => ({
140-
...(await importOriginal<typeof import("@prisma/compute-sdk")>()),
141-
AstroBuild: otherFrameworkBuild,
142-
BunBuild: bunBuild,
143-
NextjsBuild: nextjsBuild,
144-
NuxtBuild: otherFrameworkBuild,
145-
NestjsBuild: otherFrameworkBuild,
146-
TanstackStartBuild: otherFrameworkBuild,
147-
}));
148-
149-
const { resolvePreviewBuildStrategy } = await import(
150-
"../src/lib/app/preview-build"
151-
);
152-
153-
const result = await resolvePreviewBuildStrategy({
154-
appPath: cwd,
155-
buildType: "auto",
156-
entrypoint: undefined,
157-
});
158-
159-
expect(result.buildType).toBe("bun");
160-
expect(bunBuild).toHaveBeenCalledWith({
161-
appPath: cwd,
162-
entrypoint: "index.ts",
163-
});
164-
});
165-
166-
it("auto-detects SDK framework strategies before falling back to Bun", async () => {
167-
const cwd = await createTempCwd();
168-
169-
const bunBuild = mockBuildStrategy(() => ({
170-
canBuild: vi.fn().mockResolvedValue(true),
171-
execute: vi.fn(),
172-
}));
173-
const nextjsBuild = mockBuildStrategy(() => ({
174-
canBuild: vi.fn().mockResolvedValue(false),
175-
execute: vi.fn(),
176-
}));
177-
const nuxtBuild = mockBuildStrategy(() => ({
178-
canBuild: vi.fn().mockResolvedValue(true),
179-
execute: vi.fn(),
180-
}));
181-
const astroBuild = mockBuildStrategy(() => ({
182-
canBuild: vi.fn().mockResolvedValue(true),
183-
execute: vi.fn(),
184-
}));
185-
const tanstackStartBuild = mockBuildStrategy(() => ({
186-
canBuild: vi.fn().mockResolvedValue(true),
187-
execute: vi.fn(),
188-
}));
189-
190-
vi.doMock("@prisma/compute-sdk", async (importOriginal) => ({
191-
...(await importOriginal<typeof import("@prisma/compute-sdk")>()),
192-
AstroBuild: astroBuild,
193-
BunBuild: bunBuild,
194-
NextjsBuild: nextjsBuild,
195-
NuxtBuild: nuxtBuild,
196-
NestjsBuild: nextjsBuild,
197-
TanstackStartBuild: tanstackStartBuild,
198-
}));
199-
200-
const { resolvePreviewBuildStrategy } = await import(
201-
"../src/lib/app/preview-build"
202-
);
203-
204-
const result = await resolvePreviewBuildStrategy({
205-
appPath: cwd,
206-
buildType: "auto",
207-
entrypoint: undefined,
208-
});
209-
210-
expect(result.buildType).toBe("nuxt");
211-
expect(nuxtBuild).toHaveBeenCalledWith({ appPath: cwd });
212-
expect(bunBuild).not.toHaveBeenCalled();
213-
expect(astroBuild).not.toHaveBeenCalled();
214-
expect(tanstackStartBuild).not.toHaveBeenCalled();
215-
});
216-
217-
it("resolves explicit SDK framework build strategies", async () => {
218-
const cwd = await createTempCwd();
219-
220-
const buildStrategy = mockBuildStrategy(() => ({
221-
canBuild: vi.fn(),
222-
execute: vi.fn(),
223-
}));
224-
225-
vi.doMock("@prisma/compute-sdk", async (importOriginal) => ({
226-
...(await importOriginal<typeof import("@prisma/compute-sdk")>()),
227-
AstroBuild: buildStrategy,
228-
BunBuild: buildStrategy,
229-
NextjsBuild: buildStrategy,
230-
NuxtBuild: buildStrategy,
231-
NestjsBuild: buildStrategy,
232-
TanstackStartBuild: buildStrategy,
233-
}));
234-
23592
const { resolvePreviewBuildStrategy } = await import(
23693
"../src/lib/app/preview-build"
23794
);

packages/cli/tests/app-controller.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,8 +2290,8 @@ describe("app controller", () => {
22902290
expectedBuildType: "bun",
22912291
},
22922292
{
2293-
name: "Bun from --framework bun with package.json module",
2294-
packageJson: { module: "index.ts" },
2293+
name: "Bun from --framework bun with package.json main",
2294+
packageJson: { main: "index.ts" },
22952295
framework: "bun",
22962296
expectedEntrypoint: "index.ts",
22972297
expectedBuildType: "bun",

0 commit comments

Comments
 (0)