Exploring fixing a user-experience pain point with Swift - docs and requiring an explicit package dependency to support its easy use

I feel the developer experience for creating and viewing documentation associated with Swift packages has a severe stumbling point in that the developer-friendly commands — "generate-documentation" and "preview-documentation" — are bound behind a Swift Package Manager command plugin. While "docc" is available in the toolchain directly, it is a "driver" command, meaning that it was designed with constrained inputs that you need to coordinate and orchestrate ahead of time.

The DocC tooling today uses contents from the Package manifest, as well as symbolgraphs - JSON files provided by the Swift compiler, or which can be extracted or created, which is the case for DocC's Snippets support. This happens as a part of swift-docc-plugin, where it wrangles the relevant execution and provides the nicer developer experience.

Current pain points

(1) The means of getting access to the symbol graphs - to coordinate either their creation or retrieval - is currently arranged through the Package Plugin API. This API hasn't yet been updated to support asserting traits to enable when retrieving symbol graphs, which has the side effect that it's been rather obnoxiously difficult to generate documentation for the additional API that's backed behind a non-default trait in a package.

(2) In order to get the command plugin available, you must have the package as a dependency of your Swift package, which adds to the time to sync, resolve, etc - enough so that quite a few packages simply refuse to add it, or bake its availability in the dependency list behind having an environment variable set, or some equivalent hack. Other solutions, including Swift Package Index, make a simple run at attempting to parse the Package.swift and add it temporarily in order to generate documentation - but that process doesn't uniformly work consistently.

Possible solutions

(A) In my ideal world, I’d like to see a “swift docs” that "does the right thing” for a developer experience, and is available with the toolchain as it's shipped. Chris McGee suggested this in a pitch thread back in November. I wanted to reinforce that and ask us to explore it a bit more.

To enable such a solution today I can see several possible paths:

  • Convert swift-docc-plugin to use SwiftPM (or a library exposed from it) as a dependency to wrangle its orchestration needs, continue to support its use as a "command plugin" while also adding a CLI that can be independently invoked - and then include it within the packages that we build as part of the toolchain.
  • Adding a new package that can be included in the toolchain builds that provides the same functionality as swift-docc-plugin, but configured to operate as a standalone CLI, and leverages Swift Package Manager through some API - likely a dependency - to allow it to do the Package introspection and symbol graph retrieval orchestration that it would need to do, invoking the docc driver command to completion.
  • Another solution is to extend in Swift Package Manager with a new "command" (akin to swift build or swift test).

One of the arguments for not including this in the toolchain earlier is the dependencies that this package has today: the "preview-documentation" relies on SwiftNIO, which has a cascading issue of expanding the dependencies needed within the toolchain. I'll also note that Swift Package Manager has fairly significantly constrained dependencies as well, especially as a key component in bootstrapping the creation of the toolchain.

(B) If we want to keep with using this as a Package Manager command plugin, having some means of loading default plugins so that a package doesn't need to include it may be a reasonable path. I made a pitch with this concept in 2024, which seemed possible, although not without its own complications. The plugin would still require SwiftPM to maintain a plugin API structure and plumb it appropriately, but we could potentially have a “local plugin” installation directory that could house something like swift-docc-plugin, or equivalent Swift command extension points.

Questions to answer

These raise high level questions for Swift as a toolchain. I view them as:

  • What and how can we expand the commands that we include by default in a shipped Swift toolchain? What do they need to support, and what constraints do we have in including them?
  • How can we enable building on top of what the toolchain provides, vending libraries and API (Package Manager, DocC, or others) appropriately, without requiring all of that code to be built in the toolchain?
  • What kind of developer experience do we want for the "Swift CLI" - commands included when we ship a toolchain - and how do we want to manage driver executables vs. better developer experience in using those commands?

My goal in reviving these topics is to find an acceptable path to improve the developer experience for documentation:

  • Supporting and enabling easier generation of docs - something akin to swift docs rather than swift package generate-documentation, or at least not mandating that every package add a dependency in order to easily generate docs.
  • Enabling full traits support when generating documentation.
  • Expanding support for including more content into the documentation such as DocC's snippets feature, which relies on that orchestration and creating symbolgraphs from Swift source files.
  • Enabling the documentation-to-markdown capability to be assembled, maybe cached, and retrieved using CLI commands
5 Likes

Thanks for bringing up this topic. I personally think that documentation generation and previewing is a fundamental tooling need. Requiring users to take multiple steps to get this functionality creates too much friction. I would love to see docs building and previewing natively integrated with the Swift Package Manager.

1 Like

I echo what @FranzBusch said. I would like to see a first class support for documentation generation, documentation viewing, and possibly other documentation functions I'm not aware of.

Having this support means that any Swift code or package would have documentation, even if it's only the public API's. Package authors should not need to take any action other than invoking the command (generate, view, etc..) they want for the documentation they want.

This would be great. Two more items on my wish list (if not implemented already):

  • Ability co customize styles (fonts, colors, indents, etc.)
  • Ability to generate static HTML (no JavaScript) - think about Help Books and .chm files.