mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat: add Vue widget demo node and development support
- Add LoraManagerDemoNode to node mappings for Vue widget demonstration - Update .gitignore to exclude Vue widget development artifacts (node_modules, .vite, dist) - Implement automatic Vue widget build check in development mode with fallback handling - Maintain pytest compatibility with proper import error handling
This commit is contained in:
4
vue-widgets/.gitignore
vendored
Normal file
4
vue-widgets/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
*.local
|
||||
.DS_Store
|
||||
179
vue-widgets/DEMO_INSTRUCTIONS.md
Normal file
179
vue-widgets/DEMO_INSTRUCTIONS.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Demo Widget Testing Instructions
|
||||
|
||||
## What Was Created
|
||||
|
||||
A complete Vue + PrimeVue development scaffold for creating custom ComfyUI widgets, including a working demo to validate the entire workflow.
|
||||
|
||||
## Components
|
||||
|
||||
### 1. Python Node (`py/nodes/demo_vue_widget_node.py`)
|
||||
- **Node Name**: LoRA Manager Demo (Vue)
|
||||
- **Category**: loramanager/demo
|
||||
- **Inputs**:
|
||||
- `lora_demo_widget` (custom widget)
|
||||
- `text` (optional string)
|
||||
- **Outputs**:
|
||||
- `model_name` (STRING)
|
||||
- `strength` (FLOAT)
|
||||
- `info` (STRING)
|
||||
|
||||
### 2. Vue Widget (`vue-widgets/src/components/DemoWidget.vue`)
|
||||
Uses PrimeVue components:
|
||||
- **InputText** - For model name input
|
||||
- **InputNumber** - For strength value (0-2, step 0.1) with +/- buttons
|
||||
- **Button** - Apply and Reset actions
|
||||
- **Card** - Display current configuration
|
||||
|
||||
### 3. Build System
|
||||
- **Vite** - Fast build tool
|
||||
- **TypeScript** - Type-safe development
|
||||
- **Output**: `web/comfyui/vue-widgets/demo-widget.js`
|
||||
|
||||
## How to Test
|
||||
|
||||
### 1. Build the Widget (if not already built)
|
||||
|
||||
```bash
|
||||
cd vue-widgets
|
||||
npm install # Only needed once
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 2. Start/Restart ComfyUI
|
||||
|
||||
```bash
|
||||
# In your ComfyUI root directory
|
||||
python main.py
|
||||
```
|
||||
|
||||
### 3. Add the Demo Node
|
||||
|
||||
1. Open ComfyUI in your browser (usually http://localhost:8188)
|
||||
2. Right-click on the canvas → **Add Node**
|
||||
3. Navigate to: **loramanager** → **demo** → **LoRA Manager Demo (Vue)**
|
||||
4. The node should appear with a Vue-powered widget inside
|
||||
|
||||
### 4. Test the Widget
|
||||
|
||||
The widget provides an interactive demo:
|
||||
|
||||
1. **Enter a model name** in the text field (e.g., "test-lora-model")
|
||||
2. **Adjust the strength** using the number input or +/- buttons (0.0 - 2.0)
|
||||
3. **Click "Apply"** to set the configuration
|
||||
4. A card will appear showing the current configuration
|
||||
5. **Click "Reset"** to clear everything
|
||||
|
||||
### 5. Test Workflow Integration
|
||||
|
||||
1. Add some input/output nodes to create a minimal workflow
|
||||
2. Connect the demo node outputs to other nodes:
|
||||
- `model_name` → Can connect to any STRING input
|
||||
- `strength` → Can connect to any FLOAT input
|
||||
- `info` → Informational STRING output
|
||||
3. Click **Queue Prompt** to execute the workflow
|
||||
4. Check the console/terminal - you should see:
|
||||
```
|
||||
[LoraManagerDemoNode] Vue Widget Demo - Model: test-lora-model, Strength: 1.5
|
||||
```
|
||||
|
||||
### 6. Test State Persistence
|
||||
|
||||
1. Configure the widget (set model name and strength, click Apply)
|
||||
2. Save the workflow (Ctrl+S / Cmd+S)
|
||||
3. Reload the page
|
||||
4. Load the saved workflow
|
||||
5. The widget should restore its state
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
✅ **Success Indicators:**
|
||||
- Widget appears inside the node with proper styling
|
||||
- PrimeVue components are rendered correctly
|
||||
- Buttons respond to clicks
|
||||
- Input values update reactively
|
||||
- Configuration card appears after clicking Apply
|
||||
- Node outputs the correct data when workflow executes
|
||||
- State persists when saving/loading workflows
|
||||
|
||||
❌ **Common Issues:**
|
||||
|
||||
**Widget doesn't appear:**
|
||||
- Check browser console for JavaScript errors
|
||||
- Verify `web/comfyui/vue-widgets/demo-widget.js` exists
|
||||
- Restart ComfyUI completely
|
||||
|
||||
**Build errors:**
|
||||
- Make sure you're in the `vue-widgets` directory when running npm commands
|
||||
- Check Node.js version: `node --version` (should be 18+)
|
||||
- Try deleting `node_modules` and running `npm install` again
|
||||
|
||||
**Widget shows but crashes:**
|
||||
- Check browser console for errors
|
||||
- Verify PrimeVue components are imported correctly
|
||||
- Check that the widget type matches between Python and JavaScript
|
||||
|
||||
## Development Workflow
|
||||
|
||||
For active development:
|
||||
|
||||
```bash
|
||||
# Terminal 1: Watch mode for auto-rebuild
|
||||
cd vue-widgets
|
||||
npm run dev
|
||||
|
||||
# Terminal 2: ComfyUI server
|
||||
cd ../../.. # Back to ComfyUI root
|
||||
python main.py
|
||||
```
|
||||
|
||||
When you make changes to Vue files:
|
||||
1. Vite automatically rebuilds
|
||||
2. Hard refresh the browser (Ctrl+Shift+R / Cmd+Shift+R)
|
||||
3. Changes should appear
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that the demo works, you can:
|
||||
|
||||
1. **Modify the demo widget** to add more features
|
||||
2. **Create new widgets** for actual LoRA Manager functionality
|
||||
3. **Add more PrimeVue components** (see [PrimeVue Docs](https://primevue.org/))
|
||||
4. **Integrate with the LoRA Manager API** to fetch real data
|
||||
5. **Add styling** to match ComfyUI's theme better
|
||||
|
||||
## File Structure Reference
|
||||
|
||||
```
|
||||
ComfyUI-Lora-Manager/
|
||||
├── vue-widgets/ # Vue source code
|
||||
│ ├── src/
|
||||
│ │ ├── main.ts # Extension registration
|
||||
│ │ └── components/
|
||||
│ │ └── DemoWidget.vue # Demo widget component
|
||||
│ ├── package.json # Dependencies
|
||||
│ ├── vite.config.mts # Build config
|
||||
│ ├── tsconfig.json # TypeScript config
|
||||
│ ├── README.md # Development guide
|
||||
│ └── DEMO_INSTRUCTIONS.md # This file
|
||||
│
|
||||
├── web/comfyui/
|
||||
│ └── vue-widgets/ # Build output (gitignored)
|
||||
│ ├── demo-widget.js # Compiled JavaScript
|
||||
│ └── assets/
|
||||
│ └── demo-widget-*.css # Compiled CSS
|
||||
│
|
||||
├── py/nodes/
|
||||
│ └── demo_vue_widget_node.py # Python node definition
|
||||
│
|
||||
├── __init__.py # Updated with demo node
|
||||
├── VUE_WIDGETS_SETUP.md # Complete setup guide
|
||||
└── .gitignore # Updated to ignore build output
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check the browser console for errors
|
||||
2. Check the ComfyUI terminal for Python errors
|
||||
3. Review `VUE_WIDGETS_SETUP.md` for detailed documentation
|
||||
4. Review `vue-widgets/README.md` for development guide
|
||||
169
vue-widgets/README.md
Normal file
169
vue-widgets/README.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Vue Widgets for ComfyUI LoRA Manager
|
||||
|
||||
This directory contains the source code for Vue 3 + PrimeVue custom widgets for ComfyUI LoRA Manager.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
vue-widgets/
|
||||
├── src/ # TypeScript/Vue source code
|
||||
│ ├── main.ts # Main entry point that registers extensions
|
||||
│ └── components/ # Vue components
|
||||
│ └── DemoWidget.vue # Example demo widget
|
||||
├── package.json # Dependencies and build scripts
|
||||
├── vite.config.mts # Vite build configuration
|
||||
├── tsconfig.json # TypeScript configuration
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
```bash
|
||||
cd vue-widgets
|
||||
npm install
|
||||
```
|
||||
|
||||
### Build for Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This compiles the TypeScript/Vue code and outputs to `../web/comfyui/vue-widgets/`.
|
||||
|
||||
### Development Mode (Watch)
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This builds the widgets in watch mode, automatically rebuilding when files change.
|
||||
|
||||
### Type Checking
|
||||
|
||||
```bash
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
## Creating a New Widget
|
||||
|
||||
### 1. Create the Python Node
|
||||
|
||||
Create a new node file in `/py/nodes/your_node.py`:
|
||||
|
||||
```python
|
||||
class YourCustomNode:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"your_widget_name": ("YOUR_WIDGET_TYPE", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
FUNCTION = "process"
|
||||
CATEGORY = "loramanager"
|
||||
|
||||
def process(self, your_widget_name):
|
||||
# Process widget data
|
||||
return (str(your_widget_name),)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"YourCustomNode": YourCustomNode
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Create the Vue Component
|
||||
|
||||
Create a new component in `src/components/YourWidget.vue`:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="your-widget-container">
|
||||
<!-- Your UI here using PrimeVue components -->
|
||||
<Button label="Click me" @click="handleClick" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import Button from 'primevue/button'
|
||||
|
||||
const props = defineProps<{
|
||||
widget: { serializeValue?: (node: unknown, index: number) => Promise<unknown> }
|
||||
node: { id: number }
|
||||
}>()
|
||||
|
||||
onMounted(() => {
|
||||
// Serialize widget data when workflow is saved
|
||||
props.widget.serializeValue = async () => {
|
||||
return { /* your data */ }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Your styles */
|
||||
</style>
|
||||
```
|
||||
|
||||
### 3. Register the Widget
|
||||
|
||||
In `src/main.ts`, add your widget registration:
|
||||
|
||||
```typescript
|
||||
import YourWidget from '@/components/YourWidget.vue'
|
||||
|
||||
// In getCustomWidgets()
|
||||
YOUR_WIDGET_TYPE(node) {
|
||||
return createVueWidget(node, YourWidget, 'your-widget-name')
|
||||
}
|
||||
|
||||
// In nodeCreated()
|
||||
if (node.constructor?.comfyClass !== 'YourCustomNode') return
|
||||
```
|
||||
|
||||
### 4. Register the Node
|
||||
|
||||
Add your node to `__init__.py`:
|
||||
|
||||
```python
|
||||
from .py.nodes.your_node import YourCustomNode
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
# ...
|
||||
"YourCustomNode": YourCustomNode
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Build and Test
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Then restart ComfyUI and test your new widget!
|
||||
|
||||
## Available PrimeVue Components
|
||||
|
||||
This project uses PrimeVue 4.x. Popular components include:
|
||||
|
||||
- `Button` - Buttons with icons and variants
|
||||
- `InputText` - Text input fields
|
||||
- `InputNumber` - Number input with increment/decrement
|
||||
- `Dropdown` - Select dropdowns
|
||||
- `Card` - Card containers
|
||||
- `DataTable` - Data tables with sorting/filtering
|
||||
- `Dialog` - Modal dialogs
|
||||
- `Tree` - Tree view components
|
||||
- And many more! See [PrimeVue Docs](https://primevue.org/)
|
||||
|
||||
## Notes
|
||||
|
||||
- Build output goes to `../web/comfyui/vue-widgets/` (gitignored)
|
||||
- The widget type name in Python (e.g., "YOUR_WIDGET_TYPE") must match the key in `getCustomWidgets()`
|
||||
- Widget data is serialized when the workflow is saved/executed via `serializeValue()`
|
||||
- ComfyUI's app.js is marked as external and not bundled
|
||||
1694
vue-widgets/package-lock.json
generated
Normal file
1694
vue-widgets/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
vue-widgets/package.json
Normal file
28
vue-widgets/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "comfyui-lora-manager-vue-widgets",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "Vue-based custom widgets for ComfyUI LoRA Manager",
|
||||
"dependencies": {
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^9.14.0",
|
||||
"primevue": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@comfyorg/comfyui-frontend-types": "^1.35.4",
|
||||
"@types/node": "^22.10.1",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.3.5",
|
||||
"vue-tsc": "^2.1.10"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"build:production": "vite build --mode production",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"clean": "rm -rf ../web/comfyui/vue-widgets",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"prepare": "npm run build"
|
||||
}
|
||||
}
|
||||
37
vue-widgets/pre-commit.example
Normal file
37
vue-widgets/pre-commit.example
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Example pre-commit hook to ensure Vue widgets are built before committing
|
||||
#
|
||||
# To use this hook:
|
||||
# 1. Copy this file to .git/hooks/pre-commit
|
||||
# 2. Make it executable: chmod +x .git/hooks/pre-commit
|
||||
#
|
||||
# Or use a tool like Husky for automatic hook management:
|
||||
# npm install --save-dev husky
|
||||
# npx husky install
|
||||
# npx husky add .git/hooks/pre-commit "cd vue-widgets && npm run build"
|
||||
|
||||
echo "Running pre-commit hook: Building Vue widgets..."
|
||||
|
||||
# Navigate to vue-widgets directory and build
|
||||
cd "$(git rev-parse --show-toplevel)/vue-widgets" || exit 1
|
||||
|
||||
# Check if node_modules exists
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "node_modules not found, running npm install..."
|
||||
npm install || exit 1
|
||||
fi
|
||||
|
||||
# Build Vue widgets
|
||||
npm run build || {
|
||||
echo "❌ Vue widget build failed! Commit aborted."
|
||||
echo "Please fix the build errors before committing."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Add built files to the commit
|
||||
cd ..
|
||||
git add web/comfyui/vue-widgets/
|
||||
|
||||
echo "✓ Vue widgets built and staged successfully"
|
||||
exit 0
|
||||
176
vue-widgets/src/components/DemoWidget.vue
Normal file
176
vue-widgets/src/components/DemoWidget.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<div class="demo-widget-container">
|
||||
<h3 class="demo-title">LoRA Manager Demo Widget</h3>
|
||||
|
||||
<div class="demo-content">
|
||||
<div class="input-group">
|
||||
<label for="demo-input">Model Name:</label>
|
||||
<InputText
|
||||
id="demo-input"
|
||||
v-model="modelName"
|
||||
placeholder="Enter model name..."
|
||||
class="demo-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="strength-input">Strength:</label>
|
||||
<InputNumber
|
||||
id="strength-input"
|
||||
v-model="strength"
|
||||
:min="0"
|
||||
:max="2"
|
||||
:step="0.1"
|
||||
showButtons
|
||||
class="demo-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<Button
|
||||
label="Apply"
|
||||
icon="pi pi-check"
|
||||
@click="handleApply"
|
||||
severity="success"
|
||||
/>
|
||||
<Button
|
||||
label="Reset"
|
||||
icon="pi pi-refresh"
|
||||
@click="handleReset"
|
||||
severity="secondary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Card v-if="appliedValue" class="result-card">
|
||||
<template #title>Current Configuration</template>
|
||||
<template #content>
|
||||
<p><strong>Model:</strong> {{ appliedValue.modelName || 'None' }}</p>
|
||||
<p><strong>Strength:</strong> {{ appliedValue.strength }}</p>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import Button from 'primevue/button'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import InputNumber from 'primevue/inputnumber'
|
||||
import Card from 'primevue/card'
|
||||
|
||||
interface ComponentWidget {
|
||||
serializeValue?: (node: unknown, index: number) => Promise<unknown>
|
||||
value?: unknown
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
widget: ComponentWidget
|
||||
node: { id: number }
|
||||
}>()
|
||||
|
||||
const modelName = ref('')
|
||||
const strength = ref(1.0)
|
||||
const appliedValue = ref<{ modelName: string; strength: number } | null>(null)
|
||||
|
||||
function handleApply() {
|
||||
appliedValue.value = {
|
||||
modelName: modelName.value,
|
||||
strength: strength.value
|
||||
}
|
||||
console.log('Applied configuration:', appliedValue.value)
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
modelName.value = ''
|
||||
strength.value = 1.0
|
||||
appliedValue.value = null
|
||||
console.log('Reset configuration')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Serialize the widget value when the workflow is saved or executed
|
||||
props.widget.serializeValue = async () => {
|
||||
const value = appliedValue.value || { modelName: '', strength: 1.0 }
|
||||
console.log('Serializing widget value:', value)
|
||||
return value
|
||||
}
|
||||
|
||||
// Restore widget value if it exists
|
||||
if (props.widget.value) {
|
||||
const savedValue = props.widget.value as { modelName: string; strength: number }
|
||||
modelName.value = savedValue.modelName || ''
|
||||
strength.value = savedValue.strength || 1.0
|
||||
appliedValue.value = savedValue
|
||||
console.log('Restored widget value:', savedValue)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-widget-container {
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
background: var(--comfy-menu-bg);
|
||||
border-radius: 4px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
|
||||
.demo-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
margin-top: 8px;
|
||||
background: var(--comfy-input-bg);
|
||||
}
|
||||
|
||||
.result-card :deep(.p-card-title) {
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.result-card :deep(.p-card-content) {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.result-card p {
|
||||
margin: 4px 0;
|
||||
font-size: 13px;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
</style>
|
||||
73
vue-widgets/src/main.ts
Normal file
73
vue-widgets/src/main.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { createApp, type App as VueApp } from 'vue'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import DemoWidget from '@/components/DemoWidget.vue'
|
||||
|
||||
// @ts-ignore - ComfyUI external module
|
||||
import { app } from '../../../scripts/app.js'
|
||||
|
||||
const vueApps = new Map<number, VueApp>()
|
||||
|
||||
// @ts-ignore
|
||||
function createVueWidget(node) {
|
||||
const container = document.createElement('div')
|
||||
container.id = `lora-manager-demo-widget-${node.id}`
|
||||
container.style.width = '100%'
|
||||
container.style.height = '100%'
|
||||
container.style.minHeight = '300px'
|
||||
container.style.display = 'flex'
|
||||
container.style.flexDirection = 'column'
|
||||
container.style.overflow = 'hidden'
|
||||
|
||||
const widget = node.addDOMWidget(
|
||||
'lora_demo_widget',
|
||||
'lora-manager-demo',
|
||||
container,
|
||||
{
|
||||
getMinHeight: () => 320,
|
||||
hideOnZoom: false,
|
||||
serialize: true
|
||||
}
|
||||
)
|
||||
|
||||
const vueApp = createApp(DemoWidget, {
|
||||
widget,
|
||||
node
|
||||
})
|
||||
|
||||
vueApp.use(PrimeVue)
|
||||
|
||||
vueApp.mount(container)
|
||||
vueApps.set(node.id, vueApp)
|
||||
|
||||
widget.onRemove = () => {
|
||||
const vueApp = vueApps.get(node.id)
|
||||
if (vueApp) {
|
||||
vueApp.unmount()
|
||||
vueApps.delete(node.id)
|
||||
}
|
||||
}
|
||||
|
||||
return { widget }
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: 'comfyui.loramanager.demo',
|
||||
|
||||
getCustomWidgets() {
|
||||
return {
|
||||
// @ts-ignore
|
||||
LORA_DEMO_WIDGET(node) {
|
||||
return createVueWidget(node)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @ts-ignore
|
||||
nodeCreated(node) {
|
||||
if (node.constructor?.comfyClass !== 'LoraManagerDemoNode') return
|
||||
|
||||
const [oldWidth, oldHeight] = node.size
|
||||
|
||||
node.setSize([Math.max(oldWidth, 350), Math.max(oldHeight, 400)])
|
||||
}
|
||||
})
|
||||
24
vue-widgets/tsconfig.json
Normal file
24
vue-widgets/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
10
vue-widgets/tsconfig.node.json
Normal file
10
vue-widgets/tsconfig.node.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.mts"]
|
||||
}
|
||||
35
vue-widgets/vite.config.mts
Normal file
35
vue-widgets/vite.config.mts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src')
|
||||
}
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, './src/main.ts'),
|
||||
formats: ['es'],
|
||||
fileName: 'demo-widget'
|
||||
},
|
||||
rollupOptions: {
|
||||
external: [
|
||||
'../../../scripts/app.js'
|
||||
],
|
||||
output: {
|
||||
dir: '../web/comfyui/vue-widgets',
|
||||
entryFileNames: 'demo-widget.js',
|
||||
chunkFileNames: 'assets/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[name]-[hash][extname]'
|
||||
}
|
||||
},
|
||||
sourcemap: true,
|
||||
minify: false
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user