From 261387b21d7c63d331be4921b1b2825dcf4143d0 Mon Sep 17 00:00:00 2001 From: Terry Jia Date: Tue, 10 Jun 2025 21:28:19 -0400 Subject: [PATCH 1/2] use typed comfy app --- package-lock.json | 33 +++++++ package.json | 3 +- src/components/VueExampleComponent.vue | 73 ++++++++++----- src/main.ts | 119 +++++++++++++++++++------ vite.config.mts | 1 - 5 files changed, 174 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6be2b34..b321aa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "devDependencies": { + "@comfyorg/comfyui-frontend-types": "^1.22.1", "@vitejs/plugin-vue": "^5.2.3", "vite": "^6.3.5", "vite-plugin-vue-devtools": "^7.7.2" @@ -497,6 +498,27 @@ "node": ">=6.9.0" } }, + "node_modules/@comfyorg/comfyui-frontend-types": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/@comfyorg/comfyui-frontend-types/-/comfyui-frontend-types-1.22.1.tgz", + "integrity": "sha512-/jtTgvUS8K8KrsSxeIdaaTIMbLSgFFJBefnnv+gYZTd0xp+DRttar2L4/ZQGPZpFR1CwEU70dAEQEd30nxvPcw==", + "dev": true, + "license": "GPL-3.0-only", + "dependencies": { + "@comfyorg/litegraph": "^0.15.15" + }, + "peerDependencies": { + "vue": "^3.5.13", + "zod": "^3.23.8" + } + }, + "node_modules/@comfyorg/litegraph": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.15.15.tgz", + "integrity": "sha512-otOKgTxNPV6gEa6PW1fHGMMF8twjnZkP0vWQhGsRISK4vN8tPfX8O9sC9Hnq3nV8axaMv4/Ff49+7mMVcFEKeA==", + "dev": true, + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", @@ -2969,6 +2991,17 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.25.58", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.58.tgz", + "integrity": "sha512-DVLmMQzSZwNYzQoMaM3MQWnxr2eq+AtM9Hx3w1/Yl0pH8sLTSjN4jGP7w6f7uand6Hw44tsnSu1hz1AOA6qI2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index f543237..c748fb9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "devDependencies": { "@vitejs/plugin-vue": "^5.2.3", "vite": "^6.3.5", - "vite-plugin-vue-devtools": "^7.7.2" + "vite-plugin-vue-devtools": "^7.7.2", + "@comfyorg/comfyui-frontend-types": "^1.22.1" }, "scripts": { "build": "vite build" diff --git a/src/components/VueExampleComponent.vue b/src/components/VueExampleComponent.vue index b991ca2..8dc7166 100644 --- a/src/components/VueExampleComponent.vue +++ b/src/components/VueExampleComponent.vue @@ -16,7 +16,13 @@ import { onMounted, ref } from 'vue' import DrawingApp from "./DrawingApp.vue"; import { useI18n } from 'vue-i18n' - import { app } from "../../../scripts/app.js"; + import { ComfyApp } from '@comfyorg/comfyui-frontend-types' + + declare global { + interface Window { + app?: ComfyApp + } + } const { t } = useI18n() const drawingAppRef = ref | null>(null); @@ -35,37 +41,56 @@ } async function uploadTempImage(imageData: string, prefix: string) { - const blob = await fetch(imageData).then((r) => r.blob()) - const name = `${prefix}_${Date.now()}.png` - const file = new File([blob], name) + try { + if (!window.app?.api) { + throw new Error('ComfyUI API not available') + } + + const blob = await fetch(imageData).then((r) => r.blob()) + const name = `${prefix}_${Date.now()}.png` + const file = new File([blob], name) - const body = new FormData() - body.append('image', file) - body.append('subfolder', 'threed') - body.append('type', 'temp') + const body = new FormData() + body.append('image', file) + body.append('subfolder', 'threed') + body.append('type', 'temp') - console.log(app.api.fetchApi) + console.log('Vue Component: Using window.app.api.fetchApi') - const resp = await app.api.fetchApi('/upload/image', { - method: 'POST', - body - }) + const resp = await window.app.api.fetchApi('/upload/image', { + method: 'POST', + body + }) - return resp.json() + return resp.json() + } catch (error) { + console.error('Vue Component: Error uploading image:', error) + throw error + } } onMounted(() => { widget.serializeValue = async (node, index) => { - console.log("inside vue") - console.log("node", node) - console.log("index", index) - - const canvasData = canvasDataURL.value - - const data = await uploadTempImage(canvasData, "test_vue_basic") - - return { - image: `threed/${data.name} [temp]` + try { + console.log("Vue Component: inside vue serializeValue") + console.log("node", node) + console.log("index", index) + + const canvasData = canvasDataURL.value + + if (!canvasData) { + console.warn('Vue Component: No canvas data available') + return { image: null } + } + + const data = await uploadTempImage(canvasData, "test_vue_basic") + + return { + image: `threed/${data.name} [temp]` + } + } catch (error) { + console.error('Vue Component: Error in serializeValue:', error) + return { image: null } } } }) diff --git a/src/main.ts b/src/main.ts index 322d864..7aea54a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,39 +1,100 @@ -import { app } from "../../../scripts/app.js"; +import { ComfyApp } from '@comfyorg/comfyui-frontend-types' + import { addWidget, ComponentWidgetImpl } from "../../../scripts/domWidget.js"; import VueExampleComponent from "@/components/VueExampleComponent.vue"; -app.registerExtension({ - name: 'vue-basic', - getCustomWidgets(app) { - return { - CUSTOM_VUE_COMPONENT_BASIC(node) { - // Add custom vue component here +// Declare global ComfyUI objects +declare global { + interface Window { + app?: ComfyApp + } +} - const inputSpec = { - name: 'custom_vue_component_basic', - type: 'vue-basic', - } +function waitForInit(): Promise { + return new Promise((resolve) => { + // Check if document is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', checkApp) + } else { + checkApp() + } - const widget = new ComponentWidgetImpl({ - node, - name: inputSpec.name, - component: VueExampleComponent, - inputSpec, - options: {} - }) - - addWidget(node, widget) - - return {widget} - } + // Check if app is available + function checkApp() { + if (window.app) { + resolve() + } else { + // Poll for app availability + const interval = setInterval(() => { + if (window.app) { + console.log('App initialized') + clearInterval(interval) + resolve() + } + }, 50) + + // Set timeout to avoid infinite polling + setTimeout(() => { + clearInterval(interval) + console.error('Timeout waiting for app to initialize') + resolve() // Continue anyway to avoid blocking + }, 5000) + } + } + }) +} + +async function initializeExtension(): Promise { + try { + await waitForInit() + console.log('Vue App:', window.app) + + if (!window.app) { + console.error('ComfyUI app not available') + return } - }, - nodeCreated(node) { - if (node.constructor.comfyClass !== 'vue-basic') return - const [oldWidth, oldHeight] = node.size + window.app.registerExtension({ + name: 'vue-basic', + getCustomWidgets(app) { + return { + CUSTOM_VUE_COMPONENT_BASIC(node) { + // Add custom vue component here + + console.log("tttt") - node.setSize([Math.max(oldWidth, 300), Math.max(oldHeight, 520)]) + const inputSpec = { + name: 'custom_vue_component_basic', + type: 'vue-basic', + } + + const widget = new ComponentWidgetImpl({ + node, + name: inputSpec.name, + component: VueExampleComponent, + inputSpec, + options: {} + }) + + addWidget(node, widget) + + return {widget} + } + } + }, + nodeCreated(node) { + if (node.constructor.comfyClass !== 'vue-basic') return + + const [oldWidth, oldHeight] = node.size + + node.setSize([Math.max(oldWidth, 300), Math.max(oldHeight, 520)]) + } + }); } -}); \ No newline at end of file + catch (error) { + console.error('Failed to initialize Vue basic Example:', error) + } +} + +void initializeExtension() \ No newline at end of file diff --git a/vite.config.mts b/vite.config.mts index 37bfc7c..673a8bb 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -21,7 +21,6 @@ export default defineConfig({ }, rollupOptions: { external: [ - '../../../scripts/app.js', '../../../scripts/api.js', '../../../scripts/domWidget.js', '../../../scripts/utils.js', From c0bf071c1a2129c802480be8fc45d148c7630eba Mon Sep 17 00:00:00 2001 From: Terry Jia Date: Thu, 12 Jun 2025 19:55:43 -0400 Subject: [PATCH 2/2] refactor code --- src/components/VueExampleComponent.vue | 130 ++++++++++++------------- src/main.ts | 113 ++++++--------------- vite.config.mts | 1 + 3 files changed, 94 insertions(+), 150 deletions(-) diff --git a/src/components/VueExampleComponent.vue b/src/components/VueExampleComponent.vue index 8dc7166..88ab83a 100644 --- a/src/components/VueExampleComponent.vue +++ b/src/components/VueExampleComponent.vue @@ -3,97 +3,97 @@

{{ t("vue-basic.title") }}