mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-30 19:07:25 +08:00
Add frontend extension example
This commit is contained in:
parent
5d5a4554e1
commit
b278ae149d
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,8 +5,9 @@ __pycache__/
|
|||||||
!/input/example.png
|
!/input/example.png
|
||||||
/models/
|
/models/
|
||||||
/temp/
|
/temp/
|
||||||
/custom_nodes/
|
/custom_nodes/*
|
||||||
!custom_nodes/example_node.py.example
|
!custom_nodes/example_node.py.example
|
||||||
|
!custom_nodes/frontend_extension.js.example
|
||||||
extra_model_paths.yaml
|
extra_model_paths.yaml
|
||||||
/.vs
|
/.vs
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
@ -105,8 +105,9 @@ class Example(io.ComfyNode):
|
|||||||
#def fingerprint_inputs(s, image, string_field, int_field, float_field, print_to_screen):
|
#def fingerprint_inputs(s, image, string_field, int_field, float_field, print_to_screen):
|
||||||
# return ""
|
# return ""
|
||||||
|
|
||||||
# Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension
|
# Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension.
|
||||||
# WEB_DIRECTORY = "./somejs"
|
# See frontend_extension.js.example for a commented JavaScript example.
|
||||||
|
# WEB_DIRECTORY = "./js"
|
||||||
|
|
||||||
|
|
||||||
# Add custom API routes, using router
|
# Add custom API routes, using router
|
||||||
|
|||||||
113
custom_nodes/frontend_extension.js.example
Normal file
113
custom_nodes/frontend_extension.js.example
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
Example frontend extension for a ComfyUI custom node.
|
||||||
|
|
||||||
|
To try this with custom_nodes/example_node.py.example:
|
||||||
|
|
||||||
|
1. Copy example_node.py.example to your custom node package as __init__.py.
|
||||||
|
2. Set WEB_DIRECTORY = "./js" in that Python file.
|
||||||
|
3. Create a js directory next to __init__.py.
|
||||||
|
4. Copy this file to js/frontend_extension.js.
|
||||||
|
|
||||||
|
ComfyUI loads every .js file in WEB_DIRECTORY in the browser. This JavaScript
|
||||||
|
does not run your Python node. It customizes the frontend representation of
|
||||||
|
nodes after the backend has registered their schemas.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { app } from "../../scripts/app.js";
|
||||||
|
|
||||||
|
const EXTENSION_NAME = "comfy.example.frontend_extension";
|
||||||
|
const EXAMPLE_NODE_CLASS = "Example";
|
||||||
|
|
||||||
|
app.registerExtension({
|
||||||
|
name: EXTENSION_NAME,
|
||||||
|
|
||||||
|
/*
|
||||||
|
setup() runs once after the frontend has initialized. Use it for extension
|
||||||
|
level initialization that is not tied to one specific node instance.
|
||||||
|
*/
|
||||||
|
async setup() {
|
||||||
|
console.log(`${EXTENSION_NAME} loaded`);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
beforeRegisterNodeDef() runs when the frontend is about to register a node
|
||||||
|
class. This is the safest place to wrap prototype methods, because every
|
||||||
|
node instance created later will inherit the wrapped behavior.
|
||||||
|
|
||||||
|
nodeData.name is the class name sent by the Python node schema. For the
|
||||||
|
Python example node this is "Example".
|
||||||
|
*/
|
||||||
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||||
|
if (nodeData.name !== EXAMPLE_NODE_CLASS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
||||||
|
|
||||||
|
nodeType.prototype.onNodeCreated = function () {
|
||||||
|
const result = originalOnNodeCreated?.apply(this, arguments);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function runs for each frontend node instance. At this point
|
||||||
|
`this` is the LiteGraph node object shown on the canvas.
|
||||||
|
|
||||||
|
Use properties for data that should be serialized with the workflow.
|
||||||
|
Plain fields on `this` are useful for transient UI state.
|
||||||
|
*/
|
||||||
|
this.properties = this.properties || {};
|
||||||
|
this.properties.example_frontend_extension_enabled ??= true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
addWidget() adds a control to the node body. This button only logs
|
||||||
|
information, so it is safe as an example and does not change queueing
|
||||||
|
or execution behavior.
|
||||||
|
*/
|
||||||
|
this.addWidget("button", "Log node info", null, () => {
|
||||||
|
console.log("Node id:", this.id);
|
||||||
|
console.log("Node title:", this.title);
|
||||||
|
console.log("Node properties:", this.properties);
|
||||||
|
console.log("Output images:", this.imgs);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prototype methods can be hooked by saving the original method and
|
||||||
|
calling it from your replacement. Keep the original call unless you
|
||||||
|
intentionally want to replace ComfyUI's default behavior.
|
||||||
|
|
||||||
|
onExecuted() is called after this node receives execution results from
|
||||||
|
the backend. If the node produced image previews, ComfyUI may expose
|
||||||
|
those images on node.imgs. The field can be undefined or empty before
|
||||||
|
the node has executed, or for nodes that do not display images.
|
||||||
|
*/
|
||||||
|
const originalOnExecuted = nodeType.prototype.onExecuted;
|
||||||
|
|
||||||
|
nodeType.prototype.onExecuted = function (message) {
|
||||||
|
const result = originalOnExecuted?.apply(this, arguments);
|
||||||
|
|
||||||
|
if (this.imgs?.length) {
|
||||||
|
console.log(`Node ${this.id} is displaying ${this.imgs.length} image(s).`);
|
||||||
|
} else {
|
||||||
|
console.log(`Node ${this.id} executed without frontend images.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug("Execution message:", message);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
nodeCreated() is another lifecycle hook. It runs for each node instance
|
||||||
|
after creation. Use it for per-node setup that does not need to alter the
|
||||||
|
node class prototype.
|
||||||
|
*/
|
||||||
|
async nodeCreated(node) {
|
||||||
|
if (node.comfyClass !== EXAMPLE_NODE_CLASS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.exampleFrontendExtensionLoaded = true;
|
||||||
|
},
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user