Swift Package Manager, How to add a package as development dependency?

Viewed 1580

Is there a way, to add a spm package as development dependency?

For example, is there a way we can do some thing like, developmentDependencies: { somePackage }.

(like we can easily achieved in other package managers like npm, pub, etc?)

3 Answers

Actually, I can confirm1 at as of Swift 5.2 this is possible. SE-0226 defines "Target Based Dependency Resolution", which basically means that SPM will only download the dependencies that are actually required by the target(s) you use.

For example:

// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SwiftlySearch",
    platforms: [
        .iOS(.v13)
    ],
    products: [
        .library(
            name: "SwiftlySearch",
            targets: ["SwiftlySearch"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/nalexn/ViewInspector.git", from: "0.4.3")
    ],
    targets: [
        .target(
            name: "SwiftlySearch",
            dependencies: []
        ),
        .testTarget(
            name: "SwiftlySearchTests",
            dependencies: ["SwiftlySearch", "ViewInspector"]
        ),
    ]
)

This will only download ViewInspector for the target "SwiftlySearchTests", and not for the released library SwiftlySearch.

TL;DR: Just declare dependencies only on the targets that use them, SPM will figure out the rest.


1 I just tested this using the built-in package manager in Xcode 11.6, which behaved as expected.

No, there currently is not. It's something I've seen discussed a few times on the Swift Evolution forums, it's something I'd like, and I actually thought I had seen some news about it happening, but alas, no.

The "best" way to get the same effect as of right now is to comment out your dev dependencies when doing release builds. There's a tool called Rocket that includes the hiding of dev dependencies as part of its release steps. I haven't used it, though, as I chose to write my own scripts instead. My example is my project DiceKit, where the Package.swift file does not include dev dependencies, and when my CI needs those dependencies, I run an include_dev_dependencies.py script before testing and a remove_dev_dependencies.py after testing.

This approach is definitely not ideal, and may not work for you, but I hope you can figure something out. Good luck!

    .target(
        name: “MyDemoApp",
        dependencies: [
            .product(name: "jsonlogic", package: "json-logic-swift")
        ]),

had to declare the import name as well as the package name

Related