163 lines
4.6 KiB
TypeScript
163 lines
4.6 KiB
TypeScript
import { useState, useCallback } from "react";
|
|
import { IpcClient } from "@/ipc/ipc_client";
|
|
import {
|
|
appOutputAtom,
|
|
appUrlAtom,
|
|
currentAppAtom,
|
|
previewPanelKeyAtom,
|
|
previewErrorMessageAtom,
|
|
selectedAppIdAtom,
|
|
} from "@/atoms/appAtoms";
|
|
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
|
|
export function useRunApp() {
|
|
const [loading, setLoading] = useState(false);
|
|
const [app, setApp] = useAtom(currentAppAtom);
|
|
const setAppOutput = useSetAtom(appOutputAtom);
|
|
const [appUrlObj, setAppUrlObj] = useAtom(appUrlAtom);
|
|
const setPreviewPanelKey = useSetAtom(previewPanelKeyAtom);
|
|
const appId = useAtomValue(selectedAppIdAtom);
|
|
const setPreviewErrorMessage = useSetAtom(previewErrorMessageAtom);
|
|
const runApp = useCallback(async (appId: number) => {
|
|
setLoading(true);
|
|
try {
|
|
const ipcClient = IpcClient.getInstance();
|
|
console.debug("Running app", appId);
|
|
|
|
// Clear the URL and add restart message
|
|
if (appUrlObj?.appId !== appId) {
|
|
setAppUrlObj({ appUrl: null, appId: null });
|
|
}
|
|
setAppOutput((prev) => [
|
|
...prev,
|
|
{
|
|
message: "Trying to restart app...",
|
|
type: "stdout",
|
|
appId,
|
|
timestamp: Date.now(),
|
|
},
|
|
]);
|
|
const app = await ipcClient.getApp(appId);
|
|
setApp(app);
|
|
await ipcClient.runApp(appId, (output) => {
|
|
setAppOutput((prev) => [...prev, output]);
|
|
// Check if the output contains a localhost URL
|
|
const urlMatch = output.message.match(/(https?:\/\/localhost:\d+\/?)/);
|
|
if (urlMatch) {
|
|
setAppUrlObj({ appUrl: urlMatch[1], appId });
|
|
}
|
|
});
|
|
setPreviewErrorMessage(undefined);
|
|
} catch (error) {
|
|
console.error(`Error running app ${appId}:`, error);
|
|
setPreviewErrorMessage(
|
|
error instanceof Error ? error.message : error?.toString(),
|
|
);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const stopApp = useCallback(async (appId: number) => {
|
|
if (appId === null) {
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
const ipcClient = IpcClient.getInstance();
|
|
await ipcClient.stopApp(appId);
|
|
|
|
setPreviewErrorMessage(undefined);
|
|
} catch (error) {
|
|
console.error(`Error stopping app ${appId}:`, error);
|
|
setPreviewErrorMessage(
|
|
error instanceof Error ? error.message : error?.toString(),
|
|
);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const onHotModuleReload = useCallback(() => {
|
|
setPreviewPanelKey((prevKey) => prevKey + 1);
|
|
}, [setPreviewPanelKey]);
|
|
|
|
const restartApp = useCallback(
|
|
async ({
|
|
removeNodeModules = false,
|
|
}: { removeNodeModules?: boolean } = {}) => {
|
|
if (appId === null) {
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
try {
|
|
const ipcClient = IpcClient.getInstance();
|
|
console.debug(
|
|
"Restarting app",
|
|
appId,
|
|
removeNodeModules ? "with node_modules cleanup" : "",
|
|
);
|
|
|
|
// Clear the URL and add restart message
|
|
setAppUrlObj({ appUrl: null, appId: null });
|
|
setAppOutput((prev) => [
|
|
...prev,
|
|
{
|
|
message: "Restarting app...",
|
|
type: "stdout",
|
|
appId,
|
|
timestamp: Date.now(),
|
|
},
|
|
]);
|
|
|
|
const app = await ipcClient.getApp(appId);
|
|
setApp(app);
|
|
await ipcClient.restartApp(
|
|
appId,
|
|
(output) => {
|
|
setAppOutput((prev) => [...prev, output]);
|
|
if (
|
|
output.message.includes("hmr update") &&
|
|
output.message.includes("[vite]")
|
|
) {
|
|
onHotModuleReload();
|
|
return;
|
|
}
|
|
// Check if the output contains a localhost URL
|
|
const urlMatch = output.message.match(
|
|
/(https?:\/\/localhost:\d+\/?)/,
|
|
);
|
|
if (urlMatch) {
|
|
setAppUrlObj({ appUrl: urlMatch[1], appId });
|
|
}
|
|
},
|
|
removeNodeModules,
|
|
);
|
|
} catch (error) {
|
|
console.error(`Error restarting app ${appId}:`, error);
|
|
setPreviewErrorMessage(
|
|
error instanceof Error ? error.message : error?.toString(),
|
|
);
|
|
} finally {
|
|
setPreviewPanelKey((prevKey) => prevKey + 1);
|
|
setLoading(false);
|
|
}
|
|
},
|
|
[appId, setApp, setAppOutput, setAppUrlObj, setPreviewPanelKey],
|
|
);
|
|
|
|
const refreshAppIframe = useCallback(async () => {
|
|
setPreviewPanelKey((prevKey) => prevKey + 1);
|
|
}, [setPreviewPanelKey]);
|
|
|
|
return {
|
|
loading,
|
|
runApp,
|
|
stopApp,
|
|
restartApp,
|
|
app,
|
|
refreshAppIframe,
|
|
};
|
|
}
|