Skip to content

Conversation

@LittleSound
Copy link
Collaborator

@LittleSound LittleSound commented Nov 13, 2025

This pull request implements an on-demand import system for core extensions, with initial adaptations for Three.js-related extensions.

Overview

The new system introduces a configuration-based approach to manage extension loading, replacing the previous synchronous import-all pattern with an event-driven lazy loading mechanism.

Key Features

1. Configuration-Based Extension Loading

Each extension now defines its loading behavior through a comfy.ext.config.ts file:

export default defineComfyExtConfig({
  name: 'Comfy.Load3D',
  activationEvents: ['onWidgets:contributes', 'onCommands:contributes', 'onSettings:contributes'],
  contributes: [
    {
      name: 'Comfy.Load3D',
      widgets: ['LOAD_3D'],
      settings: [...],
      commands: [...]
    }
  ]
})

2. Event-Driven Loading System

Extensions are loaded on-demand based on activation events:

  • * - Load immediately on startup
  • onWidgets:contributes - Load when widget contributions are needed
  • onCommands:contributes - Load when command contributions are needed
  • onSettings:contributes - Load when settings contributions are needed

3. Automatic Extension Discovery

Using Vite's import.meta.glob, the system automatically discovers extensions without maintaining manual import lists:

  • Config files are eagerly loaded for metadata
  • Extension entry files are lazily loaded on demand

Benefits

  • Reduced Initial Bundle Size: Large dependencies like Three.js are no longer included in the main bundle
  • Faster Startup Time: Only essential extensions load immediately
  • Better Code Splitting: Vite can optimize chunks based on actual usage patterns
  • Improved Maintainability: No manual import list maintenance required

Adapted Extensions

The following extensions have been migrated to the new system:

  • load3d - 3D model loading and preview (Three.js-dependent)
  • saveMesh - 3D mesh export functionality
  • cloudBadges - Cloud subscription badges
  • cloudRemoteConfig - Remote configuration polling
  • cloudSessionCookie - Cloud session management
  • cloudSubscription - Subscription features
  • cloudFeedbackTopbarButton - Feedback button

Future Work

  1. Pre-register Commands: Register command metadata from config files before loading the extension, then import the extension only when the command is invoked
  2. Pre-register Keybindings: Similar approach for keyboard shortcuts
  3. Pre-register Settings: Load settings UI metadata upfront while deferring the actual implementation

Technical Details

  • Config files use eager import with import: 'default' for optimal tree-shaking
  • Extension entry files use lazy import via dynamic import()
  • Event-based dispatch system ensures each extension loads exactly once
  • Cloud-specific extensions support conditional loading based on environment and subscription status

┆Issue is synchronized with this Notion page by Unito

@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Nov 13, 2025
@github-actions
Copy link

github-actions bot commented Nov 13, 2025

🎭 Playwright Test Results

Some tests failed

⏰ Completed at: 11/14/2025, 01:47:36 AM UTC

📈 Summary

  • Total Tests: 498
  • Passed: 464 ✅
  • Failed: 1 ❌
  • Flaky: 3 ⚠️
  • Skipped: 30 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 455 / ❌ 1 / ⚠️ 3 / ⏭️ 30
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Nov 13, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 11/14/2025, 01:37:18 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Nov 13, 2025

Bundle Size Report

Summary

  • Raw size: 13.7 MB baseline 13.6 MB — 🔴 +78.5 kB
  • Gzip: 2.75 MB baseline 2.72 MB — 🔴 +28.1 kB
  • Brotli: 2.17 MB baseline 2.14 MB — 🔴 +26.6 kB
  • Bundles: 118 current • 89 baseline • 68 added / 39 removed

