How Vite+ Handles Task Dependency Resolution with the Topological Flag in Monorepos

Vite+ automatically resolves task dependencies in monorepos by building a directed workspace graph from package.json relationships and applying topological sorting to ensure dependencies execute before dependents when running commands with --recursive or --filter.

The voidzero-dev/vite-plus toolchain introduces sophisticated task orchestration for JavaScript monorepos through its topological dependency resolution system. When executing commands across multiple packages, Vite+ analyzes workspace relationships defined in package.json to determine the optimal execution order. This ensures that build artifacts from dependency packages are available before dependent packages begin their tasks.

Workspace Graph Construction and Implicit Dependencies

Vite+ builds a workspace graph that represents each package as a node and the package.json relationships (dependencies, devDependencies, peerDependencies, etc.) as directed edges. When a command is run with --recursive or --filter, Vite+ must decide in which order to execute the selected packages.

Implicit Dependencies in Topological Mode

When the topological flag is enabled (the default for recursive runs), every workspace-to-workspace dependency edge is converted into an implicit task dependency. According to the project documentation in CLAUDE.md (lines 46-53), if package A depends on package B, then A#build automatically depends on B#build.

This behavior ensures that:

  • Build tasks in dependency packages complete before downstream packages start
  • Dev dependencies are prepared before their consumers execute
  • Peer dependency constraints are respected during task execution

Default Topological Ordering for Recursive Commands

When executing vp exec -r … or vp run -r …, Vite+ automatically applies topological ordering. The RFC documented in rfcs/exec-command.md (lines 11-19) specifies that the topological sort uses petgraph::algo::toposort on the FilterResolution.package_subgraph, ensuring that dependencies are executed before dependents.

Implementation of the Topological Sort Algorithm

The core resolution logic resides in packages/cli/binding/src/exec/workspace.rs, where Vite+ implements a robust sorting mechanism with cycle detection.

Building the Workspace Graph

The function vite_workspace::load_package_graph constructs a DiGraphMap<PackageNodeIndex, ()> that stores all packages and their intra-workspace dependency edges. This directed graph serves as the foundation for all subsequent topological operations.

Subgraph Extraction and Filtering

After the user applies filters (--recursive, --filter, or defaults to the current package), the FilterResolution struct contains a package_subgraph field. This subgraph includes only the selected nodes and the edges relevant to those nodes, allowing targeted execution within large monorepos.

The topological_sort_packages Function

The critical sorting logic appears in lines 321-335 of workspace.rs. The topological_sort_packages function implements a two-phase approach:

fn topological_sort_packages(subgraph: &DiGraphMap<PackageNodeIndex, ()>) -> Vec<PackageNodeIndex> {
    match petgraph::algo::toposort(subgraph, None) {
        Ok(mut sorted) => {
            sorted.reverse();            // deps-first order
            sorted
        }
        Err(_cycle) => {
            // Fallback for cycles – SCCs in reverse topological order
            petgraph::algo::tarjan_scc(subgraph).into_iter().flatten().collect()
        }
    }
}

The function first attempts petgraph::algo::toposort, which returns nodes in dependents-first order. Vite+ reverses this list to ensure dependencies appear first. If the graph contains a cycle, the algorithm falls back to Tarjan's strongly-connected-components algorithm, yielding SCCs in reverse topological order to preserve correct dependencies-first ordering for everything outside the cycle.

Handling Circular Dependencies

When toposort detects a cycle, Vite+ does not fail. Instead, it uses petgraph::algo::tarjan_scc to identify strongly connected components. The RFC documentation explains that this preserves a correct dependencies-first order for acyclic portions of the graph, while the intra-cycle order is left arbitrary since no linear order can satisfy a circular dependency.

CLI Flags for Execution Order Control

Vite+ provides several flags to override the default topological behavior when running tasks across multiple packages.

Running Tasks in Parallel

The --parallel flag (defined in packages/cli/binding/src/exec/args.rs) skips topological ordering entirely and spawns all selected packages concurrently. This is useful for tasks that do not depend on build artifacts, though output may be interleaved:


# Execute command in all packages simultaneously

vp exec -r --parallel -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

Reverse Topological Order

The --reverse flag reverses the computed topological order, causing dependents to execute before their dependencies. This is particularly useful for cleanup or teardown scripts:


# Run dependents first, then dependencies

vp exec -r --reverse -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

Disabling Implicit Dependencies

The --no-topological flag (available on vp run commands) disables the creation of implicit dependencies from package.json relationships. When used, only explicit task dependencies defined in vite-task.json are honored:


# Ignore workspace dependencies, use only vite-task.json dependsOn

vp run build -r --no-topological

Practical Examples

The following commands demonstrate common topological execution patterns in Vite+ monorepos:


# Run a command in every workspace package, respecting package.json deps

vp exec -r -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

# Packages are invoked in dependency-first order (e.g., lib → app)

# Reverse the order – useful for teardown scripts

vp exec -r --reverse -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

# Dependents run first, then their dependencies

# Execute in parallel – ignore topological order

vp exec -r --parallel -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

Summary

  • Vite+ constructs a directed workspace graph from package.json dependencies to model package relationships.
  • The topological_sort_packages function in packages/cli/binding/src/exec/workspace.rs uses petgraph::algo::toposort to establish a dependencies-first execution order.
  • When cycles are detected, the system falls back to Tarjan's SCC algorithm to maintain correct ordering for acyclic portions of the graph.
  • The --recursive flag enables topological ordering by default, while --parallel, --reverse, and --no-topological provide explicit control over execution semantics.
  • Implicit task dependencies are automatically derived from workspace package relationships unless explicitly disabled.

Frequently Asked Questions

What happens when Vite+ detects a circular dependency in the workspace?

When petgraph::algo::toposort detects a cycle in the workspace graph, Vite+ falls back to petgraph::algo::tarjan_scc as implemented in packages/cli/binding/src/exec/workspace.rs. This algorithm identifies strongly connected components and emits them in reverse topological order, preserving correct dependencies-first ordering for packages outside the cycle while handling the circular portion as a single unit.

How does the topological flag interact with explicit task dependencies in vite-task.json?

The topological flag creates implicit dependencies based on package.json relationships, while vite-task.json defines explicit dependencies through the dependsOn field. By default, both are respected. However, using --no-topological on vp run commands disables implicit dependencies, causing Vite+ to honor only the explicit dependsOn entries defined in vite-task.json.

Can I run dependent packages before their dependencies in Vite+?

Yes. Passing the --reverse flag to vp exec or vp run reverses the topological order, causing dependents to execute before their dependencies. This is useful for cleanup tasks, cache invalidation, or any operation where you need to process packages in the opposite direction of their dependency graph.

Does topological sorting apply to all Vite+ commands by default?

No. Topological sorting is automatically applied only when using --recursive (-r) or --filter flags that select multiple packages. Single-package execution does not trigger the topological sort. Additionally, you can explicitly disable topological ordering with --parallel (for concurrent execution) or --no-topological (to ignore workspace dependencies).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →