[GH-ISSUE #14] Import app directly rather than waitForInit #7

Open
opened 2026-10-26 22:08:22 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @mcmerdith on GitHub (Aug 1, 2025).
Original GitHub issue: https://github.com/Comfy-Org/ComfyUI-React-Extension-Template/issues/14

I just started developing a custom node using this template and ran into frustrating issues with the usage of waitForInit.

A prime example of this is the nodeCreated and getCustomWidgets function for extensions. When using waitForInit, the extension doesn't actually load until after the graph has already been created and nodeCreated will never be run. Similarly for getCustomWidgets, the graph is created before the custom widgets are registered and do not display.

This is fine for sidebar tabs, bottom panels, menus, etc, but altering the graph is not possible under this architecture (user is required to use Fix node (recreate) for widgets defined by the extension to load correctly)

The frontend docs specify that app is available via import { app } from "../../scripts/app.js". I altered this slightly to import { app } from "/scripts/app.js" which may not be strictly correct but it is working for me.

In my extension I achieved this as follows:

/* shims.ts */

import { ComfyApp, ComfyApi } from '@comfyorg/comfyui-frontend-types'

// @ts-expect-error external file
import { app } from '/scripts/app.js'
// @ts-expect-error external file
import { api } from '/scripts/api.js'

declare const app: ComfyApp;
declare const api: ComfyApi;

export { app, api };

Creating a dedicated file to do the imports is not necessary, but is convenient if app or api will be used in multiple places and you want to avoid constantly redeclaring the type.

My full (WIP) extension is prompt-legos to see this implementation in practice.

I am new to the comfy dev ecosystem, so if there is a specific reason to use window.app I am open to alternative options, but this is what I have found works in my use case

Originally created by @mcmerdith on GitHub (Aug 1, 2025). Original GitHub issue: https://github.com/Comfy-Org/ComfyUI-React-Extension-Template/issues/14 I just started developing a custom node using this template and ran into frustrating issues with the usage of `waitForInit`. A prime example of this is the `nodeCreated` and `getCustomWidgets` function for extensions. When using `waitForInit`, the extension doesn't actually load until after the graph has already been created and `nodeCreated` will never be run. Similarly for `getCustomWidgets`, the graph is created before the custom widgets are registered and do not display. This is fine for sidebar tabs, bottom panels, menus, etc, but altering the graph is not possible under this architecture (user is required to use `Fix node (recreate)` for widgets defined by the extension to load correctly) The frontend docs specify that `app` is available via `import { app } from "../../scripts/app.js"`. I altered this slightly to `import { app } from "/scripts/app.js"` which may not be strictly correct but it is working for me. In my extension I achieved this as follows: ```ts /* shims.ts */ import { ComfyApp, ComfyApi } from '@comfyorg/comfyui-frontend-types' // @ts-expect-error external file import { app } from '/scripts/app.js' // @ts-expect-error external file import { api } from '/scripts/api.js' declare const app: ComfyApp; declare const api: ComfyApi; export { app, api }; ``` Creating a dedicated file to do the imports is not necessary, but is convenient if `app` or `api` will be used in multiple places and you want to avoid constantly redeclaring the type. My full (WIP) extension is [prompt-legos](https://github.com/mcmerdith/prompt-legos) to see this implementation in practice. I am new to the comfy dev ecosystem, so if there is a specific reason to use `window.app` I am open to alternative options, but this is what I have found works in my use case
Author
Owner

@christian-byrne commented on GitHub (Aug 1, 2025):

The template's waitForInit function (main.tsx:20-52) waits for window.app to exist to avoid trying to mount things before the vue app is setup (if I recall correctly), but by then (as you identified):

  • Graph construction is complete
  • Node instances already created
  • Widget registration window closed

The current ComfyUI Extension Lifecycle is

  1. init → 2. addCustomNodeDefs → 3. getCustomWidgets → 4. beforeRegisterNodeDef → 5. registerCustomNodes → 6. beforeConfigureGraph → 7. nodeCreated → 8. loadedGraphNode → 9. afterConfigureGraph → 10. setup

The template currently registers at step 10, missing critical steps 3 and 7.

The rewriteComfyImports plugin (vite.config.ts:10-26) already supports direct imports:

  • Development: Rewrites /scripts/app.js → http://127.0.0.1:8188/scripts/app.js
  • Production: Marks scripts as external (not bundled)

This means your approach is already technically supported by the build system.

You are absolutely right. The template should support both patterns:

// Early registration for lifecycle hooks
import { app } from '/scripts/app.js'

app.registerExtension({
  name: 'MyExtension',
  getCustomWidgets() { /* works - registered early */ },
  nodeCreated(node) { /* works - registered early */ }
})

// Later registration for UI components  
waitForInit().then(() => {
  window.app.extensionManager.registerSidebarTab({...}) // same app instance
})

Both approaches can be used together in the same extension since the direct import and window.app reference the same app instance - just accessed at different timing points during initialization. The template should be updated to demonstrate this hybrid approach with clear documentation on when to use each pattern.

<!-- gh-comment-id:3143065698 --> @christian-byrne commented on GitHub (Aug 1, 2025): The template's `waitForInit` function (main.tsx:20-52) waits for `window.app` to exist to avoid trying to mount things before the vue app is setup (if I recall correctly), but by then (as you identified): - Graph construction is complete - Node instances already created - Widget registration window closed The current ComfyUI Extension Lifecycle is 1. `init` → 2. `addCustomNodeDefs` → 3. **`getCustomWidgets`** → 4. `beforeRegisterNodeDef` → 5. `registerCustomNodes` → 6. `beforeConfigureGraph` → 7. **`nodeCreated`** → 8. `loadedGraphNode` → 9. `afterConfigureGraph` → 10. `setup` The template currently registers at step 10, missing critical steps 3 and 7. The `rewriteComfyImports` plugin (vite.config.ts:10-26) already supports direct imports: - Development: Rewrites `/scripts/app.js` → `http://127.0.0.1:8188/scripts/app.js` - Production: Marks scripts as external (not bundled) This means your approach is already technically supported by the build system. You are absolutely right. The template should support both patterns: ```typescript // Early registration for lifecycle hooks import { app } from '/scripts/app.js' app.registerExtension({ name: 'MyExtension', getCustomWidgets() { /* works - registered early */ }, nodeCreated(node) { /* works - registered early */ } }) // Later registration for UI components waitForInit().then(() => { window.app.extensionManager.registerSidebarTab({...}) // same app instance }) ``` **Both approaches can be used together in the same extension** since the direct import and `window.app` reference the same app instance - just accessed at different timing points during initialization. The template should be updated to demonstrate this hybrid approach with clear documentation on when to use each pattern.
Author
Owner

@mcmerdith commented on GitHub (Aug 1, 2025):

Okay, I can PR it, just wanted to check first to make sure I wasn't totally off base

<!-- gh-comment-id:3145963241 --> @mcmerdith commented on GitHub (Aug 1, 2025): Okay, I can PR it, just wanted to check first to make sure I wasn't totally off base
Author
Owner

@christian-byrne commented on GitHub (Aug 2, 2025):

Nope, you're right on the mark. Very much appreciated!

<!-- gh-comment-id:3146185567 --> @christian-byrne commented on GitHub (Aug 2, 2025): Nope, you're right on the mark. Very much appreciated!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/ComfyUI-React-Extension-Template#7
No description provided.