Section 5/131 menit

5. Tuist — Konfigurasi dan Penggunaan

5. Tuist — Konfigurasi dan Penggunaan

Instalasi

swift
# Install Tuist via mise (direkomendasikan)
mise install tuist
mise use tuist@latest

# Atau via curl
curl -Ls https://install.tuist.io | bash

Struktur Project Tuist

swift
MyApp/
├── Tuist/                    ← konfigurasi Tuist
│   ├── Config.swift          ← global config
│   ├── ProjectDescriptionHelpers/  ← helper yang di-share
│   │   └── Project+Templates.swift
│   └── Package.swift         ← SPM dependencies
├── Projects/                 ← definisi modules
│   ├── App/
│   │   └── Project.swift
│   ├── NetworkKit/
│   │   └── Project.swift
│   └── FeatureHome/
│       └── Project.swift
└── Workspace.swift           ← workspace root

Config.swift

swift
// Tuist/Config.swift
import ProjectDescription

let config = Config(
    compatibleXcodeVersions: .list(["16.0", "16.1", "16.2"]),
    swiftVersion: "6.0"
)

ProjectDescriptionHelpers — Reusable Templates

swift
// Tuist/ProjectDescriptionHelpers/Project+Templates.swift
import ProjectDescription

public extension Target {

    static func featureTarget(
        name: String,
        dependencies: [TargetDependency] = [],
        additionalSources: [SourceFileGlob] = []
    ) -> Target {
        .target(
            name: name,
            destinations: .iOS,
            product: .framework,
            bundleId: "com.company.\(name.lowercased())",
            deploymentTargets: .iOS("17.0"),
            sources: ["Sources/**"] + additionalSources,
            resources: ["Resources/**"],
            dependencies: dependencies,
            settings: .settings(
                base: [
                    "SWIFT_VERSION": "6.0",
                    "SWIFT_STRICT_CONCURRENCY": "complete",
                ]
            )
        )
    }

    static func testTarget(for targetName: String) -> Target {
        .target(
            name: "\(targetName)Tests",
            destinations: .iOS,
            product: .unitTests,
            bundleId: "com.company.\(targetName.lowercased()).tests",
            sources: ["Tests/**"],
            dependencies: [.target(name: targetName)]
        )
    }
}

public extension Project {

    static func feature(
        name: String,
        dependencies: [TargetDependency] = []
    ) -> Project {
        let mainTarget = Target.featureTarget(
            name: name,
            dependencies: dependencies
        )
        let testTarget = Target.testTarget(for: name)

        return Project(
            name: name,
            targets: [mainTarget, testTarget]
        )
    }
}

Workspace.swift — Root Definitions

swift
// Workspace.swift
import ProjectDescription

let workspace = Workspace(
    name: "MyApp",
    projects: [
        "Projects/App",
        "Projects/NetworkKit",
        "Projects/SharedUI",
        "Projects/FeatureHome",
        "Projects/FeatureProfile",
        "Projects/FeatureSettings",
    ]
)

Project.swift per Module

swift
// Projects/FeatureHome/Project.swift
import ProjectDescription
import ProjectDescriptionHelpers

// Cukup satu baris untuk mendefinisikan seluruh feature module
let project = Project.feature(
    name: "FeatureHome",
    dependencies: [
        .project(target: "NetworkKit", path: "../NetworkKit"),
        .project(target: "SharedUI", path: "../SharedUI"),
        .external(name: "Alamofire"),
    ]
)

Package.swift untuk External Dependencies

swift
// Tuist/Package.swift
// @preconcurrency import — Tuist menggunakan format SPM yang dimodifikasi
import PackageDescription

#if TUIST
import ProjectDescriptionHelpers
import ProjectDescription

let packageSettings = PackageSettings(
    productTypes: [
        "Alamofire": .framework,
        "SnapKit": .framework,
    ]
)
#endif

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire", from: "5.9.0"),
        .package(url: "https://github.com/SnapKit/SnapKit", from: "5.7.0"),
        .package(url: "https://github.com/pointfreeco/swift-composable-architecture", from: "1.15.0"),
    ]
)

Tuist Cache

swift
# Build semua external dependencies sebagai XCFramework (sekali)
tuist cache

# Generate project menggunakan cached binaries
tuist generate
# → Dependencies sudah pre-built, hanya first-party code yang dikompilasi

# Lihat status cache
tuist cache --print-hashes

# Clean cache
tuist clean dependencies

Penggunaan Sehari-hari

swift
# Generate workspace (jalankan setelah perubahan Project.swift)
tuist generate

# Build tanpa buka Xcode
tuist build MyApp

# Run test
tuist test MyApp

# Graph visualization — lihat dependency graph
tuist graph
# Buka MyApp.png yang di-generate

# Lint project definitions (deteksi masalah sebelum generate)
tuist inspect implicit-imports