feat: allow custom install and start commands (#892)
# Description Gives the ability to define an `install` and `startup` command when importing a project, so we can work on a project locally without any issue. # Preview <img width="2256" height="1422" alt="image" src="https://github.com/user-attachments/assets/2132b1cb-5f71-4b88-84db-8ecc81cf1f66" /> --------- Co-authored-by: Will Chen <willchen90@gmail.com>
This commit is contained in:
@@ -83,17 +83,28 @@ async function executeApp({
|
||||
appId,
|
||||
event, // Keep event for local-node case
|
||||
isNeon,
|
||||
installCommand,
|
||||
startCommand,
|
||||
}: {
|
||||
appPath: string;
|
||||
appId: number;
|
||||
event: Electron.IpcMainInvokeEvent;
|
||||
isNeon: boolean;
|
||||
installCommand?: string | null;
|
||||
startCommand?: string | null;
|
||||
}): Promise<void> {
|
||||
if (proxyWorker) {
|
||||
proxyWorker.terminate();
|
||||
proxyWorker = null;
|
||||
}
|
||||
await executeAppLocalNode({ appPath, appId, event, isNeon });
|
||||
await executeAppLocalNode({
|
||||
appPath,
|
||||
appId,
|
||||
event,
|
||||
isNeon,
|
||||
installCommand,
|
||||
startCommand,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeAppLocalNode({
|
||||
@@ -101,22 +112,28 @@ async function executeAppLocalNode({
|
||||
appId,
|
||||
event,
|
||||
isNeon,
|
||||
installCommand,
|
||||
startCommand,
|
||||
}: {
|
||||
appPath: string;
|
||||
appId: number;
|
||||
event: Electron.IpcMainInvokeEvent;
|
||||
isNeon: boolean;
|
||||
installCommand?: string | null;
|
||||
startCommand?: string | null;
|
||||
}): Promise<void> {
|
||||
const spawnedProcess = spawn(
|
||||
"(pnpm install && pnpm run dev --port 32100) || (npm install --legacy-peer-deps && npm run dev -- --port 32100)",
|
||||
[],
|
||||
{
|
||||
cwd: appPath,
|
||||
shell: true,
|
||||
stdio: "pipe", // Ensure stdio is piped so we can capture output/errors and detect close
|
||||
detached: false, // Ensure child process is attached to the main process lifecycle unless explicitly backgrounded
|
||||
},
|
||||
);
|
||||
const defaultCommand =
|
||||
"(pnpm install && pnpm run dev --port 32100) || (npm install --legacy-peer-deps && npm run dev -- --port 32100)";
|
||||
const hasCustomCommands = !!installCommand?.trim() && !!startCommand?.trim();
|
||||
const command = hasCustomCommands
|
||||
? `${installCommand!.trim()} && ${startCommand!.trim()}`
|
||||
: defaultCommand;
|
||||
const spawnedProcess = spawn(command, [], {
|
||||
cwd: appPath,
|
||||
shell: true,
|
||||
stdio: "pipe", // Ensure stdio is piped so we can capture output/errors and detect close
|
||||
detached: false, // Ensure child process is attached to the main process lifecycle unless explicitly backgrounded
|
||||
});
|
||||
|
||||
// Check if process spawned correctly
|
||||
if (!spawnedProcess.pid) {
|
||||
@@ -375,6 +392,8 @@ export function registerAppHandlers() {
|
||||
supabaseProjectId: null,
|
||||
githubOrg: null,
|
||||
githubRepo: null,
|
||||
installCommand: originalApp.installCommand,
|
||||
startCommand: originalApp.startCommand,
|
||||
})
|
||||
.returning();
|
||||
|
||||
@@ -511,6 +530,8 @@ export function registerAppHandlers() {
|
||||
appId,
|
||||
event,
|
||||
isNeon: !!app.neonProjectId,
|
||||
installCommand: app.installCommand,
|
||||
startCommand: app.startCommand,
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -646,6 +667,8 @@ export function registerAppHandlers() {
|
||||
appId,
|
||||
event,
|
||||
isNeon: !!app.neonProjectId,
|
||||
installCommand: app.installCommand,
|
||||
startCommand: app.startCommand,
|
||||
}); // This will handle starting either mode
|
||||
|
||||
return;
|
||||
|
||||
@@ -69,7 +69,12 @@ export function registerImportHandlers() {
|
||||
"import-app",
|
||||
async (
|
||||
_,
|
||||
{ path: sourcePath, appName }: ImportAppParams,
|
||||
{
|
||||
path: sourcePath,
|
||||
appName,
|
||||
installCommand,
|
||||
startCommand,
|
||||
}: ImportAppParams,
|
||||
): Promise<ImportAppResult> => {
|
||||
// Validate the source path exists
|
||||
try {
|
||||
@@ -128,6 +133,8 @@ export function registerImportHandlers() {
|
||||
name: appName,
|
||||
// Use the name as the path for now
|
||||
path: appName,
|
||||
installCommand: installCommand ?? null,
|
||||
startCommand: startCommand ?? null,
|
||||
})
|
||||
.returning();
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ export interface App {
|
||||
vercelProjectName: string | null;
|
||||
vercelTeamSlug: string | null;
|
||||
vercelDeploymentUrl: string | null;
|
||||
installCommand: string | null;
|
||||
startCommand: string | null;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
@@ -226,6 +228,8 @@ export interface ApproveProposalResult {
|
||||
export interface ImportAppParams {
|
||||
path: string;
|
||||
appName: string;
|
||||
installCommand?: string;
|
||||
startCommand?: string;
|
||||
}
|
||||
|
||||
export interface CopyAppParams {
|
||||
|
||||
Reference in New Issue
Block a user