Files
ComfyUI_frontend/src/services/extensionService.ts

130 lines
3.9 KiB
TypeScript

import { app } from '@/scripts/app'
import { api } from '@/scripts/api'
import { useCommandStore } from '@/stores/commandStore'
import { useExtensionStore } from '@/stores/extensionStore'
import { useKeybindingStore } from '@/stores/keybindingStore'
import { useMenuItemStore } from '@/stores/menuItemStore'
import { useSettingStore } from '@/stores/settingStore'
import { useWidgetStore } from '@/stores/widgetStore'
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
import type { ComfyExtension } from '@/types/comfy'
export const useExtensionService = () => {
const extensionStore = useExtensionStore()
const settingStore = useSettingStore()
/**
* Loads all extensions from the API into the window in parallel
*/
const loadExtensions = async () => {
extensionStore.loadDisabledExtensionNames(
settingStore.get('Comfy.Extension.Disabled')
)
const extensions = await api.getExtensions()
// Need to load core extensions first as some custom extensions
// may depend on them.
await import('../extensions/core/index')
extensionStore.captureCoreExtensions()
await Promise.all(
extensions
.filter((extension) => !extension.includes('extensions/core'))
.map(async (ext) => {
try {
await import(/* @vite-ignore */ api.fileURL(ext))
} catch (error) {
console.error('Error loading extension', ext, error)
}
})
)
}
/**
* Register an extension with the app
* @param extension The extension to register
*/
const registerExtension = (extension: ComfyExtension) => {
extensionStore.registerExtension(extension)
useKeybindingStore().loadExtensionKeybindings(extension)
useCommandStore().loadExtensionCommands(extension)
useMenuItemStore().loadExtensionMenuCommands(extension)
extension.settings?.forEach((setting) => {
settingStore.addSetting(setting)
})
useBottomPanelStore().registerExtensionBottomPanelTabs(extension)
if (extension.getCustomWidgets) {
// TODO(huchenlei): We should deprecate the async return value of
// getCustomWidgets.
;(async () => {
if (extension.getCustomWidgets) {
const widgets = await extension.getCustomWidgets(app)
useWidgetStore().registerCustomWidgets(widgets)
}
})()
}
}
/**
* Invoke an extension callback
* @param {keyof ComfyExtension} method The extension callback to execute
* @param {any[]} args Any arguments to pass to the callback
* @returns
*/
const invokeExtensions = (method: keyof ComfyExtension, ...args: any[]) => {
const results: any[] = []
for (const ext of extensionStore.enabledExtensions) {
if (method in ext) {
try {
results.push(ext[method](...args, app))
} catch (error) {
console.error(
`Error calling extension '${ext.name}' method '${method}'`,
{ error },
{ extension: ext },
{ args }
)
}
}
}
return results
}
/**
* Invoke an async extension callback
* Each callback will be invoked concurrently
* @param {string} method The extension callback to execute
* @param {...any} args Any arguments to pass to the callback
* @returns
*/
const invokeExtensionsAsync = async (
method: keyof ComfyExtension,
...args: any[]
) => {
return await Promise.all(
extensionStore.enabledExtensions.map(async (ext) => {
if (method in ext) {
try {
return await ext[method](...args, app)
} catch (error) {
console.error(
`Error calling extension '${ext.name}' method '${method}'`,
{ error },
{ extension: ext },
{ args }
)
}
}
})
)
}
return {
loadExtensions,
registerExtension,
invokeExtensions,
invokeExtensionsAsync
}
}