diff --git a/cli/bin.ts b/cli/bin.ts index 08c21d19..903447a2 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -10,6 +10,7 @@ import dotenv from "dotenv"; import fs from "fs"; import { checkForUpdate } from "./update"; import { login, logout } from "./auth"; +import { startFlutterDaemonServer } from "./flutter/daemon"; function loadenv(argv) { const { cwd } = argv; @@ -113,6 +114,17 @@ export default async function cli() { }, [loadenv] ) + .command( + "flutter daemon start", + "Starts local flutter daemon server for grida services", + () => {}, + () => { + startFlutterDaemonServer(); + } + ) + .option("port", { + requiresArg: false, + }) .option("figma-personal-access-token", { description: "figma personal access token", alias: ["fpat", "figma-pat"], diff --git a/cli/flutter/daemon/index.ts b/cli/flutter/daemon/index.ts new file mode 100644 index 00000000..713ab563 --- /dev/null +++ b/cli/flutter/daemon/index.ts @@ -0,0 +1,6 @@ +import Daemon from "@flutter-daemon/server"; + +export function startFlutterDaemonServer() { + const server = new Daemon(); + server.listen({}); +} diff --git a/cli/flutter/index.ts b/cli/flutter/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/cli/package.json b/cli/package.json index 3c858aae..08d62ea1 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.13", + "version": "0.0.14", "private": false, "license": "Apache-2.0", "description": "grida CLI", @@ -8,6 +8,7 @@ "repository": "https://github.com/gridaco/code", "dependencies": { "@base-sdk-fp/auth": "^0.1.4", + "@flutter-daemon/server": "^0.0.1", "dotenv": "^16.0.1", "enquirer": "^2.3.6", "glob": "^8.0.3", @@ -18,7 +19,6 @@ "open": "^8.4.0", "ora": "^5.4.0", "semver": "^7.3.7", - "ts-node": "^10.9.1", "which": "^2.0.2", "yaml": "^2.1.1", "yargs": "^17.2.1" @@ -28,7 +28,7 @@ "dev": "ts-node index.ts", "dev:watch": "ts-node-dev index.ts --watch", "test": "jest", - "build": "ncc build index.ts -o dist -e keytar", + "build": "ncc build index.ts -o dist -e keytar -e glob -e dotenv", "prepack": "yarn test && yarn clean && yarn build" }, "devDependencies": { @@ -40,6 +40,7 @@ "@vercel/ncc": "^0.34.0", "jest": "^28.1.3", "ts-jest": "^28.0.7", + "ts-node": "^10.9.1", "ts-node-dev": "^2.0.0", "typescript": "^4.7.4" }, diff --git a/cli/yarn.lock b/cli/yarn.lock index 1ad24aef..47fef2b6 100644 --- a/cli/yarn.lock +++ b/cli/yarn.lock @@ -320,6 +320,13 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@flutter-daemon/server@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@flutter-daemon/server/-/server-0.0.1.tgz#b01f2b2742490fe21c2de2a4a82fae409263131a" + integrity sha512-eGnGOzhLr5jtSek9ynyQmFO46lXrH/C9AS9vyO8h8mhn1lNUXk8qChnL3i0Z2R3iED4lMnOk8uqel6aif5/OQQ== + dependencies: + ws "^8.8.1" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2881,6 +2888,11 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" +ws@^8.8.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" + integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" diff --git a/editor-packages/editor-preview-flutter-daemon-view/flutter-daemon-view.tsx b/editor-packages/editor-preview-flutter-daemon-view/flutter-daemon-view.tsx new file mode 100644 index 00000000..bec3bfdd --- /dev/null +++ b/editor-packages/editor-preview-flutter-daemon-view/flutter-daemon-view.tsx @@ -0,0 +1,99 @@ +import React, { useEffect, useState } from "react"; +import Client, { FlutterProject } from "@flutter-daemon/client"; + +/** + * cached client + */ +let _clinet: Client; +function useClinet() { + const [client, setClient] = useState(_clinet); + useEffect(() => { + if (!_clinet) { + _clinet = new Client("ws://localhost:43070"); + setClient(_clinet); + } + }, []); + + return client; +} + +/** + * cached project + */ +let _project: FlutterProject; +function useMainProject(initial?: string) { + const client = useClinet(); + const [project, setProject] = useState(_project); + useEffect(() => { + if (!client) return; + if (!_project) { + client + .project("tmp", "tmp", { + "lib/main.dart": initial, + }) + .then((project) => { + _project = project; + setProject(_project); + }); + } + }, [client]); + return project; +} + +/** + * A flutter render view uses `@flutter-daemon/client` with present `@flutter-daemon/server` connection. + * @returns + */ +export function SingleFileMainFlutterDaemonView({ + src, + loading, +}: { + src: string; + loading?: JSX.Element; +}) { + const project = useMainProject(src); + const [booted, setBooted] = useState(false); + const [weblaunchUrl, setWeblaunchUrl] = useState(); + + const [refreshKey, setRefreshKey] = useState(0); + + useEffect(() => { + if (project) { + project.webLaunchUrl().then((url) => { + setBooted(true); + setWeblaunchUrl(url); + }); + } + }, [project]); + + useEffect(() => { + console.log("src changed"); + if (project) { + console.log("writing file..."); + project + .writeFile("lib/main.dart", src, true) + .then(() => { + console.log("file written"); + setRefreshKey(refreshKey + 1); + }) + .catch(console.error); + // project.restart().then(() => {}); + } + }, [src]); + + if (booted) { + return ( +