Category Glance
App Entry Points 🔴 +70.9 kB (3.01 MB) · Other 🔴 +7.65 kB (3.93 MB) · Vendor & Third-Party ⚪ 0 B (5.32 MB) · Graph Workspace ⚪ 0 B (799 kB) · Panels & Settings ⚪ 0 B (306 kB) · UI Components ⚪ 0 B (266 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.01 MB (baseline 2.94 MB) • 🔴 +70.9 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-AwPTwhzb.js (new) 2.55 MB 🔴 +2.55 MB 🔴 +537 kB 🔴 +409 kB
assets/index-4zurlI3-.js (removed) 2.55 MB 🟢 -2.55 MB 🟢 -536 kB 🟢 -408 kB
assets/index-D0n0TeQC.js (removed) 386 kB 🟢 -386 kB 🟢 -77.9 kB 🟢 -63.1 kB
assets/index-Dt6c-gII.js (new) 198 kB 🔴 +198 kB 🔴 +37 kB 🔴 +30.1 kB
assets/index-CuRFgnQx.js (new) 63.8 kB 🔴 +63.8 kB 🔴 +14 kB 🔴 +12.3 kB
assets/index-CFPudQou.js (new) 18.8 kB 🔴 +18.8 kB 🔴 +4.94 kB 🔴 +4.39 kB
assets/index-B8lFzS1Q.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.2 kB 🔴 +3.65 kB
assets/index-BfV9UNmp.js (new) 16.5 kB 🔴 +16.5 kB 🔴 +3.29 kB 🔴 +2.85 kB
assets/index-BFaTqN4j.js (new) 14.7 kB 🔴 +14.7 kB 🔴 +3.86 kB 🔴 +3.37 kB
assets/index-D3iLMOUX.js (new) 13.1 kB 🔴 +13.1 kB 🔴 +3.21 kB 🔴 +2.78 kB
assets/index-Dj8aM5GG.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +2.85 kB 🔴 +2.46 kB
assets/index-B3h1C8OO.js (new) 10.1 kB 🔴 +10.1 kB 🔴 +2.57 kB 🔴 +2.23 kB
assets/index-BUNRuFNt.js (new) 7.7 kB 🔴 +7.7 kB 🔴 +1.51 kB 🔴 +1.32 kB
assets/index-DQ0IuI7J.js (new) 7.15 kB 🔴 +7.15 kB 🔴 +1.88 kB 🔴 +1.62 kB
assets/index-CfMYYCAN.js (new) 7.01 kB 🔴 +7.01 kB 🔴 +2.01 kB 🔴 +1.7 kB
assets/index-Dohy3cPw.js (new) 7.01 kB 🔴 +7.01 kB 🔴 +1.94 kB 🔴 +1.66 kB
assets/index-DAE59TCF.js (new) 6.72 kB 🔴 +6.72 kB 🔴 +2.11 kB 🔴 +1.83 kB
assets/index-BqRlxgNC.js (new) 6.36 kB 🔴 +6.36 kB 🔴 +1.91 kB 🔴 +1.66 kB
assets/index-B18C6BoO.js (new) 6.22 kB 🔴 +6.22 kB 🔴 +2.13 kB 🔴 +1.81 kB
assets/index-Cx7c_IHX.js (new) 4.98 kB 🔴 +4.98 kB 🔴 +1.51 kB 🔴 +1.31 kB
assets/index-BJ7qB_VH.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.36 kB 🔴 +1.22 kB
assets/index-DnGrQo8K.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.09 kB 🔴 +929 B
assets/index-jvlqUON5.js (new) 3.28 kB 🔴 +3.28 kB 🔴 +1.05 kB 🔴 +918 B
assets/index-m4BQEFet.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.04 kB 🔴 +884 B
assets/index-C62SCtwP.js (new) 3.04 kB 🔴 +3.04 kB 🔴 +1.04 kB 🔴 +884 B
assets/index-Dw93gVz6.js (new) 2.92 kB 🔴 +2.92 kB 🔴 +937 B 🔴 +790 B
assets/index-BRiH8TAO.js (new) 2.9 kB 🔴 +2.9 kB 🔴 +854 B 🔴 +722 B
assets/index-Eq7Ro7lK.js (new) 2.58 kB 🔴 +2.58 kB 🔴 +840 B 🔴 +698 B
assets/index-ByhrYgdM.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +915 B 🔴 +767 B
assets/index-KvERLJIn.js (new) 2.49 kB 🔴 +2.49 kB 🔴 +791 B 🔴 +679 B
assets/index-DX5ye0iN.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +781 B 🔴 +664 B
assets/index-gHD4EknA.js (new) 2.23 kB 🔴 +2.23 kB 🔴 +735 B 🔴 +623 B
assets/index-Cap6YZr9.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +574 B 🔴 +483 B
assets/index-VBAHuVuH.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -576 B 🟢 -489 B
assets/index-B4QLtcLP.js (new) 345 B 🔴 +345 B 🔴 +246 B 🔴 +233 B
assets/index-CuOq7Asd.js (removed) 345 B 🟢 -345 B 🟢 -245 B 🟢 -236 B

Status: 32 added / 4 removed

Graph Workspace — 799 kB (baseline 799 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-D0FF51Ey.js (removed) 799 kB 🟢 -799 kB 🟢 -156 kB 🟢 -120 kB
assets/GraphView-Hx6X7X9f.js (new) 799 kB 🔴 +799 kB 🔴 +156 kB 🔴 +120 kB

Status: 1 added / 1 removed

Views & Navigation — 8 kB (baseline 8 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-IceF5SD4.js (removed) 8 kB 🟢 -8 kB 🟢 -2.43 kB 🟢 -2.13 kB
assets/UserSelectView-kCGLEsYP.js (new) 8 kB 🔴 +8 kB 🔴 +2.43 kB 🔴 +2.13 kB

Status: 1 added / 1 removed

Panels & Settings — 306 kB (baseline 306 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-cH7MmydR.js (new) 22.9 kB 🔴 +22.9 kB 🔴 +5.43 kB 🔴 +4.76 kB
assets/CreditsPanel-yG7ZlpGd.js (removed) 22.9 kB 🟢 -22.9 kB 🟢 -5.43 kB 🟢 -4.75 kB
assets/KeybindingPanel-Dcd3SaXC.js (new) 15.1 kB 🔴 +15.1 kB 🔴 +3.73 kB 🔴 +3.29 kB
assets/KeybindingPanel-DgI8eDzO.js (removed) 15.1 kB 🟢 -15.1 kB 🟢 -3.73 kB 🟢 -3.28 kB
assets/ExtensionPanel-BXM0UCMT.js (new) 11.9 kB 🔴 +11.9 kB 🔴 +2.79 kB 🔴 +2.44 kB
assets/ExtensionPanel-jjrzg2B9.js (removed) 11.9 kB 🟢 -11.9 kB 🟢 -2.79 kB 🟢 -2.45 kB
assets/AboutPanel-CgPK0hiY.js (removed) 10.1 kB 🟢 -10.1 kB 🟢 -2.62 kB 🟢 -2.32 kB
assets/AboutPanel-FHFgO0fW.js (new) 10.1 kB 🔴 +10.1 kB 🔴 +2.63 kB 🔴 +2.3 kB
assets/ServerConfigPanel-aY60ZLic.js (new) 8.05 kB 🔴 +8.05 kB 🔴 +2.12 kB 🔴 +1.88 kB
assets/ServerConfigPanel-Ds3Zh43u.js (removed) 8.05 kB 🟢 -8.05 kB 🟢 -2.12 kB 🟢 -1.87 kB
assets/UserPanel-Cehkb38L.js (new) 7.76 kB 🔴 +7.76 kB 🔴 +2.02 kB 🔴 +1.77 kB
assets/UserPanel-COd5nV6z.js (removed) 7.76 kB 🟢 -7.76 kB 🟢 -2.02 kB 🟢 -1.77 kB
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 266 kB (baseline 266 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-CLBpgz8F.js (removed) 185 kB 🟢 -185 kB 🟢 -31.9 kB 🟢 -25.9 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-Q4HQwb68.js (new) 185 kB 🔴 +185 kB 🔴 +31.9 kB 🔴 +25.9 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-B1DQ1KiJ.js (new) 47.9 kB 🔴 +47.9 kB 🔴 +10.4 kB 🔴 +9.01 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-C1Tc0tcq.js (removed) 47.9 kB 🟢 -47.9 kB 🟢 -10.4 kB 🟢 -9.04 kB
assets/ComfyQueueButton-B0BUEkMR.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -2.78 kB 🟢 -2.46 kB
assets/ComfyQueueButton-opYUq6Gp.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +2.78 kB 🔴 +2.46 kB
assets/WidgetSelectButton-7rxrctiy.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.94 kB 🟢 -1.7 kB
assets/WidgetSelectButton-BuJSQ28G.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.94 kB 🔴 +1.7 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-6dfFKvB0.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -809 B 🟢 -707 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-Fe9oTWtj.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +812 B 🔴 +707 B
assets/LazyImage.vue_vue_type_script_setup_true_lang-CYFSl-yC.js 10.7 kB 10.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-D2s8tnS2.js 1.26 kB 1.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-ByrPd5jr.js 1.62 kB 1.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Data & Services — 12.6 kB (baseline 12.6 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-AXGMJdz0.js (removed) 7.6 kB 🟢 -7.6 kB 🟢 -1.84 kB 🟢 -1.59 kB
assets/keybindingService-Bcrq49Us.js (new) 7.6 kB 🔴 +7.6 kB 🔴 +1.84 kB 🔴 +1.58 kB
assets/serverConfigStore-CKc7RoFy.js (new) 2.79 kB 🔴 +2.79 kB 🔴 +891 B 🔴 +780 B
assets/serverConfigStore-CSC1Jwyz.js (removed) 2.79 kB 🟢 -2.79 kB 🟢 -890 B 🟢 -774 B
assets/audioService-BjP9xA91.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -961 B 🟢 -827 B
assets/audioService-HK8HyVXN.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +963 B 🔴 +823 B

Status: 3 added / 3 removed

Utilities & Hooks — 5.87 kB (baseline 5.87 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-AAJkJ3Nt.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -651 B 🟢 -546 B
assets/audioUtils-C7cEfLwX.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +548 B
assets/mathUtil-CTARWQ-l.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useTransformCompatOverlayProps-YaCpDdzr.js 486 B 486 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useWidgetValue-IC6pgigJ.js 2.45 kB 2.45 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 5.32 MB (baseline 5.32 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-CVXrkfGT.js (new) 3.22 MB 🔴 +3.22 MB 🔴 +685 kB 🔴 +549 kB
assets/vendor-other-DC3ww4lS.js (removed) 3.22 MB 🟢 -3.22 MB 🟢 -684 kB 🟢 -549 kB
assets/vendor-tiptap-D_Aa50m_.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-tiptap-D5vdTa2Y.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-vue-BXFQnYFV.js (new) 92.6 kB 🔴 +92.6 kB 🔴 +23.9 kB 🔴 +20.8 kB
assets/vendor-vue-C80SsSPi.js (removed) 92.6 kB 🟢 -92.6 kB 🟢 -23.9 kB 🟢 -20.8 kB
assets/vendor-primevue-PESgPnbc.js 517 B 517 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 3 added / 3 removed

Other — 3.93 MB (baseline 3.92 MB) • 🔴 +7.65 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-0fTjSIxG.js (removed) 22.1 kB 🟢 -22.1 kB 🟢 -5.57 kB 🟢 -4.92 kB
assets/WidgetRecordAudio-CrVJ3Y32.js (new) 22.1 kB 🔴 +22.1 kB 🔴 +5.58 kB 🔴 +4.92 kB
assets/AudioPreviewPlayer-BB29eDqf.js (new) 14.9 kB 🔴 +14.9 kB 🔴 +3.71 kB 🔴 +3.32 kB
assets/AudioPreviewPlayer-BJlivRbW.js (removed) 14.9 kB 🟢 -14.9 kB 🟢 -3.71 kB 🟢 -3.31 kB
assets/WidgetInputNumber-D5iZDU86.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.77 kB 🟢 -3.35 kB
assets/WidgetInputNumber-J0vtwLi2.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.77 kB 🔴 +3.35 kB
assets/Load3DConfiguration-Chq3OY3j.js (new) 7.65 kB 🔴 +7.65 kB 🔴 +2.08 kB 🔴 +1.85 kB
assets/WidgetGalleria-BCJjasmq.js (new) 5.59 kB 🔴 +5.59 kB 🔴 +1.74 kB 🔴 +1.54 kB
assets/WidgetGalleria-sFRXLc6P.js (removed) 5.59 kB 🟢 -5.59 kB 🟢 -1.74 kB 🟢 -1.53 kB
assets/WidgetColorPicker-BLkG1c-m.js (new) 4.87 kB 🔴 +4.87 kB 🔴 +1.67 kB 🔴 +1.46 kB
assets/WidgetColorPicker-C3OZdh2r.js (removed) 4.87 kB 🟢 -4.87 kB 🟢 -1.67 kB 🟢 -1.46 kB
assets/WidgetMarkdown-DQU1CxJ8.js (removed) 4.85 kB 🟢 -4.85 kB 🟢 -1.69 kB 🟢 -1.46 kB
assets/WidgetMarkdown-kylB9x7j.js (new) 4.85 kB 🔴 +4.85 kB 🔴 +1.69 kB 🔴 +1.46 kB
assets/WidgetAudioUI-BAoLaX3_.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.48 kB 🔴 +1.33 kB
assets/WidgetAudioUI-BHebKTYh.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.48 kB 🟢 -1.32 kB
assets/WidgetMultiSelect-Cu14efow.js (new) 4.26 kB 🔴 +4.26 kB 🔴 +1.44 kB 🔴 +1.26 kB
assets/WidgetMultiSelect-D8xdTt_a.js (removed) 4.26 kB 🟢 -4.26 kB 🟢 -1.44 kB 🟢 -1.26 kB
assets/WidgetTreeSelect-BFILnFR8.js (new) 3.99 kB 🔴 +3.99 kB 🔴 +1.36 kB 🔴 +1.2 kB
assets/WidgetTreeSelect-C39Z07nA.js (removed) 3.99 kB 🟢 -3.99 kB 🟢 -1.36 kB 🟢 -1.2 kB
assets/WidgetTextarea-BpqVNiy5.js (new) 3.7 kB 🔴 +3.7 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetTextarea-D_lOaiuH.js (removed) 3.7 kB 🟢 -3.7 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetInputText-CKNz1BoX.js (new) 3.62 kB 🔴 +3.62 kB 🔴 +1.26 kB 🔴 +1.11 kB
assets/WidgetInputText-DECIpvLz.js (removed) 3.62 kB 🟢 -3.62 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/WidgetToggleSwitch-C-_gPOL2.js (removed) 3.49 kB 🟢 -3.49 kB 🟢 -1.21 kB 🟢 -1.06 kB
assets/WidgetToggleSwitch-TVO6YGNp.js (new) 3.49 kB 🔴 +3.49 kB 🔴 +1.21 kB 🔴 +1.06 kB
assets/WidgetSelect-BqdtAul1.js (removed) 2.29 kB 🟢 -2.29 kB 🟢 -718 B 🟢 -614 B
assets/WidgetSelect-V-vP2n35.js (new) 2.29 kB 🔴 +2.29 kB 🔴 +720 B 🔴 +617 B
assets/Load3D-BQQA918H.js (removed) 2.01 kB 🟢 -2.01 kB 🟢 -608 B 🟢 -509 B
assets/Load3D-CeWQ0L7m.js (new) 2.01 kB 🔴 +2.01 kB 🔴 +608 B 🔴 +516 B
assets/WidgetLegacy-DGyFwAdc.js (new) 1.91 kB 🔴 +1.91 kB 🔴 +558 B 🔴 +501 B
assets/WidgetLegacy-DqbnhA8j.js (removed) 1.91 kB 🟢 -1.91 kB 🟢 -557 B 🟢 -496 B
assets/commands-_6uSNVYB.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BaAvtVOT.js 14.7 kB 14.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BRKOlMPq.js 15.4 kB 15.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-C1kmJUO0.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CHLkz7NH.js 17.4 kB 17.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-cLsDwHMQ.js 14 kB 14 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ct50VUT9.js 16.2 kB 16.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DOEnM922.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ds4Sq2CW.js 15.7 kB 15.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BjHbZI-o.js 97.5 kB 97.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BsmSUEg9.js 75.9 kB 75.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C1dqVsBC.js 103 kB 103 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CTcPPkuZ.js 87.4 kB 87.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CwX98cQA.js 89.7 kB 89.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DFyT7zKX.js 84.8 kB 84.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DHvyJYQT.js 74.9 kB 74.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-ruI2u5eb.js 118 kB 118 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-UdMyOcTd.js 86.4 kB 86.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-_Px5dSNW.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-7z21KPoS.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BWKZzBPK.js 346 kB 346 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CGbgH4Yl.js 320 kB 320 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CjjjdWkV.js 313 kB 313 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CVrNtxvj.js 288 kB 288 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DLRSA0IK.js 309 kB 309 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DQV2gnwA.js 372 kB 372 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ofqLG5vz.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-4dlndULn.js 2.44 kB 2.44 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetFileUpload-Cx6dGznS.js 11.9 kB 11.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-Ds3K3ULR.js 2.15 kB 2.15 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 16 added / 15 removed

Copy link
Collaborator

@jtydhr88 jtydhr88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a quick test on my local, the model list dropdown on vueNodes for load3d doesn't work after this refactor:
image
but it is working well before this refactor

@christian-byrne christian-byrne added the claude-review Add to trigger a PR code review from Claude Code label Nov 13, 2025
@@ -0,0 +1,73 @@
import type { ComfyExtension } from '@/types'

// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[quality] medium Priority

Issue: Using eslint-disable comment to suppress TypeScript function type rule rather than providing proper type annotation
Context: The line disables the no-unsafe-function-type rule which is designed to catch potentially unsafe function type usage
Suggestion: Replace with explicit Function type annotation or use more specific function signature type

extension.config
)
activationEvents.forEach((event) =>
onceExtImportEvent(event, async () => void (await extension.entry()))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[architecture] high Priority

Issue: No error handling for extension entry point execution in dispatchComfyExtensions
Context: Line 30 uses void operator to suppress Promise rejection warnings, but doesn't handle actual errors that could crash the extension loading system
Suggestion: Add proper error handling with try-catch and logging to prevent individual extension failures from affecting the entire system

export async function importExtensionsByEvent(event: string) {
const callbacks = eventMap.get(event)
if (!callbacks) return
eventMap.delete(event)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[architecture] high Priority

Issue: Race condition in importExtensionsByEvent - event map is deleted before callbacks complete execution
Context: Line 42 deletes the event from the map immediately, but callbacks are executed asynchronously with Promise.all which could cause issues if the same event is triggered again before completion
Suggestion: Move eventMap.delete(event) to after the Promise.all completes to prevent race conditions

await Promise.all([...callbacks].map((cb) => cb({ event })))
}

export function extentionsImportEventHas(event: string) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[quality] low Priority

Issue: Typo in function name extentionsImportEventHas - missing 's' in 'extensions'
Context: Function name has spelling error which affects code readability and consistency
Suggestion: Rename to extensionsImportEventHas to fix the typo

const pkgs: ComfyExtensionPackages = {}
for (const [entryPath, entry] of Object.entries(entrance)) {
const pathArr = entryPath.split('/')
const name = pathArr.at(-2)!
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[quality] medium Priority

Issue: Using non-null assertion with .at(-2) without proper null check
Context: Line 22 uses ! to assert the name exists but .at(-2) can return undefined if array has less than 2 elements
Suggestion: Add proper null check and error handling before using non-null assertion to prevent runtime errors

import './webcamCapture'
import './widgetInputs'
export async function registerExtensions() {
console.log('importExtensions running...')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[quality] medium Priority

Issue: Debug console.log left in production code
Context: Line 5 contains debugging statement that should be removed from production code
Suggestion: Remove the console.log or replace with proper logging system that can be disabled in production

}
}

;(async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[performance] high Priority

Issue: Async IIFE with Promise.all could block widget creation flow and create race conditions
Context: Lines 88-92 create widgets asynchronously while sync widgets are created immediately, potentially causing UI inconsistencies and timing issues
Suggestion: Consider using a more structured approach like a callback system or ensuring proper ordering between sync and async widget creation


import { useExtensionService } from './extensionService'
import {
extentionsImportEventHas,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[quality] low Priority

Issue: Same typo in import - extentionsImportEventHas should be extensionsImportEventHas
Context: The typo from dispatch.ts is imported here, propagating the naming inconsistency
Suggestion: Fix the typo when the original function is renamed in dispatch.ts

import { defineComfyExtConfig } from '@/extensions/utils'

export default defineComfyExtConfig({
name: 'Comfy.SaveGLB',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[architecture] medium Priority

Issue: Inconsistent naming pattern between config name and contributes name
Context: Config has name 'Comfy.SaveGLB' but contributes section has same name, while other configs like load3d use different names for different contributions
Suggestion: Consider using a more descriptive pattern like 'Comfy.SaveMesh' to match the actual functionality and be consistent with the load3d pattern

return isCloud
},
get subscriptionRequired() {
return !!window.__CONFIG__?.subscription_required
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[security] medium Priority

Issue: Direct access to global window.CONFIG object for subscription validation
Context: Line 14 accesses window.CONFIG?.subscription_required which could be manipulated by client-side code to bypass subscription checks
Suggestion: Ensure subscription validation is also performed server-side and this client-side check is only used for UI behavior, not security enforcement

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comprehensive PR Review

This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.

Review Summary

PR: refactor: core extension on-demand import (#6675)
Impact: 540 additions, 125 deletions across 95 files

Issue Distribution

  • Critical: 0
  • High: 2
  • Medium: 6
  • Low: 2

Category Breakdown

  • Architecture: 4 issues
  • Security: 1 issues
  • Performance: 1 issues
  • Code Quality: 4 issues

Key Findings

Architecture & Design

This PR introduces a significant architectural change implementing on-demand extension loading with configuration-based activation events. The new system replaces synchronous imports with event-driven lazy loading, which should improve initial bundle size and startup time. However, several issues were identified:

  1. Error Handling: The extension loading system lacks proper error handling, which could cause cascading failures
  2. Race Conditions: The event dispatch system has a potential race condition where events are deleted before callbacks complete
  3. Widget Loading Flow: The async widget loading implementation could create UI inconsistencies

Security Considerations

The security review identified one medium-priority concern regarding client-side subscription validation. The system relies on window.CONFIG.subscription_required which could be manipulated by client-side code. This should only be used for UI behavior, not actual security enforcement.

Performance Impact

The performance analysis found one high-priority issue with the widget loading system using async IIFEs that could block the UI creation flow. The mixing of synchronous and asynchronous widget creation could lead to timing issues and inconsistent user experience.

Integration Points

The new system integrates well with the existing Vite build system using import.meta.glob for dynamic extension discovery. The configuration-based approach provides good separation of concerns between extension metadata and implementation.

Positive Observations

  • Clean Architecture: The new config-based approach provides clear separation between extension metadata and implementation
  • Build Optimization: Using eager imports for configs and lazy imports for extensions should improve bundle splitting
  • Type Safety: Strong TypeScript typing throughout the new extension system
  • Cloud Integration: Thoughtful handling of cloud-only extensions with proper conditional loading

References

Next Steps

  1. Address high-priority race condition and performance issues before merge
  2. Add comprehensive error handling to extension loading system
  3. Fix naming typos throughout the codebase
  4. Consider adding integration tests for the new extension loading system
  5. Update documentation to reflect the new extension architecture

This is a comprehensive automated review focusing on architecture, security, performance, and code quality. For architectural decisions requiring human judgment, please request additional manual review.

@github-actions github-actions bot removed the claude-review Add to trigger a PR code review from Claude Code label Nov 13, 2025
@DrJKL DrJKL force-pushed the rizumu/refactor/on-demand-loading-extension branch from ee4ed1b to 40dd82c Compare November 14, 2025 01:35
@LittleSound
Copy link
Collaborator Author

Hi @DrJKL . what changes did you make?

@DrJKL
Copy link
Contributor

DrJKL commented Nov 14, 2025

Hi @DrJKL . what changes did you make?

Just rebasing onto main

@LittleSound
Copy link
Collaborator Author

Just rebasing onto main

Why. Did something happen to the main branch?

@DrJKL
Copy link
Contributor

DrJKL commented Nov 14, 2025

Just rebasing onto main

Why. Did something happen to the main branch?

A healthy number of merges today, including some fixes for some of the tests, yeah

@LittleSound
Copy link
Collaborator Author

Understood. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants