diff --git a/.claude/commands/create-frontend-release.md b/.claude/commands/create-frontend-release.md
index bbd6578c00c..de669571088 100644
--- a/.claude/commands/create-frontend-release.md
+++ b/.claude/commands/create-frontend-release.md
@@ -128,7 +128,25 @@ echo "Last stable release: $LAST_STABLE"
### Step 4: Analyze Dependency Updates
-1. **Check significant dependency updates:**
+1. **Use pnpm's built-in dependency analysis:**
+ ```bash
+ # Get outdated dependencies with pnpm
+ pnpm outdated --format table > outdated-deps-${NEW_VERSION}.txt
+
+ # Check for license compliance
+ pnpm licenses ls --json > licenses-${NEW_VERSION}.json
+
+ # Analyze why specific dependencies exist
+ echo "Dependency analysis:" > dep-analysis-${NEW_VERSION}.md
+ MAJOR_DEPS=("vue" "vite" "@vitejs/plugin-vue" "typescript" "pinia")
+ for dep in "${MAJOR_DEPS[@]}"; do
+ echo -e "\n## $dep\n\`\`\`" >> dep-analysis-${NEW_VERSION}.md
+ pnpm why "$dep" >> dep-analysis-${NEW_VERSION}.md || echo "Not found" >> dep-analysis-${NEW_VERSION}.md
+ echo "\`\`\`" >> dep-analysis-${NEW_VERSION}.md
+ done
+ ```
+
+2. **Check for significant dependency updates:**
```bash
# Extract all dependency changes for major version bumps
OTHER_DEP_CHANGES=""
@@ -200,22 +218,48 @@ echo "Last stable release: $LAST_STABLE"
PR data: [contents of prs-${NEW_VERSION}.json]
```
-3. **Generate GTM notification:**
+3. **Generate GTM notification using this EXACT Slack-compatible format:**
```bash
- # Save to gtm-summary-${NEW_VERSION}.md based on analysis
- # If GTM-worthy features exist, include them with testing instructions
- # If not, note that this is a maintenance/bug fix release
-
- # Check if notification is needed
- if grep -q "No marketing-worthy features" gtm-summary-${NEW_VERSION}.md; then
- echo "✅ No GTM notification needed for this release"
- echo "📄 Summary saved to: gtm-summary-${NEW_VERSION}.md"
- else
+ # Only create file if GTM-worthy features exist:
+ if [ "$GTM_FEATURES_FOUND" = "true" ]; then
+ cat > gtm-summary-${NEW_VERSION}.md << 'EOF'
+ *GTM Summary: ComfyUI Frontend v${NEW_VERSION}*
+
+ _Disclaimer: the below is AI-generated_
+
+ 1. *[Feature Title]* (#[PR_NUMBER])
+ * *Author:* @[username]
+ * *Demo:* [Media Link or "No demo available"]
+ * *Why users should care:* [One compelling sentence]
+ * *Key Features:*
+ * [Feature detail 1]
+ * [Feature detail 2]
+
+ 2. *[Feature Title]* (#[PR_NUMBER])
+ * *Author:* @[username]
+ * *Demo:* [Media Link]
+ * *Why users should care:* [One compelling sentence]
+ * *Key Features:*
+ * [Feature detail 1]
+ * [Feature detail 2]
+ EOF
echo "📋 GTM summary saved to: gtm-summary-${NEW_VERSION}.md"
echo "📤 Share this file in #gtm channel to notify the team"
+ else
+ echo "✅ No GTM notification needed for this release"
+ echo "📄 No gtm-summary file created - no marketing-worthy features"
fi
```
+ **CRITICAL Formatting Requirements:**
+ - Use single asterisk (*) for emphasis, NOT double (**)
+ - Use underscore (_) for italics
+ - Use 4 spaces for indentation (not tabs)
+ - Convert author names to @username format (e.g., "John Smith" → "@john")
+ - No section headers (#), no code language specifications
+ - Always include "Disclaimer: the below is AI-generated"
+ - Keep content minimal - no testing instructions, additional sections, etc.
+
### Step 6: Version Preview
**Version Preview:**
@@ -228,37 +272,42 @@ echo "Last stable release: $LAST_STABLE"
### Step 7: Security and Dependency Audit
-1. Run security audit:
+1. Run pnpm security audit:
```bash
- npm audit --audit-level moderate
+ pnpm audit --audit-level moderate
+ pnpm licenses ls --summary
```
2. Check for known vulnerabilities in dependencies
-3. Scan for hardcoded secrets or credentials:
+3. Run comprehensive dependency health check:
+ ```bash
+ pnpm doctor
+ ```
+4. Scan for hardcoded secrets or credentials:
```bash
git log -p ${BASE_TAG}..HEAD | grep -iE "(password|key|secret|token)" || echo "No sensitive data found"
```
-4. Verify no sensitive data in recent commits
-5. **SECURITY REVIEW**: Address any critical findings before proceeding?
+5. Verify no sensitive data in recent commits
+6. **SECURITY REVIEW**: Address any critical findings before proceeding?
### Step 8: Pre-Release Testing
1. Run complete test suite:
```bash
- npm run test:unit
- npm run test:component
+ pnpm test:unit
+ pnpm test:component
```
2. Run type checking:
```bash
- npm run typecheck
+ pnpm typecheck
```
3. Run linting (may have issues with missing packages):
```bash
- npm run lint || echo "Lint issues - verify if critical"
+ pnpm lint || echo "Lint issues - verify if critical"
```
4. Test build process:
```bash
- npm run build
- npm run build:types
+ pnpm build
+ pnpm build:types
```
5. **QUALITY GATE**: All tests and builds passing?
@@ -488,7 +537,7 @@ echo "Workflow triggered. Waiting for PR creation..."
```bash
# Check npm availability
for i in {1..10}; do
- if npm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
+ if pnpm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
echo "✅ npm package available"
break
fi
diff --git a/.claude/commands/create-hotfix-release.md b/.claude/commands/create-hotfix-release.md
index 5dd29469853..de314309dbc 100644
--- a/.claude/commands/create-hotfix-release.md
+++ b/.claude/commands/create-hotfix-release.md
@@ -80,7 +80,7 @@ For each commit:
- **CONFIRMATION REQUIRED**: Conflicts resolved correctly?
3. After successful cherry-pick:
- Show the changes: `git show HEAD`
- - Run validation: `npm run typecheck && npm run lint`
+ - Run validation: `pnpm typecheck && pnpm lint`
4. **CONFIRMATION REQUIRED**: Cherry-pick successful and valid?
### Step 6: Create PR to Core Branch
@@ -197,7 +197,7 @@ For each commit:
5. Track progress:
- GitHub release draft/publication
- PyPI upload
- - npm types publication
+ - pnpm types publication
### Step 12: Post-Release Verification
@@ -211,7 +211,7 @@ For each commit:
```
3. Verify npm package:
```bash
- npm view @comfyorg/comfyui-frontend-types@1.23.5
+ pnpm view @comfyorg/comfyui-frontend-types@1.23.5
```
4. Generate release summary with:
- Version released
diff --git a/.claude/commands/verify-visually.md b/.claude/commands/verify-visually.md
index 6a6c63eaa8e..66260b159fe 100644
--- a/.claude/commands/verify-visually.md
+++ b/.claude/commands/verify-visually.md
@@ -5,7 +5,7 @@ Follow these steps systematically to verify our changes:
1. **Server Setup**
- Check if the dev server is running on port 5173 using browser navigation or port checking
- - If not running, start it with `npm run dev` from the root directory
+ - If not running, start it with `pnpm dev` from the root directory
- If the server fails to start, provide detailed troubleshooting steps by reading package.json and README.md for accurate instructions
- Wait for the server to be fully ready before proceeding
diff --git a/.github/workflows/chromatic.yaml b/.github/workflows/chromatic.yaml
index 11ac26254ed..ed2314e80af 100644
--- a/.github/workflows/chromatic.yaml
+++ b/.github/workflows/chromatic.yaml
@@ -21,11 +21,16 @@ jobs:
with:
fetch-depth: 0 # Required for Chromatic baseline
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- cache: 'npm'
+ cache: 'pnpm'
- name: Get current time
id: current-time
@@ -51,8 +56,21 @@ jobs:
---
*This comment will be updated when the build completes*
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ storybook-static
+ tsconfig.tsbuildinfo
+ key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
+ restore-keys: |
+ storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
+ storybook-cache-${{ runner.os }}-
+ storybook-tools-cache-${{ runner.os }}-
+
- name: Install dependencies
- run: npm ci
+ run: pnpm install --frozen-lockfile
- name: Build Storybook and run Chromatic
id: chromatic
diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml
index 5b0c0ffbd1d..3ec61cb3c2c 100644
--- a/.github/workflows/claude-pr-review.yml
+++ b/.github/workflows/claude-pr-review.yml
@@ -53,14 +53,20 @@ jobs:
with:
fetch-depth: 0
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
+ cache: 'pnpm'
- name: Install dependencies for analysis tools
run: |
- npm install -g typescript @vue/compiler-sfc
+ pnpm install -g typescript @vue/compiler-sfc
- name: Run Claude PR Review
uses: anthropics/claude-code-action@main
diff --git a/.github/workflows/dev-release.yaml b/.github/workflows/dev-release.yaml
index 177c01df927..0b45420c646 100644
--- a/.github/workflows/dev-release.yaml
+++ b/.github/workflows/dev-release.yaml
@@ -16,9 +16,26 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ dist
+ tsconfig.tsbuildinfo
+ key: dev-release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ dev-release-tools-cache-${{ runner.os }}-
+
- name: Get current version
id: current_version
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
@@ -29,9 +46,9 @@ jobs:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
USE_PROD_CONFIG: 'true'
run: |
- npm ci
- npm run build
- npm run zipdist
+ pnpm install --frozen-lockfile
+ pnpm build
+ pnpm zipdist
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/i18n-custom-nodes.yaml b/.github/workflows/i18n-custom-nodes.yaml
index 8d2c354996b..a5617c19642 100644
--- a/.github/workflows/i18n-custom-nodes.yaml
+++ b/.github/workflows/i18n-custom-nodes.yaml
@@ -42,9 +42,14 @@ jobs:
with:
repository: ${{ inputs.owner }}/${{ inputs.repository }}
path: 'ComfyUI/custom_nodes/${{ inputs.repository }}'
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
+ cache: 'pnpm'
- uses: actions/setup-python@v4
with:
python-version: '3.10'
@@ -63,8 +68,8 @@ jobs:
working-directory: ComfyUI/custom_nodes/${{ inputs.repository }}
- name: Build & Install ComfyUI_frontend
run: |
- npm ci
- npm run build
+ pnpm install --frozen-lockfile
+ pnpm build
rm -rf ../ComfyUI/web/*
mv dist/* ../ComfyUI/web/
working-directory: ComfyUI_frontend
@@ -79,18 +84,18 @@ jobs:
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
- run: npm run dev:electron &
+ run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Capture base i18n
run: npx tsx scripts/diff-i18n capture
working-directory: ComfyUI_frontend
- name: Update en.json
- run: npm run collect-i18n
+ run: pnpm collect-i18n
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
- run: npm run locale
+ run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend
diff --git a/.github/workflows/i18n-node-defs.yaml b/.github/workflows/i18n-node-defs.yaml
index 3e672cbd1a3..1327db3cf74 100644
--- a/.github/workflows/i18n-node-defs.yaml
+++ b/.github/workflows/i18n-node-defs.yaml
@@ -13,22 +13,22 @@ jobs:
update-locales:
runs-on: ubuntu-latest
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
+ - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
- run: npm run dev:electron &
+ run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Update en.json
- run: npm run collect-i18n -- scripts/collect-i18n-node-defs.ts
+ run: pnpm collect-i18n -- scripts/collect-i18n-node-defs.ts
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
- run: npm run locale
+ run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend
diff --git a/.github/workflows/i18n.yaml b/.github/workflows/i18n.yaml
index 3482e74c6f5..2f332e9dcb7 100644
--- a/.github/workflows/i18n.yaml
+++ b/.github/workflows/i18n.yaml
@@ -1,37 +1,45 @@
name: Update Locales
on:
+ # Manual dispatch for urgent translation updates
+ workflow_dispatch:
+ # Only trigger on PRs to main/master - additional branch filtering in job condition
pull_request:
- branches: [ main, master, dev* ]
- paths-ignore:
- - '.github/**'
- - '.husky/**'
- - '.vscode/**'
- - 'browser_tests/**'
- - 'tests-ui/**'
+ branches: [ main ]
+ types: [opened, synchronize, reopened]
jobs:
update-locales:
- # Don't run on fork PRs
- if: github.event.pull_request.head.repo.full_name == github.repository
+ # Branch detection: Only run for manual dispatch or version-bump-* branches from main repo
+ if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-'))
runs-on: ubuntu-latest
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
+ - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ ComfyUI_frontend/.cache
+ ComfyUI_frontend/.cache
+ key: i18n-tools-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}
+ restore-keys: |
+ i18n-tools-cache-${{ runner.os }}-
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
- run: npm run dev:electron &
+ run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Update en.json
- run: npm run collect-i18n -- scripts/collect-i18n-general.ts
+ run: pnpm collect-i18n -- scripts/collect-i18n-general.ts
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
- run: npm run locale
+ run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend
diff --git a/.github/workflows/lint-and-format.yaml b/.github/workflows/lint-and-format.yaml
index 5d9a50d834f..b715328db96 100644
--- a/.github/workflows/lint-and-format.yaml
+++ b/.github/workflows/lint-and-format.yaml
@@ -19,20 +19,40 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- cache: 'npm'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ .eslintcache
+ tsconfig.tsbuildinfo
+ .prettierCache
+ .knip-cache
+ key: lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js,mts}', '*.config.*', '.eslintrc.*', '.prettierrc.*', 'tsconfig.json') }}
+ restore-keys: |
+ lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
+ lint-format-cache-${{ runner.os }}-
+ ci-tools-cache-${{ runner.os }}-
- name: Install dependencies
- run: npm ci
+ run: pnpm install --frozen-lockfile
- name: Run ESLint with auto-fix
- run: npm run lint:fix
+ run: pnpm lint:fix
- name: Run Prettier with auto-format
- run: npm run format
+ run: pnpm format
- name: Check for changes
id: verify-changed-files
@@ -54,12 +74,13 @@ jobs:
- name: Final validation
run: |
- npm run lint
- npm run format:check
- npm run knip
+ pnpm lint
+ pnpm format:check
+ pnpm knip
- name: Comment on PR about auto-fix
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
+ continue-on-error: true
uses: actions/github-script@v7
with:
script: |
@@ -72,6 +93,7 @@ jobs:
- name: Comment on PR about manual fix needed
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name != github.repository
+ continue-on-error: true
uses: actions/github-script@v7
with:
script: |
@@ -79,5 +101,5 @@ jobs:
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
- body: '## ⚠️ Linting/Formatting Issues Found\n\nThis PR has linting or formatting issues that need to be fixed.\n\n**Since this PR is from a fork, auto-fix cannot be applied automatically.**\n\n### Option 1: Set up pre-commit hooks (recommended)\nRun this once to automatically format code on every commit:\n```bash\nnpm run prepare\n```\n\n### Option 2: Fix manually\nRun these commands and push the changes:\n```bash\nnpm run lint:fix\nnpm run format\n```\n\nSee [CONTRIBUTING.md](https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/CONTRIBUTING.md#git-pre-commit-hooks) for more details.'
+ body: '## ⚠️ Linting/Formatting Issues Found\n\nThis PR has linting or formatting issues that need to be fixed.\n\n**Since this PR is from a fork, auto-fix cannot be applied automatically.**\n\n### Option 1: Set up pre-commit hooks (recommended)\nRun this once to automatically format code on every commit:\n```bash\npnpm prepare\n```\n\n### Option 2: Fix manually\nRun these commands and push the changes:\n```bash\npnpm lint:fix\npnpm format\n```\n\nSee [CONTRIBUTING.md](https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/CONTRIBUTING.md#git-pre-commit-hooks) for more details.'
})
\ No newline at end of file
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 55c0881635b..8958ce14705 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -19,9 +19,25 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ tsconfig.tsbuildinfo
+ key: release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ release-tools-cache-${{ runner.os }}-
+
- name: Get current version
id: current_version
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
@@ -41,9 +57,9 @@ jobs:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
USE_PROD_CONFIG: 'true'
run: |
- npm ci
- npm run build
- npm run zipdist
+ pnpm install --frozen-lockfile
+ pnpm build
+ pnpm zipdist
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
@@ -113,14 +129,31 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
+ cache: 'pnpm'
registry-url: https://registry.npmjs.org
- - run: npm ci
- - run: npm run build:types
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ tsconfig.tsbuildinfo
+ dist
+ key: types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ types-tools-cache-${{ runner.os }}-
+
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build:types
- name: Publish package
- run: npm publish --access public
+ run: pnpm publish --access public
working-directory: dist
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.github/workflows/test-browser-exp.yaml b/.github/workflows/test-browser-exp.yaml
index 6f73174c1d2..f260c2a3d8c 100644
--- a/.github/workflows/test-browser-exp.yaml
+++ b/.github/workflows/test-browser-exp.yaml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
if: github.event.label.name == 'New Browser Test Expectations'
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
+ - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend
diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/test-ui.yaml
index a41964d7fa5..3838e98b09e 100644
--- a/.github/workflows/test-ui.yaml
+++ b/.github/workflows/test-ui.yaml
@@ -37,9 +37,16 @@ jobs:
path: 'ComfyUI/custom_nodes/ComfyUI_devtools'
ref: 'd05fd48dd787a4192e16802d4244cfcc0e2f9684'
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- uses: actions/setup-node@v4
with:
node-version: lts/*
+ cache: 'pnpm'
+ cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml'
- name: Get current time
id: current-time
@@ -59,16 +66,28 @@ jobs:
---
-
+
[${{ steps.current-time.outputs.time }} UTC] Preparing browser tests across multiple browsers...
---
*This comment will be updated when tests complete*
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ ComfyUI_frontend/.cache
+ ComfyUI_frontend/tsconfig.tsbuildinfo
+ key: playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-${{ hashFiles('ComfyUI_frontend/src/**/*.{ts,vue,js}', 'ComfyUI_frontend/*.config.*') }}
+ restore-keys: |
+ playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-
+ playwright-setup-cache-${{ runner.os }}-
+ playwright-tools-cache-${{ runner.os }}-
+
- name: Build ComfyUI_frontend
run: |
- npm ci
- npm run build
+ pnpm install --frozen-lockfile
+ pnpm build
working-directory: ComfyUI_frontend
- name: Generate cache key
@@ -115,9 +134,15 @@ jobs:
ComfyUI_frontend
key: comfyui-setup-${{ needs.setup.outputs.cache-key }}
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- uses: actions/setup-python@v4
with:
python-version: '3.10'
+ cache: 'pip'
- name: Get current time
id: current-time
@@ -143,7 +168,7 @@ jobs:
comment-author: 'github-actions[bot]'
edit-mode: append
body: |
-
+
${{ matrix.browser }}: Running tests...
- name: Install requirements
@@ -160,12 +185,21 @@ jobs:
wait-for-it --service 127.0.0.1:8188 -t 600
working-directory: ComfyUI
+ - name: Cache Playwright browsers
+ uses: actions/cache@v4
+ with:
+ path: ~/.cache/ms-playwright
+ key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-${{ matrix.browser }}
+ restore-keys: |
+ playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-
+ playwright-browsers-${{ runner.os }}-
+
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Install Wrangler
- run: npm install -g wrangler
+ run: pnpm install -g wrangler
- name: Run Playwright tests (${{ matrix.browser }})
id: playwright
@@ -182,6 +216,7 @@ jobs:
- name: Deploy to Cloudflare Pages (${{ matrix.browser }})
id: cloudflare-deploy
if: always()
+ continue-on-error: true
run: |
# Retry logic for wrangler deploy (3 attempts)
RETRY_COUNT=0
diff --git a/.github/workflows/update-electron-types.yaml b/.github/workflows/update-electron-types.yaml
index 2430cf5e590..04d8cc436c3 100644
--- a/.github/workflows/update-electron-types.yaml
+++ b/.github/workflows/update-electron-types.yaml
@@ -14,19 +14,33 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- cache: 'npm'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ key: electron-types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ electron-types-tools-cache-${{ runner.os }}-
- name: Update electron types
- run: npm install @comfyorg/comfyui-electron-types@latest
+ run: pnpm install @comfyorg/comfyui-electron-types@latest
- name: Get new version
id: get-version
run: |
- NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./package-lock.json')).packages['node_modules/@comfyorg/comfyui-electron-types'].version)")
+ NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./pnpm-lock.yaml')).packages['node_modules/@comfyorg/comfyui-electron-types'].version)")
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
- name: Create Pull Request
diff --git a/.github/workflows/update-manager-types.yaml b/.github/workflows/update-manager-types.yaml
index 7933c7cbe2b..8f3bf6cdb11 100644
--- a/.github/workflows/update-manager-types.yaml
+++ b/.github/workflows/update-manager-types.yaml
@@ -19,14 +19,36 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- cache: 'npm'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ key: update-manager-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ update-manager-tools-cache-${{ runner.os }}-
- name: Install dependencies
- run: npm ci
+ run: pnpm install --frozen-lockfile
+
+ - name: Cache ComfyUI-Manager repository
+ uses: actions/cache@v4
+ with:
+ path: ComfyUI-Manager
+ key: comfyui-manager-repo-${{ runner.os }}-${{ github.run_id }}
+ restore-keys: |
+ comfyui-manager-repo-${{ runner.os }}-
- name: Checkout ComfyUI-Manager repository
uses: actions/checkout@v4
@@ -64,7 +86,7 @@ jobs:
- name: Lint generated types
run: |
echo "Linting generated ComfyUI-Manager API types..."
- npm run lint:fix:no-cache -- ./src/types/generatedManagerTypes.ts
+ pnpm lint:fix:no-cache -- ./src/types/generatedManagerTypes.ts
- name: Check for changes
id: check-changes
diff --git a/.github/workflows/update-registry-types.yaml b/.github/workflows/update-registry-types.yaml
index 39a653697ef..0cd2c41daea 100644
--- a/.github/workflows/update-registry-types.yaml
+++ b/.github/workflows/update-registry-types.yaml
@@ -18,14 +18,36 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- cache: 'npm'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ key: update-registry-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ update-registry-tools-cache-${{ runner.os }}-
- name: Install dependencies
- run: npm ci
+ run: pnpm install --frozen-lockfile
+
+ - name: Cache comfy-api repository
+ uses: actions/cache@v4
+ with:
+ path: comfy-api
+ key: comfy-api-repo-${{ runner.os }}-${{ github.run_id }}
+ restore-keys: |
+ comfy-api-repo-${{ runner.os }}-
- name: Checkout comfy-api repository
uses: actions/checkout@v4
@@ -64,7 +86,7 @@ jobs:
- name: Lint generated types
run: |
echo "Linting generated Comfy Registry API types..."
- npm run lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts
+ pnpm lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts
- name: Check for changes
id: check-changes
diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml
index 8e5f7042f63..77021e5c7c6 100644
--- a/.github/workflows/version-bump.yaml
+++ b/.github/workflows/version-bump.yaml
@@ -26,16 +26,21 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- cache: 'npm'
+ cache: 'pnpm'
- name: Bump version
id: bump-version
run: |
- npm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
+ pnpm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
NEW_VERSION=$(node -p "require('./package.json').version")
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/vitest.yaml b/.github/workflows/vitest.yaml
index 788b6aba4a3..cba1dbe0587 100644
--- a/.github/workflows/vitest.yaml
+++ b/.github/workflows/vitest.yaml
@@ -13,15 +13,34 @@ jobs:
steps:
- uses: actions/checkout@v4
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ coverage
+ .vitest-cache
+ key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }}
+ restore-keys: |
+ vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
+ vitest-cache-${{ runner.os }}-
+ test-tools-cache-${{ runner.os }}-
- name: Install dependencies
- run: npm ci
+ run: pnpm install --frozen-lockfile
- name: Run Vitest tests
run: |
- npm run test:component
- npm run test:unit
+ pnpm test:component
+ pnpm test:unit
diff --git a/.gitignore b/.gitignore
index 60cca8f981a..aa68ddd07aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,7 +10,6 @@ lerna-debug.log*
# Package manager lockfiles (allow users to use different package managers)
bun.lock
bun.lockb
-pnpm-lock.yaml
yarn.lock
# Cache files
@@ -77,3 +76,12 @@ vite.config.mts.timestamp-*.mjs
*storybook.log
storybook-static
+
+
+
+.nx/cache
+.nx/workspace-data
+.cursor/rules/nx-rules.mdc
+.github/instructions/nx.instructions.md
+vite.config.*.timestamp*
+vitest.config.*.timestamp*
diff --git a/.storybook/CLAUDE.md b/.storybook/CLAUDE.md
index a8a9371629b..3877181a23d 100644
--- a/.storybook/CLAUDE.md
+++ b/.storybook/CLAUDE.md
@@ -2,9 +2,9 @@
## Quick Commands
-- `npm run storybook`: Start Storybook development server
-- `npm run build-storybook`: Build static Storybook
-- `npm run test:component`: Run component tests (includes Storybook components)
+- `pnpm storybook`: Start Storybook development server
+- `pnpm build-storybook`: Build static Storybook
+- `pnpm test:component`: Run component tests (includes Storybook components)
## Development Workflow for Storybook
@@ -19,8 +19,8 @@
- Ensure proper theming and styling
3. **Code Quality**:
- - Run `npm run typecheck` to verify TypeScript
- - Run `npm run lint` to check for linting issues
+ - Run `pnpm typecheck` to verify TypeScript
+ - Run `pnpm lint` to check for linting issues
- Follow existing story patterns and conventions
## Story Creation Guidelines
@@ -138,13 +138,13 @@ The Storybook preview is configured with:
```bash
# Check TypeScript issues
-npm run typecheck
+pnpm typecheck
# Lint Storybook files
-npm run lint .storybook/
+pnpm lint .storybook/
# Build to check for production issues
-npm run build-storybook
+pnpm build-storybook
```
## File Organization
diff --git a/.storybook/README.md b/.storybook/README.md
index 902397471b9..0d34474ecd6 100644
--- a/.storybook/README.md
+++ b/.storybook/README.md
@@ -40,10 +40,10 @@ Storybook is a frontend workshop for building UI components and pages in isolati
```bash
# Start Storybook development server
-npm run storybook
+pnpm storybook
# Build static Storybook for deployment
-npm run build-storybook
+pnpm build-storybook
```
### Creating Stories
diff --git a/AGENTS.md b/AGENTS.md
index f01701cf44f..5cec6b8109b 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -8,19 +8,19 @@
- Config: `vite.config.mts`, `vitest.config.ts`, `playwright.config.ts`, `eslint.config.js`, `.prettierrc`.
## Build, Test, and Development Commands
-- `npm run dev`: Start Vite dev server.
-- `npm run dev:electron`: Dev server with Electron API mocks.
-- `npm run build`: Type-check then production build to `dist/`.
-- `npm run preview`: Preview the production build locally.
-- `npm run test:unit`: Run Vitest unit tests (`tests-ui/`).
-- `npm run test:component`: Run component tests (`src/components/`).
-- `npm run test:browser`: Run Playwright E2E tests (`browser_tests/`).
-- `npm run lint` / `npm run lint:fix`: Lint (ESLint). `npm run format` / `format:check`: Prettier.
-- `npm run typecheck`: Vue TSC type checking.
+- `pnpm dev`: Start Vite dev server.
+- `pnpm dev:electron`: Dev server with Electron API mocks.
+- `pnpm build`: Type-check then production build to `dist/`.
+- `pnpm preview`: Preview the production build locally.
+- `pnpm test:unit`: Run Vitest unit tests (`tests-ui/`).
+- `pnpm test:component`: Run component tests (`src/components/`).
+- `pnpm test:browser`: Run Playwright E2E tests (`browser_tests/`).
+- `pnpm lint` / `pnpm lint:fix`: Lint (ESLint). `pnpm format` / `format:check`: Prettier.
+- `pnpm typecheck`: Vue TSC type checking.
## Coding Style & Naming Conventions
- Language: TypeScript, Vue SFCs (`.vue`). Indent 2 spaces; single quotes; no semicolons; width 80 (see `.prettierrc`).
-- Imports: sorted/grouped by plugin; run `npm run format` before committing.
+- Imports: sorted/grouped by plugin; run `pnpm format` before committing.
- ESLint: Vue + TS rules; no floating promises; unused imports disallowed; i18n raw text restrictions in templates.
- Naming: Vue components in PascalCase (e.g., `MenuHamburger.vue`); composables `useXyz.ts`; Pinia stores `*Store.ts`.
@@ -33,7 +33,7 @@
## Commit & Pull Request Guidelines
- Commits: Prefer Conventional Commits (e.g., `feat(ui): add sidebar`), `refactor(litegraph): …`. Use `[skip ci]` for locale-only updates when appropriate.
- PRs: Include clear description, linked issues (`Fixes #123`), and screenshots/GIFs for UI changes. Add/adjust tests and i18n strings when applicable.
-- Quality gates: `npm run lint`, `npm run typecheck`, and relevant tests must pass. Keep PRs focused and small.
+- Quality gates: `pnpm lint`, `pnpm typecheck`, and relevant tests must pass. Keep PRs focused and small.
## Security & Configuration Tips
- Secrets: Use `.env` (see `.env_example`); do not commit secrets.
diff --git a/CLAUDE.md b/CLAUDE.md
index 2e15e3b17d7..922d1f8531c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,13 +2,13 @@
## Quick Commands
-- `npm run`: See all available commands
-- `npm run typecheck`: Type checking
-- `npm run lint`: Linting
-- `npm run format`: Prettier formatting
-- `npm run test:component`: Run component tests with browser environment
-- `npm run test:unit`: Run all unit tests
-- `npm run test:unit -- tests-ui/tests/example.test.ts`: Run single test file
+- `pnpm`: See all available commands
+- `pnpm typecheck`: Type checking
+- `pnpm lint`: Linting
+- `pnpm format`: Prettier formatting
+- `pnpm test:component`: Run component tests with browser environment
+- `pnpm test:unit`: Run all unit tests
+- `pnpm test:unit -- tests-ui/tests/example.test.ts`: Run single test file
## Development Workflow
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c25dc96741d..83b1951bc78 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,7 +17,7 @@ Have another idea? Drop into Discord or open an issue, and let's chat!
### Prerequisites & Technology Stack
- **Required Software**:
- - Node.js (v16 or later; v20/v22 strongly recommended) and npm
+ - Node.js (v16 or later; v24 strongly recommended) and pnpm
- Git for version control
- A running ComfyUI backend instance
@@ -39,7 +39,7 @@ Have another idea? Drop into Discord or open an issue, and let's chat!
2. Install dependencies:
```bash
- npm install
+ pnpm install
```
3. Configure environment (optional):
@@ -57,13 +57,13 @@ python main.py --port 8188
### Git pre-commit hooks
-Run `npm run prepare` to install Git pre-commit hooks. Currently, the pre-commit hook is used to auto-format code on commit.
+Run `pnpm prepare` to install Git pre-commit hooks. Currently, the pre-commit hook is used to auto-format code on commit.
### Dev Server
- Start local ComfyUI backend at `localhost:8188`
-- Run `npm run dev` to start the dev server
-- Run `npm run dev:electron` to start the dev server with electron API mocked
+- Run `pnpm dev` to start the dev server
+- Run `pnpm dev:electron` to start the dev server with electron API mocked
#### Access dev server on touch devices
@@ -155,7 +155,7 @@ For ComfyUI_frontend development, you can ask coding assistants to use Playwrigh
##### Setup for Claude Code
-After installing dependencies with `npm i`, the Playwright MCP server will be automatically available when you start Claude Code locally.
+After installing dependencies with `pnpm i`, the Playwright MCP server will be automatically available when you start Claude Code locally.
Here's how Claude Code can use the Playwright MCP server to inspect the interface of the local development server (assuming you're running the dev server at `localhost:5173`):
@@ -210,14 +210,14 @@ Here's how Claude Code can use the Playwright MCP server to inspect the interfac
### Unit Tests
-- `npm i` to install all dependencies
-- `npm run test:unit` to execute all unit tests
+- `pnpm i` to install all dependencies
+- `pnpm test:unit` to execute all unit tests
### Component Tests
Component tests verify Vue components in `src/components/`.
-- `npm run test:component` to execute all component tests
+- `pnpm test:component` to execute all component tests
### Playwright Tests
@@ -228,12 +228,12 @@ Playwright tests verify the whole app. See [browser_tests/README.md](browser_tes
Before submitting a PR, ensure all tests pass:
```bash
-npm run test:unit
-npm run test:component
-npm run test:browser
-npm run typecheck
-npm run lint
-npm run format
+pnpm test:unit
+pnpm test:component
+pnpm test:browser
+pnpm typecheck
+pnpm lint
+pnpm format
```
## Code Style Guidelines
@@ -265,7 +265,7 @@ The project supports three types of icons, all with automatic imports (no manual
2. **Iconify Icons** - 200,000+ icons from various libraries: ``, ``
3. **Custom Icons** - Your own SVG icons: ``
-Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `src/assets/icons/custom/`.
+Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `src/assets/icons/custom/` and processed by `build/customIconCollection.ts` with automatic validation.
For detailed instructions and code examples, see [src/assets/icons/README.md](src/assets/icons/README.md).
diff --git a/browser_tests/tests/selectionToolbox.spec.ts b/browser_tests/tests/selectionToolbox.spec.ts
index 90568e3aa04..ce45eb3fbff 100644
--- a/browser_tests/tests/selectionToolbox.spec.ts
+++ b/browser_tests/tests/selectionToolbox.spec.ts
@@ -43,7 +43,7 @@ test.describe('Selection Toolbox', () => {
const boundingBox = await toolboxContainer.boundingBox()
expect(boundingBox).not.toBeNull()
// Canvas-based positioning can vary, just verify toolbox appears in reasonable bounds
- expect(boundingBox!.x).toBeGreaterThan(-100) // Not too far off-screen left
+ expect(boundingBox!.x).toBeGreaterThan(-200) // Not too far off-screen left
expect(boundingBox!.x).toBeLessThan(1000) // Not too far off-screen right
expect(boundingBox!.y).toBeGreaterThan(-100) // Not too far off-screen top
})
diff --git a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-nodes-border-chromium-linux.png b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-nodes-border-chromium-linux.png
index 12215637fd1..5ebf2600940 100644
Binary files a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-nodes-border-chromium-linux.png and b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-nodes-border-chromium-linux.png differ
diff --git a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-selections-border-chromium-linux.png b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-selections-border-chromium-linux.png
index a2d11d35034..5ebf2600940 100644
Binary files a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-selections-border-chromium-linux.png and b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-multiple-selections-border-chromium-linux.png differ
diff --git a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-single-selection-no-border-chromium-linux.png b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-single-selection-no-border-chromium-linux.png
index 8017b8f49d6..89ddf1b9b72 100644
Binary files a/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-single-selection-no-border-chromium-linux.png and b/browser_tests/tests/selectionToolbox.spec.ts-snapshots/selection-toolbox-single-selection-no-border-chromium-linux.png differ
diff --git a/build/customIconCollection.js b/build/customIconCollection.js
deleted file mode 100644
index ae52b97ae0c..00000000000
--- a/build/customIconCollection.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { readFileSync, readdirSync } from 'fs'
-import { join } from 'path'
-import { dirname } from 'path'
-import { fileURLToPath } from 'url'
-
-const fileName = fileURLToPath(import.meta.url)
-const dirName = dirname(fileName)
-const customIconsPath = join(dirName, '..', 'src', 'assets', 'icons', 'custom')
-
-// Create an Iconify collection for custom icons
-export const iconCollection = {
- prefix: 'comfy',
- icons: {},
- width: 16,
- height: 16
-}
-
-// Read all SVG files from the custom icons directory
-const files = readdirSync(customIconsPath)
-files.forEach((file) => {
- if (file.endsWith('.svg')) {
- const name = file.replace('.svg', '')
- const content = readFileSync(join(customIconsPath, file), 'utf-8')
-
- iconCollection.icons[name] = {
- body: content
- }
- }
-})
diff --git a/build/customIconCollection.ts b/build/customIconCollection.ts
new file mode 100644
index 00000000000..f2d823ed5d8
--- /dev/null
+++ b/build/customIconCollection.ts
@@ -0,0 +1,100 @@
+import { existsSync, readFileSync, readdirSync } from 'fs'
+import { join } from 'path'
+import { dirname } from 'path'
+import { fileURLToPath } from 'url'
+
+const fileName = fileURLToPath(import.meta.url)
+const dirName = dirname(fileName)
+const customIconsPath = join(dirName, '..', 'src', 'assets', 'icons', 'custom')
+
+// Iconify collection structure
+interface IconifyIcon {
+ body: string
+ width?: number
+ height?: number
+}
+
+interface IconifyCollection {
+ prefix: string
+ icons: Record
+ width?: number
+ height?: number
+}
+
+// Create an Iconify collection for custom icons
+export const iconCollection: IconifyCollection = {
+ prefix: 'comfy',
+ icons: {},
+ width: 16,
+ height: 16
+}
+
+/**
+ * Validates that an SVG file contains valid SVG content
+ */
+function validateSvgContent(content: string, filename: string): void {
+ if (!content.trim()) {
+ throw new Error(`Empty SVG file: ${filename}`)
+ }
+
+ if (!content.includes('