XcodeGraphGenerator – A Tool to Visualize Tuist/Xcode Project Dependencies

Hi all,

I’m excited to introduce XcodeGraphGenerator, a Swift-based tool designed to help visualize Xcode project dependencies by generating interactive graphs. This tool parses Xcode projects and packages, then builds a directed acyclic graph (DAG) of the dependencies, which can be viewed via a web interface powered by Cytoscape.js. The entire backend is built using SwiftNIO, making it lightweight and efficient for serving the generated project graph.

Check out the live demo here.

Why This Could Fit into TuistCLI

I believe XcodeGraphGenerator could be a valuable addition to TuistCLI, providing visual insights into the structure of Xcode projects. This feature could complement Tuist’s goal of simplifying project management by giving developers a visual representation of target, package, and framework dependencies.

I decided it should Tuist-agnostic—similar to the XcodeGraph package it depends on—so that it can be useful to any Swift/Xcode project, not just those using Tuist.

That said, I’m more than happy to discuss how this could be adapted or integrated into the Tuist ecosystem if there is interest from the team.

Key Features:

  • Parses Xcode projects and packages with XcodeGraph to build a comprehensive graph.
  • Generates a directed acyclic graph (DAG) representing project dependencies.
  • Serves the graph over HTTP using SwiftNIO and visualizes it through Cytoscape.js.
  • Fully cross-platform (macOS, Linux, and Windows support).
  • Can be extended to support advanced project structures and dependencies.

Integration with TuistCLI

I can see potential for this tool to integrate with TuistCLI, allowing users to generate dependency graphs from the command line. Although it’s currently Tuist-agnostic, the core functionality could certainly complement Tuist’s feature set, the graph command could easily have a -i flag and use the XcodeGraph alreadyh available there.

Possible Enhancements

  • Watch the manifest somehow and hot reload
  • Change manifest through web interface (ie static vs dynamic)

How to Get Started:

  1. Clone the repository: XcodeGraphGenerator GitHub
  2. Build and run the tool using Swift Package Manager.
  3. Visualize your project’s dependencies via a local web server at http://localhost:8081.

Open to Collaboration and Feedback

I would love to collaborate with the community and the Tuist team to see how this tool can be improved or adapted to fit within TuistCLI. Please feel free to explore the project, provide feedback, or contribute. If Tuist is interested in taking over this project or integrating it officially, I’m happy to support that process.

Thanks, and I look forward to hearing your thoughts!

2 Likes

@ajkolean just WOW :open_mouth: . We’ve been dreaming of building this feature into Tuist. Congrats on the excellent craft that you’ve done there.

I’m personally on board with the idea of bringing this feature into the tuist graph command when passing the -i flag. Would you like to take a stab at integrating it? Since you are already using XcodeGraph as the object, you can reuse the existing loading logic in that command and hook your additional logic. How does it sound?

Would you be interested in working with @asmit on improving the design of it? He’s leading the design efforts of Tuist and would be able to give you a hand.

Once again, amazing work @ajkolean.

What an impressive piece of work @ajkolean :clap:

I’m personally on board with the idea of bringing this feature into the tuist graph command when passing the -i flag

I’d even considering making it a default. The default experience of generating an image is not really good enough for most large-scale projects.

I really love that the client-side is implemented with purely JS and CSS – this will also allow us to use this outside of the Tuist CLI on our server. I’d like to model the client-side code to be an HTML web component that can be easily installed u

This is super cool! Awesome work @ajkolean ! I have continually relied on the tuist graph feature as our project has grown in size but having it interactive will help the entire team better grasp all the moving parts.

I tried it on our project but couldn’t get it going, I’ve made an issue I hope I can help you resolve. :+1:

@pepicrft Thanks for the feedback! And yeah, I’m very much a developer—and not a web one—so any design feedback would be greatly appreciated.

@marekfort Great idea! This is just a POC right now and still has a lot of cleanup to do, but I envision separating the web code into an HTML module and converting it to use Tailwind CSS and TypeScript. With that structure, the CLI wouldn’t need any additional dependencies—it would simply spin up a local server with a basic HTML string that loads the module dynamically. But I am pretty far out of my depths in the JS world so maybe there is a better setup.

@kelvinharron Replied to your GH issue but just for visibility this requires some slight tweaks to the cli output of the json to output XcdoeGraph instead of a ProjectAutomation one.

