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