Skip to content

Find a better way to work on Saga and its plugins in tandem #24

@kevinrenskers

Description

@kevinrenskers
Member

Working on #22 means having to change Saga and all the readers in one go, and with them all being in separate repositories, that's a hassle. For example when I work on the SagaParsleyMarkdownReader project, that's depending on the "live" Saga project, so I can't make changes in tandem. While I could change the Package.swift file every time I work on a plugin to instead depend on the local version of Saga, this is pretty burdensome to keep doing, and if I'd accidentally commit that, that would be bad.

A monorepo that contains Saga and all the plugins and a big example project that can make use of all these different plugins would be ideal, something like this Package.swift in a monorepo:

// swift-tools-version:5.5

import PackageDescription

let package = Package(
  name: "Saga",
  platforms: [
    .macOS(.v12)
  ],
  products: [
    .library(name: "Saga", targets: ["Saga"]),
    .executable(name: "watch", targets: ["SagaCLI"]),
    .library(name: "SagaParsleyMarkdownReader", targets: ["SagaParsleyMarkdownReader"]),
    .library(name: "SagaSwimRenderer", targets: ["SagaSwimRenderer"]),
    .library(name: "SagaInkMarkdownReader", targets: ["SagaInkMarkdownReader"]),
    .library(name: "SagaPythonMarkdownReader", targets: ["SagaPythonMarkdownReader"]),
    .library(name: "SagaStencilRenderer", targets: ["SagaStencilRenderer"]),
  ],
  dependencies: [
    .package(url: "https://github.com/kylef/PathKit", from: "1.0.1"),
    .package(url: "https://github.com/JohnSundell/Codextended.git", from: "0.1.0"),
    .package(name: "Parsley", url: "https://github.com/loopwerk/Parsley", from: "0.6.0"),
    .package(name: "HTML", url: "https://github.com/robb/Swim", from: "0.3.0"),
    .package(name: "Ink", url: "https://github.com/johnsundell/ink.git", from: "0.5.0"),
    .package(name: "Splash", url: "https://github.com/JohnSundell/Splash", from: "0.16.0"),
    .package(name: "SwiftMarkdown", url: "https://github.com/loopwerk/SwiftMarkdown", from: "0.4.0"),
    .package(name: "Stencil", url: "https://github.com/stencilproject/Stencil", from: "0.14.0"),
  ],
  targets: [
    .target(
      name: "Saga",
      dependencies: ["PathKit", "Codextended"]
    ),
    .executableTarget(
      name: "SagaCLI",
      dependencies: ["PathKit"]
    ),
    .testTarget(
      name: "SagaTests",
      dependencies: ["Saga"]
    ),
    .target(
      name: "SagaParsleyMarkdownReader",
      dependencies: ["Saga", "Parsley"]
    ),
    .target(
      name: "SagaSwimRenderer",
      dependencies: ["Saga", "HTML"]
    ),
    .target(
      name: "SagaInkMarkdownReader",
      dependencies: ["Saga", "Ink", "Splash"]
    ),
    .target(
      name: "SagaPythonMarkdownReader",
      dependencies: ["Saga", "SwiftMarkdown"]
    ),
    .target(
      name: "SagaStencilRenderer",
      dependencies: ["Saga", "Stencil"]
    ),
  ]
)

Sadly though if someone would only use the Saga and SagaSwimRenderer packages in their Swift project, all the other dependencies (like Ink and Splash and Stencil etc) are still downloaded, even though they are not used by that person's project. I think they're not being compiled so at least it's not super horrible, but the unnecessary download is still problematic, especially as more plugins with their own big dependencies get added in the future.

A second (but smaller) problem is that all the targets would share the same version. So when I make a new release because of a small update in Saga, all the plugins would show as being updates as well.

Apollo wrote about this exact same problem, and they ended up using git subtrees, see this article: https://www.apollographql.com/blog/how-apollo-manages-swift-packages-in-a-monorepo-with-git-subtrees. It seems rather complex though.

Activity

kevinrenskers

kevinrenskers commented on Feb 18, 2025

@kevinrenskers
MemberAuthor

I thought I'd be smart and use symlinks but sadly Xcode doesn't follow symlinks :(

Image

So instead I created a brand new Swift package on my computer:

// swift-tools-version:5.5

import PackageDescription

let package = Package(
  name: "Mono",
  platforms: [
    .macOS(.v12)
  ],
  dependencies: [
    .package(path: "../Saga/"),
    .package(path: "../SagaInkMarkdownReader/"),
    .package(path: "../SagaParsleyMarkdownReader/"),
    .package(path: "../SagaPythonMarkdownReader/"),
    .package(path: "../SagaStencilRenderer/"),
    .package(path: "../SagaSwimRenderer/"),
  ],
  targets: [
    .executableTarget(
      name: "Mono",
      dependencies: [
        "Saga",
        "SagaInkMarkdownReader",
        "SagaParsleyMarkdownReader",
        "SagaPythonMarkdownReader",
        "SagaStencilRenderer",
        "SagaSwimRenderer",
      ]
    ),
  ]
)

This allows me to make changes in Saga, try to run the project, and see all the compiler error in all the plugins immediately. This is already a big improvement!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @kevinrenskers

        Issue actions

          Find a better way to work on Saga and its plugins in tandem · Issue #24 · loopwerk/Saga