1 Like

converting it to use Tailwind CSS and TypeScript

Our philosophy on the server is to use only HTLM and CSS, so I would advise against that. Not relying on Tailwind and Typescript makes the solution easier to use in arbitrary contexts on the web with minimal size footprint :crossed_fingers:

Curious if you considered using d3 instead of cytoscape.js to drive the graph? FWIW, both are good, flexible libraries, so mostly wondering if there was a specific thinking behind choosing cytoscape.js. The reason why I’m asking about d3 – I really like the force-graph behavior like this one, built on top of d3-force. It’s almost certainly possible to achieve the same behavior with cytoscape.js, but from what I’ve seen, d3 generally seems to be a more popular choice with a richer ecosystem.

There is also a similar library to force-graph but for a 3D graph – while we don’t need 3D, I’m mentioning it because I like the styling of it.

@ajkolean, I’d also consider writing an RFC that would focus more on how this would play with the Tuist CLI, as that’s something we definitely want. No need to be too specific, the RFC should stay relatively high level. There are some examples in the GitHub discussions that we no longer actively use

@marekfort I was thinking of hosting the compiled HTML module on a CDN. This way, the CLI would remain super lightweight, only needing to serve a basic HTML string that dynamically loads the precompiled module. The benefit is that this approach would allow the component to be used anywhere. For example, you could just include it like this on the server:

<xcode-graph-component data-url="graph.json"></xcode-graph-component>

It keeps things simple for users without adding any extra dependencies or build steps on their end.

Does this even make sense? Again really been a long time since web development.

Regarding Cytoscape.js, I initially chose it because it was faster to get started with for this POC, but I completely agree that D3 offers more flexibility and customization, especially for things like force-directed graphs. I’m open to exploring D3 if it makes sense for future iterations.

I was thinking of hosting the compiled HTML module on a CDN.

Yes, this is a good approach!

For example, you could just include it like this on the server:

I believe we can skip Tuist running a server. You can save the index.html into a temporary directory and open that file directly in the browser. tuist graph would then not block the current CLI session.

The index.html could look something like:

<html>
  <head>
   // Script to load the web component
   <scrpt>window.graph = {/* ... */} // Serialized version of the graph, inserted by the CLI when `tuist graph` is run</scrpt>
  </head>
  <body>
     <xcode-graph/>
  </body>
</html>

As a follow-up, that can’t be implemented directly in the tuist/tuist repo, we are also thinking of adding tuist graph --share option. We’d upload the graph to the Tuist server and serve it at cloud.tuist.io. This would enable you to share the graph with your teammates or the community.

Regarding Cytoscape.js, I initially chose it because it was faster to get started with for this POC, but I completely agree that D3 offers more flexibility and customization, especially for things like force-directed graphs. I’m open to exploring D3 if it makes sense for future iterations.

Gotcha! I’d then lean to using D3 instead.

Exactly! The goal would be it could be used anywhere. Just create html file with a few lines to register and load the component.

Seems we are aligned implementation wise. I will throw together a RFC as you mentioned before. And start looking into D3.

1 Like

Hey, very nice work. One question I see in tuist the branch Grapher with persisting the internal graph, not the currently external one. When developing the signing plugin https://github.com/apps4everyone/tuist-plugin-signing I asked this but was not allowed. Is there now any (breaking) change planned? @pepicrft @ajkolean

Welcome to the forum @apps4everyone :wave:

I’m not entirely sure I follow the question. Would you mind rephrasing it?

Hey @pepicrft tested the XcodeGraphGenerator but it only work’s right now with the change graph json like in this branch:
https://github.com/tuist/tuist/compare/main...grapher

The XcodeGraph is a library meant for consumption outside of just tuist/tuist and its usage is recommended.

@apps4everyone Sorry for the delay been quite busy. That repo is not the final I have RFC to create on my backlog. The current command outputs a ProjectAutomationGraph for json and it needs XcodeGraph. (That branch was just a lazy modification to output it). A breaking change won’t be required, but more to come when I can get something together and feedback.

thx for the info, yes noticed the change from ProjectAutomationGraph to XcodeGraph

Any other feedback so far? will this be continued and somehow released?

@ajkolean created an RFC here. If you have feedback, let’s move the discussion there :slightly_smiling_face: