From b7dad2db9a559b4ec93805aee133b708242b859b Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:52:28 -0700 Subject: [PATCH] push files to container --- src/components/Editor.tsx | 50 ++++++++++++++++++++++++---------- src/contexts/WorkplaceState.ts | 21 ++++++++++++++ src/webcontainer.ts | 6 ++-- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 3202279a..5b5ffdc2 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -16,6 +16,8 @@ import { getActorAliases, WorkerContext, WorkplaceDispatchContext, + ContainerContext, + convertNonMotokoFilesToWebContainer, } from "../contexts/WorkplaceState"; import { compileCandid } from "../build"; import { didToJs } from "../config/actor"; @@ -99,21 +101,23 @@ export function Editor({ }) { const worker = useContext(WorkerContext); const dispatch = useContext(WorkplaceDispatchContext); + const container = useContext(ContainerContext); const [formatted, setFormatted] = useState(false); const fileName = state.selectedFile; + const fileExtension = fileName?.split(".").pop() ?? ""; const fileCode = fileName ? state.files[fileName] : ""; - // TODO - const mainFile = fileName.endsWith(".mo") - ? fileName - : state.files["Main.mo"] - ? "Main.mo" - : ""; + const mainFile = + fileExtension === "mo" ? fileName : state.files["Main.mo"] ? "Main.mo" : ""; + const selectFrontend = + "package.json" in state.files && + fileExtension !== "mo" && + fileExtension !== "md"; const monaco = useMonaco(); const checkFileAddMarkers = async () => { - if (!fileName || !fileName.endsWith("mo")) return; + if (!fileName || fileExtension !== "mo") return; const check = await worker.Moc({ type: "check", file: fileName }); const diags = check.diagnostics; setMarkers( @@ -137,7 +141,7 @@ export function Editor({ contents: newValue, }, }); - if (!fileName.endsWith("mo")) return; + if (fileExtension !== "mo") return; await worker.Moc({ type: "save", file: fileName, content: newValue }); await checkFileAddMarkers(); }; @@ -169,11 +173,23 @@ export function Editor({ editorRef.current?.getAction("editor.action.formatDocument").run(); }; const deployClick = async () => { + if (selectFrontend) { + const files = convertNonMotokoFilesToWebContainer(state); + console.log(files); + await container.container!.fs.mkdir("user", { recursive: true }); + await container.container!.mount(files, { mountPoint: "user" }); + await container.run_cmd("npm", ["install"], { cwd: "user" }); + await container.run_cmd("npm", ["run", "build"], { cwd: "user" }); + const read = await container.container!.fs.readdir("/"); + console.log(read); + return; + } const aliases = getActorAliases(state.canisters); await worker.saveWorkplaceToMotoko(state.files); await worker.Moc({ type: "setActorAliases", list: aliases }); if (!mainFile) { logger.log("Select a main entry file to deploy"); + return; } const candid = await compileCandid(worker, mainFile, logger); if (candid) { @@ -200,7 +216,7 @@ export function Editor({ Editor - {!!fileName.endsWith(".mo") && ( + {fileExtension === "mo" && ( <> {!!formatted && ( @@ -226,19 +242,25 @@ export function Editor({ small > Rabbit icon -

{isDeploying ? "Deploying..." : "Deploy"}

+

+ {isDeploying + ? "Deploying..." + : selectFrontend + ? "Deploy Frontend" + : "Deploy Backend"} +

- + - {fileName.endsWith(".md") ? fileCode : ""} + {fileExtension === "md" ? fileCode : ""} - + !path.endsWith(".mo")) + .reduce((acc, [path, content]) => { + const parts = path.split("/"); + let current = acc; + for (let i = 0; i < parts.length - 1; i++) { + if (!current[parts[i]]) { + current[parts[i]] = { directory: {} }; + } + current = current[parts[i]].directory; + } + current[parts[parts.length - 1]] = { + file: { + contents: content, + }, + }; + return acc; + }, {}); + return files; +} export type WorkplaceReducerAction = /** diff --git a/src/webcontainer.ts b/src/webcontainer.ts index 888f215d..74ec0ce2 100644 --- a/src/webcontainer.ts +++ b/src/webcontainer.ts @@ -1,4 +1,4 @@ -import { WebContainer, FileSystemTree } from "@webcontainer/api"; +import { WebContainer, FileSystemTree, SpawnOptions } from "@webcontainer/api"; import { Terminal } from "@xterm/xterm"; export class Container { @@ -52,10 +52,10 @@ export class Container { await this.container!.mount(files); } - async run_cmd(cmd: string, args: string[]) { + async run_cmd(cmd: string, args: string[], options?: SpawnOptions) { await this.init(); this.terminal.writeln(`$ ${cmd} ${args.join(" ")}`); - const installProcess = await this.container!.spawn(cmd, args); + const installProcess = await this.container!.spawn(cmd, args, options); installProcess.output.pipeTo( new WritableStream({ write: (data) => {