- 
                Notifications
    You must be signed in to change notification settings 
- Fork 393
Description
Circular Dependency Issue with verbatimModuleSyntax
We've encountered a blocking issue when enabling TypeScript's verbatimModuleSyntax option. The strict import/export requirements expose circular dependencies that were previously hidden:
The Problem
With verbatimModuleSyntax enabled:
- Type imports must use import type { ... }syntax
- Values and types cannot be mixed in the same import statement
- This stricter separation reveals circular dependencies between modules
Actual Runtime Failure
When running tests with Vitest, we encounter runtime errors that demonstrate the circular dependency problem:
FAIL  tests-ui/tests/store/bottomPanelStore.test.ts
TypeError: Class extends value undefined is not a constructor or null
 ❯ src/lib/litegraph/src/subgraph/EmptySubgraphInput.ts:14:41
     12|  * A virtual slot that simply creates a new input slot when connected …
     13|  */
     14| export class EmptySubgraphInput extends SubgraphInput {
       |                                         ^
     15|   declare parent: SubgraphInputNode
     16| 
 ❯ src/lib/litegraph/src/canvas/LinkConnector.ts:4:31
This error occurs because SubgraphInput is undefined at the time EmptySubgraphInput tries to extend it, indicating a circular dependency in the module initialization order.
The Circular Import Chain
Starting from EmptySubgraphInput.ts:
- 
EmptySubgraphInput.ts - Line 8: import { SubgraphInput } from './SubgraphInput'
- Line 14: export class EmptySubgraphInput extends SubgraphInput
 
- Line 8: 
- 
SubgraphInput.ts - Line 16: import type { SubgraphInputNode } from './SubgraphInputNode'
- Line 18: import { SubgraphSlot } from './SubgraphSlotBase'
- Line 32: export class SubgraphInput extends SubgraphSlot
 
- Line 16: 
- 
SubgraphInputNode.ts - Line 5: import type { LinkConnector } from '@/lib/litegraph/src/canvas/LinkConnector'
- Line 19: import { EmptySubgraphInput } from './EmptySubgraphInput'
- Line 30: Creates EmptySubgraphInputinstance
 
- Line 5: 
- 
LinkConnector.ts - Line 20: import { EmptySubgraphInput } from '@/lib/litegraph/src/subgraph/EmptySubgraphInput'
- Line 24: import { SubgraphInputNode } from '@/lib/litegraph/src/subgraph/SubgraphInputNode'
 
- Line 20: 
The Cycle:
EmptySubgraphInput → SubgraphInput → SubgraphInputNode → EmptySubgraphInput
                                    ↓                    ↑
                                LinkConnector ──────────┘
When modules are loaded:
- LinkConnectorimports- EmptySubgraphInput
- EmptySubgraphInputtries to extend- SubgraphInput
- SubgraphInputneeds- SubgraphInputNode(for type)
- SubgraphInputNodeneeds- EmptySubgraphInput(creates instance)
- But EmptySubgraphInputis still being defined, causingSubgraphInputto be undefined
Additional Circular Dependencies Found
- 
LiteGraph Internal Structure - Subgraphclass extends- LGraph(in LGraph.ts)
- Multiple files import both Subgraphand components that depend on it
- Temporary workaround exists: Subgraph.tsre-exports fromLGraph.ts
 
- 
ComfyApp ↔ LiteGraph - src/scripts/app.tsexports- ComfyAppclass
- Various files import from both @comfyorg/litegraphandComfyApp
- LiteGraph extensions depend on ComfyApptypes
- ComfyAppdepends on LiteGraph types
 
- 
Component Registry Circular References - Component index files export types
- Components import from their own index for type definitions
- Creates self-referential loops
 
Why This Matters
- Build failures: TypeScript cannot resolve the import order
- Runtime crashes: Even if TypeScript compiles, the circular dependencies cause runtime initialization failures
- Test failures: Vitest cannot properly initialize modules with circular dependencies
- Maintenance burden: The codebase architecture needs refactoring to properly separate concerns
Recommended Solution
Before enabling verbatimModuleSyntax, we should:
- 
Break the SubgraphInput cycle: - Option A: Extract EmptySubgraphInputto not extendSubgraphInputdirectly
- Option B: Use lazy initialization for the emptySlotinSubgraphInputNode
- Option C: Restructure the inheritance hierarchy to avoid the cycle
 
- Option A: Extract 
- 
Fix LiteGraph internal structure: - Resolve circular dependencies within the LiteGraph library
- Ensure proper initialization order for class hierarchies
- Separate type definitions from implementations
 
- 
Refactor module structure to eliminate circular dependencies: - Extract shared types to separate type-only modules
- Use dependency injection patterns where appropriate
- Consider facade patterns for complex module interactions
 
- 
Create abstraction layers: - Define interfaces in separate files from implementations
- Use type-only exports for shared contracts
- Implement proper layering (core → features → UI)
 
- 
Gradual migration: - Fix circular dependencies module by module
- Enable verbatimModuleSyntaxper module once clean
- Eventually enable project-wide
 
This refactoring would improve the codebase architecture beyond just TypeScript compliance - it would make the code more maintainable and testable.
Current Status
The branch has partial fixes for type imports, but the circular dependency issue blocks full implementation. The runtime errors in tests confirm this is not just a TypeScript compilation issue but a fundamental module structure problem that needs architectural refactoring.
Originally posted by @snomiao in #5533 (comment)
┆Issue is synchronized with this Notion page by Unito