src/installers/rpc.ts 2.7 K raw
1
import path from "node:path";
2
import { consola } from "consola";
3
import { execa } from "execa";
4
import fs from "fs-extra";
5
import pc from "picocolors";
6
import yoctoSpinner from "yocto-spinner";
7
import type { ProjectOptions } from "@/types";
8
import { EXTRAS_DIR } from "@/utils";
9
import { nameGenerator } from "@/utils/name-generator";
10
import { honoClientTemplate, honoRpcTemplate } from "@/utils/templates";
11
12
export async function rpcInstaller(
13
	options: Required<ProjectOptions>,
14
): Promise<boolean> {
15
	const spinner = yoctoSpinner({ text: "Setting up RPC client..." }).start();
16
17
	try {
18
		const { projectName, rpc, shadcn, tailwind } = options;
19
		const projectPath = path.resolve(process.cwd(), projectName);
20
21
		// 1. Update client package.json to ensure hono client is installed
22
		const clientPkgPath = path.join(projectPath, "client", "package.json");
23
		const clientPkg = await fs.readJson(clientPkgPath);
24
25
		if (!clientPkg.dependencies.hono) {
26
			await execa("bun", ["install", "hono"], { cwd: projectPath });
27
		}
28
29
		await fs.writeJson(clientPkgPath, clientPkg, { spaces: 2 });
30
31
		// 2. Update server package.json dev script for RPC
32
		const serverPkgPath = path.join(projectPath, "server", "package.json");
33
		const serverPkg = await fs.readJson(serverPkgPath);
34
35
		// Update the dev script to include parallel TypeScript compilation
36
		serverPkg.scripts.dev = "bun --watch run src/index.ts & tsc --watch";
37
38
		// Add exports mapping for server/client subpath
39
		serverPkg.exports = {
40
			...serverPkg.exports,
41
			"./client": {
42
				types: "./dist/client.d.ts",
43
				default: "./dist/client.js",
44
			},
45
		};
46
47
		await fs.writeJson(serverPkgPath, serverPkg, { spaces: 2 });
48
49
		// 3. Server modification for RPC export type (no client imports)
50
		const serverIndexPath = path.join(projectPath, "server", "src", "index.ts");
51
		await fs.writeFile(serverIndexPath, honoRpcTemplate, "utf8");
52
53
		// 4. Create separate client helper file
54
		const clientHelperPath = path.join(
55
			projectPath,
56
			"server",
57
			"src",
58
			"client.ts",
59
		);
60
		await fs.writeFile(clientHelperPath, honoClientTemplate, "utf8");
61
62
		// 5. Update App.tsx based on template selection using switch statement
63
		const appTsxSrc = path.join(
64
			EXTRAS_DIR,
65
			"client",
66
			"src",
67
			"App.tsx",
68
			nameGenerator("App.tsx", { tailwind, shadcn, rpc }),
69
		);
70
		const appTsxTarget = path.join(projectPath, "client", "src", "App.tsx");
71
72
		fs.copySync(appTsxSrc, appTsxTarget);
73
		spinner.success("RPC client setup completed");
74
		return true;
75
	} catch (err: unknown) {
76
		spinner.error("Failed to set up RPC client");
77
		if (err instanceof Error) {
78
			consola.error(pc.red("Error:"), err.message);
79
		} else {
80
			consola.error(pc.red("Error: Unknown error"));
81
		}
82
		return false;
83
	}
84
}