Azimjon Abdurasulov

01. Kirish va O'rnatish

🚀 Tuist — Mukammal Qo‘llanma & Amaliyot

Tuist 01: Kirish va o'rnatish — Tuist nima, qaysi muammoni hal qiladi va 5 daqiqada birinchi loyiha

Holat: 2026-yil oktabr. Bu dars Tuist nima ekanini, u qaysi aniq muammoni yechishini va 5 daqiqada birinchi loyihani ishga tushirishni o'rgatadi. Kod misollari Tuist 4.211.1, Xcode 27.1 (27A9275) va Swift 6.4 bilan Apple M4 Pro (12 core, 24 GB) da tekshirilgan.

Bu darsdan keyin siz: Tuist'ni o'rnatib, o'z qo'lingiz bilan birinchi modulli iOS loyihasini generatsiya qilib, simulyatorda ishga tushira olasiz — va nima uchun bu usul project.pbxproj muammosini butunlay yo'q qilishini tushunasiz.

  • project.pbxproj nega jamoaviy ishda azob berishini — haqiqiy git merge konflikti misolida ko'rasiz;
  • Tuist'ning 2026-dagi ikki yuzini (project generator + tezlik/insight platformasi) ajrata olasiz;
  • mise yoki Homebrew bilan Tuist'ni o'rnatib, versiyani jamoa uchun qotirasiz (tuist@4.211.1);
  • tuist init → tuist generate → xcodebuild → tuist test zanjirini o'z o'lchovlaringiz bilan bajarasiz;
  • 2026-dagi CLI buyruqlarini bilasiz va eski darsliklardagi eskirgan buyruqlardan (tuist focus, tuist fetch, Config.swift) qochasiz.

Mundarija

  1. [Muammo: project.pbxproj va jamoaviy ish](#muammo)
  2. Qulaylik narxi: implicit bog'liqliklar
  3. Tuist nima (2026): generator va platforma
  4. Qanday ishlaydi: manifest → graph → Xcode loyihasi
  5. O'rnatish: mise, Homebrew va versiyani qotirish
  6. 5 daqiqada birinchi loyiha
  7. Nega arziydi: real jamoalar va o'z o'lchovlarim
  8. CLI xaritasi (4.211.1)
  9. Eski darsliklar nimani noto'g'ri o'rgatadi
  10. Amaliy mashqlar
  11. O'zingizni tekshiring
  12. Xulosa
  13. Manbalar

1. Muammo: project.pbxproj va jamoaviy ish {#muammo}

Har bir Xcode loyihasining ichida MyApp.xcodeproj/project.pbxproj degan fayl bor. Bu — Xcode loyihangizning "miyasi": qaysi fayllar qaysi target'ga tegishli, qanday build setting'lar bor, qaysi framework'lar linklanadi — hammasi shu faylda yoziladi. Muammo shundaki, bu fayl odam uchun emas, mashina uchun yozilgan. Ichida har bir element uchun 24 belgili hex identifikator (masalan 00F38421DE977174828DBA92) bo'ladi.

Keling, buni gapirib o'tirmasdan, haqiqatda ko'raylik. Men Tuist bilan kichik bir loyiha generatsiya qildim, uning project.pbxproj faylini git'ga qo'ydim (ya'ni klassik "loyihani commit qilamiz" usuli), so'ng ikki dasturchi ikki alohida branch'da bittadan yangi ekran fayli qo'shdi:

# Azim o'z branch'ida Profil ekranini qo'shadi
git checkout -b feature/profile main
# ... Sources/ProfileView.swift yaratildi, loyiha qayta generatsiya qilindi ...
git commit -am "added profile screen"

# Dilnoza xuddi shu asosdan (main) Sozlamalar ekranini qo'shadi
git checkout -b feature/settings main
# ... Sources/SettingsView.swift yaratildi, loyiha qayta generatsiya qilindi ...
git commit -am "added settings screen"

# Endi Azim Dilnozaning branch'ini o'ziga qo'shib olmoqchi:
git checkout feature/profile
git merge feature/settings

Natija (men haqiqatda olgan chiqish — hech narsa o'ylab topilmagan):

Auto-merging ConflictDemo.xcodeproj/project.pbxproj
CONFLICT (content): Merge conflict in ConflictDemo.xcodeproj/project.pbxproj
Automatic merge failed; fix conflicts and then commit the result.

Faylning ichi esa shunday ko'rinadi:

		83694910F51808EF05647B16 /* Sources */ = {
			isa = PBXGroup;
			children = (
				45BB604057E80130C7A38F16 /* App.swift */,
<<<<<<< HEAD
				6035B7B5B8E94B0548015005 /* ProfileView.swift */,
=======
				3F402DE11DAC1368B68786C9 /* SettingsView.swift */,
>>>>>>> feature/settings
			);
			path = Sources;
			sourceTree = "<group>";
		};

Va yana bir konflikt "Sources" build phase'ida:

/* Begin PBXSourcesBuildPhase section */
		9BB09A959275F82566850030 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				39D7A3CC2E102EC78ACFE482 /* App.swift in Sources */,
<<<<<<< HEAD
				0BB022FF2F2F7336BBFE2F1A /* ProfileView.swift in Sources */,
=======
				8EC79921F6CBA18B331E5F1C /* SettingsView.swift in Sources */,
>>>>>>> feature/settings
			);
			runOnlyForDeploymentPostprocessing = 0;
		};

Hech kim bu fayllarni qo'lda tahrir qilmadi — ikkala dasturchi ham shunchaki Xcode'da (yoki Tuist bilan) bittadan fayl qo'shdi. Ammo ikkalasi ham files va children ro'yxatining aynan o'sha joyiga yangi qator qo'shgani uchun git bu ikki o'zgarishni avtomatik birlashtira olmadi. Endi kimdir bu hex ID'larni tushunib, qaysi qatorni qoldirib, qaysi <<<<<<</=======/>>>>>>> belgilarni o'chirishni hal qilishi kerak. Bitta qavs yoki vergul adashsa — butun loyiha Xcode'da ochilmay qoladi.

Chapda haqiqiy project.pbxproj merge konflikti (ikki branch ikkita fayl qo'shdi), o'ngda Tuist yechimi: Project.swift git'da, .xcodeproj gitignore'da.

Diagrammaning chap tomoni yuqoridagi haqiqiy konfliktni ko'rsatadi; o'ng tomoni Tuist qanday qilib bu muammoni ildizidan yo'q qilishini — Project.swift ni (odam o'qiydigan Swift kod) commit qilib, generatsiyalangan .xcodeproj ni esa .gitignore ga olib — ko'rsatadi.

🧠 Esda tuting: Konfliktning ildizi — generatsiyalangan ikkilamchi (derived) faylni Git'da saqlash. project.pbxproj sizning kodingiz emas, u sizning sozlamalaringizdan hosil bo'lgan fayl. Tuist aynan shu hosilani Git'dan chiqarib tashlaydi: siz sababni (Project.swift) saqlaysiz, natijani (project.pbxproj) esa har kim o'z mashinasida qayta generatsiya qiladi.

Modern nuans: Xcode 16 "synchronized folders" buni biroz yumshatadi

Adolatli bo'lish uchun ayni haqiqatni ham aytish kerak. Yuqoridagi konflikt loyiha fayllarni bittalab project.pbxproj da ro'yxatga olgani uchun yuzaga keldi (bu Xcode'ning yillardan beri davom etgan odati). Xcode 16 dan boshlab "synchronized folders" (sinxronlangan papkalar) paydo bo'ldi — papkani butunlab target'ga biriktirasiz, va undagi fayllar pbxproj da alohida ro'yxatga olinmaydi. Tuist buni buildableFolders orqali qo'llaydi (keyingi darsda batafsil).

Men buni ham tekshirdim: buildableFolders ishlatadigan loyihada yangi AboutView.swift faylini papkaga qo'shib, qayta generatsiya qildim — va project.pbxproj umuman o'zgarmadi (fayl md5'i bir xil qoldi: 685b13eff0ee66f641215cb1b1684b70 → 685b13eff0ee66f641215cb1b1684b70, git diff bo'sh).

⚠️ Diqqat: Demak "pbxproj konflikti"ning fayl-qo'shish turi buildableFolders bilan kamayadi. Lekin build setting'lar, target'lar, scheme'lar, bog'liqliklar o'zgarganda pbxproj baribir o'zgaradi — va agar siz uni commit qilsangiz, baribir konflikt bo'lishi mumkin. Tuist'ning asl yechimi "fayllarni yaxshiroq ro'yxatga olish" emas, balki generatsiyalangan loyihani umuman commit qilmaslikdir. Buni Tuist'ning o'zi ham tan oladi: buildable folders changelog'ida "bu konfliktlar bizning ish jarayonimizda tez-tez uchramasdi, asl yutuq — qayta generatsiya qilish shart emasligi" deyilgan.

Bundan tashqari project.pbxproj bilan bog'liq yana ikki og'riq bor, va ularni buildableFolders yecha olmaydi:

  1. Inkonsistent build setting'lar. 40 ta target'li loyihada "hammasi SWIFT_VERSION = 6.0 bo'lsin" degan qoidani Xcode interfeysida kafolatlash qiyin — kimdir bitta target'da uni qo'lda o'zgartiradi va hech kim sezmay qoladi.
  2. Arxitektura ko'rinmaydi. Qaysi modul qaysi modulga bog'langan, qayerda aylanma bog'liqlik (circular dependency) bor — pbxproj ni ochib bilib bo'lmaydi.

Keyingi bo'limda esa eng nozik, lekin eng muhim muammoni ko'ramiz: implicit (yashirin) bog'liqliklar.


2. Qulaylik narxi: implicit bog'liqliklar {#cost}

Tuist jamoasining o'zi "The cost of convenience" (qulaylikning narxi) nomli hujjatida Xcode falsafasini shunday tushuntiradi: Apple Xcode'ni kichik loyihalar uchun qulay bo'lishga optimallashtirgan. Buning uchun ko'p narsani "yashirin" (implicit) qilib qo'ygan — ya'ni build paytida avtomatik hal qilinadigan. Kichik loyihada bu qulay. Katta loyihada esa aynan shu yashirinlik muammolarning manbai bo'ladi.

Eng klassik misol — umumiy "built products" papkasi. Xcode barcha target'larning kompilyatsiya natijalarini (binary, framework) bitta derived data papkasiga joylaydi, va bu papka boshqa target'larga ham ko'rinadi. Oqibatda:

Bitta target ikkinchisiga hech qayerda yozilmagan holda bog'lanib qolishi mumkin. Build mashinangizda (derived data'da tasodifan kerakli binary turgani uchun) o'tadi, CI serverda esa (u yerda holat boshqacha) compile bo'lmaydi.

Bu — har bir iOS jamoasi hayotida bo'lgan "menikida ishlayapti-ku" (works on my machine) muammosining aniq texnik sababi. Tuist hujjati buni shunday ta'riflaydi (tarjima): "build lokal'da derived data'dagi qandaydir holat tufayli o'tishi mumkin — u singleton kabi ishlaydi — lekin CI'da holat boshqacha bo'lgani uchun compile bo'lmaydi."

Yashirin bog'liqliklar yana ikki joyda og'riq beradi:

  • SwiftUI Preview'lar ishonchsiz bo'ladi. Preview va Swift Macro'lar ishlashi uchun build tizimi tahrir qilinayotgan fayldan boshlab butun bog'liqlik grafigini aniq bilishi kerak. Grafik qanchalik yashirin bo'lsa, build tizimiga shunchalik qiyin — shuning uchun ko'p dasturchilar "Preview baribir ishlamaydi" deb undan voz kechgan.
  • Mergeable libraries kabi build paytida hal qilinadigan narsalar. Target static'mi yoki dynamic'mi — buni build paytidagi setting'lardan aniqlash grafikni yana ham noaniq qiladi.

Tuist bu muammolarni explicit (aniq) qilib yechadi: siz bog'liqliklarni Project.swift da ochiq yozasiz, Tuist esa generatsiya paytida grafikni quradi va tekshiradi. Tuist hujjatining o'z so'zi bilan:

"Tuist'ning rolini shunday ta'riflasa bo'ladi: u loyihalarning implicit (yashirin) aniqlanishining oldini oladi va explicitlikdan foydalanib yaxshiroq developer experience beradi (validatsiya, optimizatsiya). Bazel kabi vositalar buni yana chuqurroq — build tizimi darajasiga — olib boradi."

🧠 Esda tuting: Bu — Tuist va Bazel'ning umumiy falsafasi: explicitlik (aniqlik) — miqyos (scale) kaliti. Farqi shundaki, Tuist Apple'ning xcodebuild build tizimini saqlab, uning ustida ishlaydi; Bazel esa o'z build tizimini olib keladi. Shu sababli bu kursning ikkala moduli — Tuist va Bazel — bitta g'oyaning ikki darajasi.

💡 Pro tip: Tuist yashirin bog'liqliklarni topish uchun alohida buyruq beradi: tuist inspect dependencies --only implicit. Uni CI'da ishga tushirsangiz, kodingizga yashirin bog'liqlik kirib qolsa — build emas, CI tekshiruvi qulaydi, ya'ni muammoni erta ushlaysiz. Buni 4-dars da amalda ko'ramiz.


3. Tuist nima (2026): generator va platforma {#nima}

2026-yilda Tuist'ni bitta jumlada ta'riflash kam. Uning ikki yuzi bor:

1-yuz — Project generator (CLI, bepul, hisob shart emas). Siz loyiha strukturasini Swift manifestlarda (Project.swift, Tuist.swift) yozasiz, tuist generate deysiz, Tuist esa toza .xcodeproj/.xcworkspace yaratib beradi. Bu yerga tuist graph (bog'liqlik grafigi), tuist edit (manifestni autocomplete bilan tahrirlash), tuist migration (Xcode'dan ko'chirish), tuist scaffold (shablonlar) va tuist inspect (implicit bog'liqlik tekshiruvi) kiradi. Bularning hammasi hisobsiz, bepul ishlaydi.

2-yuz — Platforma (server/hisob bilan kuchayadi). Bu loyihangizni tezlashtiradi va unga "ko'z" beradi:

  • Module (binary) cache — o'zgarmagan modullarni tayyor .xcframework sifatida qayta ishlatish;
  • Selective testing — faqat o'zgargan modullar testini ishga tushirish;
  • Xcode compilation cache — Apple'ning Xcode 26+ dagi kompilyatsiya keshiga masofaviy backend;
  • Build / Test / Bundle insights — build vaqti, flaky testlar, ilova hajmi tahlili;
  • Previews (tuist share), Swift Package Registry, Runners (CI).

Tuist'ning ikki yuzi: chapda bepul generator (CLI), o'ngda server/hisob bilan ishlaydigan platforma; pastda — 2026-dan beri Bazel va Gradle'ni ham quvvatlaydi.

🧠 Esda tuting: Module cache va selective testing lokal rejimda hisobsiz ham ishlaydi (buni keyinroq o'z mashinamda ko'rsataman). Lekin ularni jamoa bo'lib birga ulashish (masofaviy kesh), insights, previews va runners uchun Tuist hisobi/serveri kerak. "Avval bepul lokal, kerak bo'lsa server" — to'g'ri yondashuv.

Yana bir muhim yangilik: Tuist endi faqat Xcode uchun emas. 2026-yil sentyabrdan beri Tuist serveri Bazel va Gradle loyihalarini ham keshlaydi (Bazel uchun REAPI masofaviy kesh + Build Event Protocol orqali insights; sozlash ikki buyruq: tuist auth login, keyin har repo uchun tuist bazel setup). Ya'ni Tuist nafaqat "Xcode project generatori", balki bir nechta build tizimiga xizmat qiluvchi platformaga aylanyapti.

⚠️ Diqqat: "Tuist Cloud" nomi endi yo'q — u shunchaki Tuist (server + dashboard, tuist.dev) deb ataladi. Eski darsliklarda "Tuist Cloud" ni uchratsangiz, bu o'sha mahsulotning eski nomi.

Tarix va falsafa (qisqa)

Tuist 2017-yildan beri rivojlanadi va uning asosiy g'oyasi boshidanoq bir xil: Infrastructure as Code tamoyilini iOS loyihalariga olib kirish. Siz loyihani "qo'lda sichqoncha bilan" emas, kod bilan ta'riflaysiz; kod esa versiyalanadi, review qilinadi va qayta ishlatiladi. Versiyalar tarixida muhim bosqich — Tuist 3 → 4 o'tishi (2024), unda ko'p narsa o'zgardi (tuist fetch → tuist install, Config.swift → Tuist.swift va hokazo — bularni 9-bo'limda ko'ramiz). Hozir Tuist 5 yo'q; eng so'nggi barqaror versiya 4.x liniyasida.


4. Qanday ishlaydi: manifest → graph → Xcode loyihasi {#qanday}

Tuist'ning yuragi — oddiy uch bosqichli jarayon:

Tuist jarayoni: 1) siz Swift manifestlarni yozasiz, 2) tuist generate bog'liqlik grafigini quradi va tekshiradi, 3) .xcworkspace/.xcodeproj/Derived yaratiladi; manifestlar git'ga, generatsiyalangan fayllar gitignore'ga.

  1. Siz Swift manifestlarni yozasiz. Kamida ikki fayl: Tuist.swift (global sozlama, loyiha ildizini belgilaydi) va Project.swift (bitta Xcode loyihasini ta'riflaydi). Tashqi paketlar uchun Tuist/Package.swift.
  2. **tuist generate grafikni quradi.** Tuist manifestlarni o'qiydi (ular haqiqiy Swift kod, shuning uchun avval kompilyatsiya qilinadi — birinchi marta sekinroq, keyin keshlanadi), bog'liqlik grafigini yasaydi, xatolarni tekshiradi, keshdagi binary'larni ulaydi.
  3. Natija — Xcode loyihasi. App.xcworkspace, App.xcodeproj va Derived/ papkasi (Info.plist va boshqa hosila fayllar). Bular gitignore qilinadi.

Manifestlar — bu "sabab", generatsiyalangan loyiha — "natija". Git'da faqat sabab saqlanadi. Shuning uchun har bir dasturchi git clone qilib, tuist generate deganda aynan bir xil loyihani oladi — 1-bo'limdagi konflikt endi tug'ilishi mumkin emas, chunki konflikt tug'diradigan fayl Git'da yo'q.

🚀 Motivatsiya: Bu bitta oddiy g'oya — "hosilani commit qilma" — jamoangizdagi eng ko'p takrorlanadigan ikki azobni birato'la yo'q qiladi: project.pbxproj merge konfliktlari va "menikida ishlayapti" muammosi. Qolgan hamma narsa (kesh, selective testing, insights) — shu poydevor ustiga quriladigan tezlik qavatlari.


5. O'rnatish: mise, Homebrew va versiyani qotirish {#ornatish}

Tuist macOS va Linux'da ishlaydi (Linux'da tuist generate kabi Xcode'ga bog'liq buyruqlar yo'q, lekin tuist inspect bundle kabilar ishlaydi). Rasmiy hujjat ikki yo'lni tavsiya qiladi.

1-usul: mise (jamoalar va CI uchun tavsiya etiladi ⭐)

mise — har bir loyiha uchun tool versiyasini qotirib qo'yadigan vosita (eski tuistenv o'rniga kelgan). Homebrew'dan farqi: Homebrew global bitta versiyani o'rnatadi; mise esa versiyani loyihaga (yoki global) bog'lab, jamoadagi hamma va CI bir xil versiyada ishlashini kafolatlaydi.

# Loyihada aniq versiyani o'rnatib, qotirish (tavsiya):
mise use tuist@4.211.1

# Global standart sifatida:
mise use -g tuist@4.211.1

# Eng so'nggi BARQAROR versiya (canary/RC emas):
mise use tuist@latest

Loyiha ildizida mise.toml fayli paydo bo'ladi:

# mise.toml
[tools]
tuist = "4.211.1"

Endi loyihani klon qilgan har kim (yoki CI) shunchaki:

mise install

deb yozsa — aynan 4.211.1 o'rnatiladi. Bu "menikida boshqa versiya edi" muammosini yo'q qiladi.

2-usul: Homebrew (faqat macOS)

brew tap tuist/tuist
brew install --formula tuist
# yoki aniq versiya:
brew install --formula tuist@4.211.1

📊 Real raqamlar: Bu darsdagi barcha tekshiruvlar aynan shu mashinada o'rnatilgan Tuist 4.211.1 bilan bajarilgan (Homebrew cask orqali: brew install --cask tuist). Tekshirish:

bash tuist version

text 4.211.1

Qaysi versiyani tanlash kerak?

⚠️ Diqqat: Tuist tez chiqadi. Har commit uchun canary build chiqadi; barqaror minor versiyalar har dushanba (~1 hafta RC bo'lib turgandan keyin) chiqariladi; patch versiyalar faqat tuzatishlar olib keladi. Yozilish paytida eng so'nggi barqaror versiya 4.212.0 edi (2026-10-12), biz esa 4.211.1 (2026-10-11) bilan ishladik. Darslik yoki jamoa loyihasida har doim aniq versiyani qotiring (tuist@4.211.1), "latest" ga tayanmang — chunki ertaga "latest" boshqa bo'ladi va o'zgargan xatti-harakat sizni kutilmaganda urishi mumkin.

Shell completion (Tab bilan to'ldirish) va boshqa sozlamalar tuist --help orqali ko'rinadi. Keling, endi amalga o'tamiz.


6. 5 daqiqada birinchi loyiha {#besh-daqiqa}

Ikki yo'lni ko'rsataman: (A) tuist init bilan tayyor shablondan, (B) hammasini qo'lda yozib — ikkinchisi Tuist "ichida" nima borligini tushunish uchun eng foydali.

A yo'li: tuist init (2026-da u interaktiv emas)

⚠️ Diqqat: Eski darsliklar tuist init deb yozib, terminal savol-javob (interaktiv) berishini ko'rsatadi. 4.211.1 da tuist init flaglar bilan interaktiv emas ishlaydi. tuist init --help ni ko'ring: --build-system (qiymatlari xcode, generated-xcode, gradle, bazel), --platform, --name, --no-server.

mkdir SalomTuist && cd SalomTuist
tuist init --build-system generated-xcode --platform ios --name DemoApp --no-server

Men bu buyruqni ishga tushirganimdagi haqiqiy chiqish:

ℹ︎ Creating generated project
   ✔︎ Generated project created [0.7s]
✔ Success
  You are all set to explore the Tuist universe

  Takeaways:
   ▸ Choose the project directory with 'cd DemoApp'
   ▸ Generate your project with 'tuist generate'
   ▸ Visualize your project graph with 'tuist graph'

U quyidagi strukturani yaratadi (haqiqiy, tekshirilgan):

DemoApp/
├── .gitignore
├── Tuist.swift
├── Project.swift
├── Tuist/
│   └── Package.swift
└── DemoApp/
    ├── Sources/
    │   ├── DemoAppApp.swift
    │   └── ContentView.swift
    ├── Tests/
    │   └── DemoAppTests.swift
    └── Resources/
        └── Assets.xcassets/

E'tibor bering: **hech qanday .xcodeproj yo'q.** Papka toza.

Generatsiyalangan Project.swift 2026-standartida — buildableFolders ishlatadi:

// Project.swift (tuist init yaratgan, qisqartirildi)
import ProjectDescription

let project = Project(
    name: "DemoApp",
    targets: [
        .target(
            name: "DemoApp",
            destinations: .iOS,
            product: .app,
            bundleId: "dev.tuist.DemoApp",
            infoPlist: .extendingDefault(with: ["UILaunchScreen": ["UIColorName": "", "UIImageName": ""]]),
            buildableFolders: ["DemoApp/Sources", "DemoApp/Resources"],
            dependencies: []
        ),
        .target(
            name: "DemoAppTests",
            destinations: .iOS,
            product: .unitTests,
            bundleId: "dev.tuist.DemoAppTests",
            infoPlist: .default,
            buildableFolders: ["DemoApp/Tests"],
            dependencies: [.target(name: "DemoApp")]
        ),
    ]
)

Va Tuist.swift — eng minimal ko'rinishda:

// Tuist.swift
import ProjectDescription

let tuist = Tuist(project: .tuist())

🧠 Esda tuting: let tuist = Tuist(project: .tuist()) — 4.211.1 dagi eng to'g'ri minimal konfiguratsiya. Eski darsliklarda bu yerda generationOptions: .options(enforceExplicitDependencies: true) yozilgan bo'lishi mumkin — u 4.211.1 da deprecated (eskirgan). Buning o'rniga yashirin bog'liqliklarni tuist inspect dependencies --only implicit bilan CI'da tekshiring.

B yo'li: qo'lda — 2 modulli loyiha (men shuni to'liq tekshirdim)

Keling, "App'ga bog'langan Core modul" misolini noldan yozamiz. Struktura:

SalomTuist/
├── Tuist.swift
├── Project.swift
├── Tuist/
│   └── Package.swift
├── App/Sources/
│   ├── SalomApp.swift
│   └── ContentView.swift
└── Core/
    ├── Sources/Greeter.swift
    └── Tests/GreeterTests.swift

Tuist.swift va Tuist/Package.swift:

// Tuist.swift
import ProjectDescription

let tuist = Tuist(project: .tuist())
// Tuist/Package.swift
// swift-tools-version: 6.0
import PackageDescription

let package = Package(name: "SalomTuist", dependencies: [])

Project.swift — uchta target: App (ilova), Core (static framework), CoreTests (testlar):

// Project.swift
import ProjectDescription

let project = Project(
    name: "SalomTuist",
    targets: [
        .target(
            name: "SalomApp",
            destinations: .iOS,
            product: .app,
            bundleId: "uz.azimjondev.salomtuist",
            deploymentTargets: .iOS("17.0"),
            infoPlist: .extendingDefault(with: ["UILaunchScreen": [:]]),
            buildableFolders: ["App/Sources"],
            dependencies: [.target(name: "Core")]
        ),
        .target(
            name: "Core",
            destinations: .iOS,
            product: .staticFramework,
            bundleId: "uz.azimjondev.salomtuist.core",
            deploymentTargets: .iOS("17.0"),
            buildableFolders: ["Core/Sources"]
        ),
        .target(
            name: "CoreTests",
            destinations: .iOS,
            product: .unitTests,
            bundleId: "uz.azimjondev.salomtuist.coretests",
            deploymentTargets: .iOS("17.0"),
            buildableFolders: ["Core/Tests"],
            dependencies: [.target(name: "Core")]
        ),
    ]
)

Swift kodlar (oddiy, lekin haqiqiy — build va test shu kod bilan o'tdi):

// Core/Sources/Greeter.swift
import Foundation

public struct Greeter {
    public init() {}

    public func salom(_ name: String) -> String {
        let trimmed = name.trimmingCharacters(in: .whitespaces)
        return trimmed.isEmpty ? "Salom, dunyo!" : "Salom, \(trimmed)!"
    }
}
// Core/Tests/GreeterTests.swift
import Testing
@testable import Core

struct GreeterTests {
    @Test func bushNom_dunyoniQaytaradi() {
        #expect(Greeter().salom("   ") == "Salom, dunyo!")
    }

    @Test func nomBilan_salomlashadi() {
        #expect(Greeter().salom("Azim") == "Salom, Azim!")
    }
}
// App/Sources/SalomApp.swift
import SwiftUI

@main
struct SalomApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
// App/Sources/ContentView.swift
import Core
import SwiftUI

struct ContentView: View {
    @State private var name = ""
    private let greeter = Greeter()

    var body: some View {
        VStack(spacing: 16) {
            Text(greeter.salom(name)).font(.title)
            TextField("Ismingiz", text: $name)
                .textFieldStyle(.roundedBorder)
        }
        .padding()
    }
}

Loyihani generatsiya qilamiz

tuist generate --no-open

Haqiqiy chiqish (men olgan):

Loading and constructing the graph
It might take a while if the cache is empty
Using cache binaries for the following targets:
Generating workspace SalomTuist.xcworkspace
Generating project SalomTuist
Total time taken: 0.704s
✔ Success
  Project generated.

📊 Real raqamlar (Apple M4 Pro, Tuist 4.211.1, Xcode 27.1): Birinchi (sovuq) generatsiya — Tuist o'z o'lchovi bo'yicha 0.704 s (jami wall-time ~1.05 s, chunki jarayon ishga tushishi ham qo'shiladi). Manifestlar keshlangandan keyin ikkinchi generatsiya — 0.603 s (wall ~0.88 s). --no-open bayrog'i Xcode'ni avtomatik ochmaslik uchun (CI va skriptlar uchun qulay).

Endi papkada quyidagilar paydo bo'ldi:

SalomTuist.xcworkspace   ← Xcode shuni ochadi
SalomTuist.xcodeproj     ← generatsiyalangan (gitignore)
Derived/                 ← Info.plist va hosila fayllar (gitignore)

Avtomatik yaratilgan scheme'lar (xcodebuild -list bilan tekshirdim):

Schemes:
    Core
    Generate Project
    SalomApp
    SalomTuist-Workspace

Ya'ni har bir test bo'lmagan target uchun bitta scheme (SalomApp, Core), bitta Workspace scheme, va bitta "Generate Project" scheme (Xcode ichidan tuist generate ni qayta ishga tushirish uchun).

⚠️ Diqqat: CoreTests alohida scheme emas — u **Core** scheme'iga biriktirilgan. Shuning uchun keyinroq tuist test Core deymiz, tuist test CoreTests emas (bu "scheme topilmadi" xatosini beradi).

Build va simulyatorda ishga tushirish

2026-da muhim nuans: **tuist build <scheme> endi loyihani build qilmaydi.** 4.211.1 da tuist build — bu build yozuvlarini tekshiradigan buyruqlar guruhi. Haqiqiy build'ni xcodebuild bilan (yoki insights kerak bo'lsa tuist xcodebuild build bilan) qilasiz. Generatsiyalangan workspace'ni build qilamiz:

xcodebuild -workspace SalomTuist.xcworkspace -scheme SalomApp \
  -destination 'generic/platform=iOS Simulator' \
  -derivedDataPath .dd build

Natija:

** BUILD SUCCEEDED **

📊 Real raqamlar: Bu 2 modulli ilovaning sovuq (cold) build'i — 17.3 s (M4 Pro, Xcode 27.1). Qaysi simulyatorlar borligini xcrun simctl list devices available bilan ko'rasiz; Xcode 27.1 da "iPhone 15" yo'q, shuning uchun men "iPhone 17" oilasidan foydalandim. Build uchun generic/platform=iOS Simulator yetarli (aniq qurilma shart emas). Ilovani simulyatorda ishga tushirish uchun Xcode'da Cmd + R bosing yoki xcodebuild ... -destination 'platform=iOS Simulator,name=iPhone 17,OS=27.0' bilan test/run qiling.

Testlar va "selective testing" (hisobsiz, lokal)

tuist test Core --device "iPhone 17" --os 27.0

Birinchi ishga tushirish natijasi:

Testing the following targets: CoreTests
[CoreTests] Compiling GreeterTests.swift
...
Test Succeeded
✔ Success
  The project tests ran successfully

Endi hech narsa o'zgartirmasdan aynan o'sha buyruqni qayta beraman:

Loading and constructing the graph
Using cache binaries for the following targets:
Generating workspace SalomTuist.xcworkspace
Generating project SalomTuist
The scheme Core's test action has no tests to run, finishing early.

🚀 Motivatsiya (o'z o'lchovim): Birinchi test — 25.1 s (simulyator yuklanishi + kompilyatsiya + 2 ta Swift Testing testi). Ikkinchi marta, hech narsa o'zgarmagani uchun, Tuist testni umuman qayta ishga tushirmaydi — 0.94 s da "ishga tushiradigan test yo'q" deb tugatadi. Bu — selective testing, va u hech qanday hisob yoki serversiz, faqat lokal mashinamda ishladi. 25 soniya → 1 soniya. Yuzlab modulli loyihada bu tamoyil (faqat o'zgargan modul testini ishga tushirish) CI vaqtini keskin kamaytiradi — masalan quyida ko'radigan Monzo'da module cache + selective testing P50 PR vaqtini 52 → 15 daqiqaga tushirgan. Selective testing'ni o'chirmoqchi bo'lsangiz: --no-selective-testing.

⚠️ Diqqat: Selective testing faqat Tuist generatsiyalagan loyihalarda (tuist test orqali) ishlaydi va granulyarligi target darajasida (bitta fayl emas, butun target). Shuning uchun modullaringiz qancha mayda bo'lsa, foyda shuncha katta. Boshqa build tizimlari uchun qo'llab-quvvatlash hali "rejalashtirilgan".

Bog'liqlik grafigini ko'rish

tuist graph --format dot --no-open

Natija (graph.dot fayli — haqiqiy chiqish):

digraph {
  Core [fillcolor=coral1 shape=cylinder style=filled]
  CoreTests [fillcolor=limegreen shape=octagon style=filled]
  SalomApp [fillcolor=deepskyblue shape=box3d style=filled]
  CoreTests -> Core
  SalomApp -> Core
}

Ya'ni SalomApp → Core va CoreTests → Core. --format qiymatlari: dot (matn), json, png, svg (png/svg uchun mashinada graphviz o'rnatilgan bo'lishi kerak). Katta loyihada bu grafik aylanma bog'liqliklarni va "kim kimga bog'langan"ni bir qarashda ko'rsatadi.

Manifestlarni autocomplete bilan tahrirlash: tuist edit

tuist edit

Bu buyruq vaqtinchalik Xcode loyihasi yaratib, barcha manifestlaringizni (Project.swift, Tuist.swift, helperlar) to'liq avtomatik to'ldirish (autocomplete) bilan ochadi — chunki manifestlar haqiqiy Swift kod. Oddiy tuist edit jarayonni bloklab turadi (siz tahrir qilyapsiz); tuist edit --permanent esa loyihani joriy papkada qoldirib, bloklamaydi.

💡 Pro tip: Project.swift ni oddiy matn muharririda yozish o'rniga tuist edit dan foydalaning — ProjectDescription API'sidagi har bir parametr (.target, destinations, product...) autocomplete bilan chiqadi, va xatoni Xcode darhol ko'rsatadi.


7. Nega arziydi: real jamoalar va o'z o'lchovlarim {#motivatsiya}

Endi eng muhim savol: bu haqiqatan ham arziydimi? Avval bir ogohlantirish, keyin raqamlar.

⚠️ Diqqat (halol gap): Quyidagi kompaniya raqamlarining deyarli hammasi Tuist tomonidan e'lon qilingan (yoki mijoz yozib, Tuist saytida chop etilgan) case-study'lardan. Bazel/Tuist/Xcode'ni bir xil loyihada yonma-yon o'lchagan neytral (uchinchi tomon) benchmark mavjud emas — har bir raqam bitta jamoaning o'z eski holatiga nisbatan. Shuning uchun ularni "reklama bo'lishi mumkin" deb o'qing. Men quyida har birining manbasi va sanasini ataylab ko'rsataman; eng ishonchli neytral raqamlar esa — yuqoridagi o'z mashinamdagi o'lchovlar.

🏢 Monzo (bank ilovasi; case-study Tuist tomonidan 2026-05-26 da chop etilgan, Monzo o'zi yozgan): ~50 dan ~200 gacha modul, 45+ iOS muhandis, 1.9M qator Swift, 20 ming unit + 8 ming snapshot test. CI bir paytlar har PR uchun 70 daqiqadan oshgan. Module cache'ni main'da har 30 daqiqada "isitib" turish bilan: P50 PR vaqti 52 → 15 daqiqa (−71%), P90 esa 57 → 35 daqiqa (−39%). Halol nuans: Monzo'ning o'zi aytadi — lokal build vaqtlari kesh bilan ham deyarli o'zgarmadi; kesh asosan CI'ni tezlashtiradi, mahsulot (release) build'larida umuman ishlatilmaydi.

🏢 Asana (loyiha-boshqaruv ilovasi; Asana muhandislik blogi, 2023-02-21 — bu ro'yxatdagi yagona vendor-bo'lmagan manba): ~10 muhandis, ~300 ming qator Swift deyarli bitta target ichida edi. ~1,400 qatorli Tuist manifestini "bir necha hafta"da yozishdi, keyin ~3 oy kodni modullarga ko'chirishdi. Natija: funksiyani o'zgartirib-qayta-build qilish 45 s → 15 s (Scalyr'da qayd etilgan median), Inbox moduli esa 30–50 s → ~4 s. Ular Bazel o'rniga Tuistni tanlashdi — sababi developer experience: Bazel "juda og'ir", "yangi mental modellar talab qiladi" va breakpoint muammolari bor edi. Narxi: git checkout 5–15 s sekinlashdi, va "muhandislarning faqat ozchiligi" Tuist ichki ishini chuqur bilardi.

🏢 Trendyol (e-commerce; mijoz yozgan, Tuist chop etgan, 2024-12-16; o'z serverida self-hosted): bir oylik sinovdan keyin build vaqtlari −65%, CI 30 → 10 daqiqa; UI-testlar uchun toza Xcode muhitini tayyorlash kamida 15 daqiqa → ~30 soniya; selective unit test'lar fikr-qaytarishni 80% gacha tezlashtirdi. (Eslatma: Trendyol'ning 170+ dasturchisi iOS + Android — faqat iOS jamoasi o'lchovi emas.)

🏢 monday.com (2025-12-15): ~20 kishilik iOS jamoasi, ~200 modul; CI merge jarayoni 20+ daqiqadan (2022) ~9 daqiqaga tushdi ("CI vaqtini yarmiga qisqartirdik", module cache "muhim rol o'ynadi").

🏢 Delivery Hero (Logistics iOS rider ilovasi, 2026-05-26): ~115 modul; toza build 2.5 → 0.5 daqiqa; CI build+test 2.5 barobar tez.

🏢 Toss (Koreya fintech; 2026-10-01): ~1,000 ga yaqin modul (ko'pi Interface/Implementation/Model/Testing'ga bo'lingan). Ular profiling bilan aniqlashdi: Xcode vaqtining katta qismi bog'liqlik grafigini hisoblashga ketadi, va bu xarajat o'zgarish hajmiga emas, modullar soniga qarab o'sadi. ~3 oyda "focus" ish jarayonini qurishdi (bir dasturchi bitta scheme tanlaydi, qolgani tayyor .xcframework bo'ladi) va 1 daqiqadan kam build'lar ulushini uch barobardan ko'proq oshirishdi. Yangi muammolar ~1,000 binary'da paydo bo'ldi (framework search path'lar, hash barqarorligi). Bu — Enterprise (pullik, self-hosted) sozlama.

📊 Real raqamlar — mening neytral o'lchovlarim (Apple M4 Pro, Tuist 4.211.1, Xcode 27.1, bu darsning 2 modulli loyihasi). Bu raqamlar reklama emas, sizda ham takrorlanadi:

| Amal | Vaqt | Shart | | ---------------------------------- | ----------------- | ---------------------------------- | | tuist generate (sovuq) | 0.70 s | manifestlar kompilyatsiyasi bilan | | tuist generate (iliq) | 0.60 s | manifestlar keshlangan | | xcodebuild sovuq build | 17.3 s | 2 target, simulyator uchun | | tuist test Core (1-marta) | 25.1 s | simulyator yuklash + 2 test | | tuist test Core (2-marta) | 0.94 s | selective testing, o'zgarish yo'q | | project.pbxproj konflikti | 2 ta hunk | ikki branch fayl qo'shdi (haqiqiy) | | fayl qo'shish (buildableFolders) | 0 qator o'zgarish | pbxproj md5 bir xil |

Umumiy xulosa: kichik loyihada Tuist'ning asosiy foydasi tezlik emas, balki tartib — pbxproj konfliktlari yo'qoladi, loyiha struktura kodda bo'ladi, onboarding osonlashadi (git clone → tuist generate → tayyor). Tezlik yutuqlari (kesh, selective testing) modullar soni va jamoa kattalashgani sari sezila boshlaydi.


8. CLI xaritasi (4.211.1) {#cli}

tuist --help chiqishi buyruqlarni ish bosqichlari bo'yicha guruhlaydi. Quyida 4.211.1 dagi asosiy buyruqlar (keyingi darslarda har biri batafsil ochiladi):

BosqichBuyruqVazifasi
Boshlashtuist initYangi loyihani boshlash (flaglar bilan, interaktiv emas)
Loyihatuist generateManifestdan Xcode workspace yaratish (run/list/show)
Loyihatuist editManifestlarni autocomplete bilan tahrirlash
Loyihatuist graphBog'liqlik grafigini chizish (dot/json/png/svg)
Loyihatuist dumpManifestni JSON ko'rinishida chiqarish
Loyihatuist cleanLokal artifact va keshlarni tozalash
Bog'liqliktuist installSPM paketlarini o'rnatish/resolve qilish
Bog'liqliktuist registryTuist Swift package registry bilan ishlash
Tezliktuist cacheModullarni binary keshlash (warm — standart, config)
Tezliktuist testLoyihani testlash (selective testing bilan)
Tezliktuist hashKesh/selective testing hashlarini debug qilish
Tahliltuist inspectdependencies (implicit/redundant), bundle, build, test
Tahliltuist buildBuild yozuvlarini tahlil qilish (list/show/xcode/gradle)
Tahliltuist xcodebuildxcodebuildni insights/analytics bilan o'raydi
Kod ulashishtuist scaffoldShablondan yangi kod yaratish
Kod ulashishtuist migrationXcode loyihasini Tuist'ga ko'chirish yordamchilari
Kod ulashishtuist pluginPlugin'larni boshqarish
Platformatuist share / tuist runPreview linkini yaratish / preview yoki scheme'ni ishga tushirish
Platformatuist setup / tuist teardownTuist xizmatlarini (masalan Xcode cache) sozlash/o'chirish
Hisobtuist auth / account / project / organization / bundleHisob va server resurslari
Boshqatuist bazelBazel repo'ni Tuist cache/insights'ga ulash (setup/test)
Boshqatuist versionJoriy versiyani ko'rsatish

🧠 Esda tuting: tuist build — bu build buyrug'i emas (bu 4.x da eng ko'p adashtiradigan joy). U build yozuvlarini tekshiradigan guruh. Haqiqiy build — xcodebuild (yoki insights uchun tuist xcodebuild).


9. Eski darsliklar nimani noto'g'ri o'rgatadi {#ozgargan}

Internetdagi ko'p Tuist darsliklari (va bu darsning eski versiyasi ham) 2023–2024 holatiga asoslangan. Tuist 3 → 4 o'tishida ko'p narsa o'zgardi. Agar quyidagilarni ko'rsangiz — bu eskirgan:

Eski (eskirgan)2026 (Tuist 4.211.1)
tuist init (interaktiv savol-javob)tuist init --build-system generated-xcode --platform ios --name X
tuist focus Profiletuist generate Profile (all-possible cache profilni nazarda tutadi)
tuist fetchtuist install
Tuist/Dependencies.swiftTuist/Package.swift (+ #if TUIST ichida PackageSettings)
Config.swiftTuist.swift
tuist build MyScheme (build uchun)build — xcodebuild bilan; tuist build endi tahlil guruhi
--no-cache--no-binary-cache → endi --cache-profile none
tuistenvmise
"Tuist Cloud"shunchaki "Tuist" (server + dashboard, tuist.dev)
.gitignore: Tuist/Dependencies/Tuist/.build
enforceExplicitDependencies: truetuist inspect dependencies --only implicit (CI'da)

💡 Pro tip: To'g'ri (2026) .gitignore ning Tuist qismi — tuist init o'zi yaratgani (tekshirilgan):

gitignore # .gitignore (Tuist qismi) *.xcodeproj *.xcworkspace graph.dot Derived/ Tuist/.build

Diqqat: endi Tuist/Dependencies/ emas, Tuist/.build (tashqi paketlar shu yerga resolve bo'ladi). xcuserdata/ va DerivedData/ ni ham qo'shing.


10. Amaliy mashqlar {#mashqlar}

  1. O'rnatish va tekshirish. mise use tuist@4.211.1 (yoki Homebrew) bilan Tuist'ni o'rnating va tuist version chiqishi 4.211.1 ekanini tasdiqlang. Loyiha ildizida mise.toml paydo bo'lganini ko'ring.
  2. Konfliktni o'z ko'zingiz bilan ko'ring. Yangi papka oching, sources: (not buildableFolders:) bilan bitta target'li loyiha yozing, tuist generate qiling, so'ng .xcodeproj ni git'ga commit qiling. Ikki branch oching, har birida bittadan .swift fayl qo'shib qayta generatsiya qiling, merge qiling va project.pbxproj da konflikt chiqishini kuzating. Keyin .xcodeproj ni .gitignore ga qo'shib, konflikt yo'qolishini ko'ring.
  3. Birinchi loyiha. Ushbu darsdagi 2 modulli SalomTuist loyihasini noldan yozing, tuist generate --no-open qiling va o'zingizda generatsiya vaqtini o'lchang (time tuist generate --no-open). Mening natijam bilan solishtiring.
  4. Selective testing. tuist test Core --device "iPhone 17" --os 27.0 ni ikki marta ketma-ket ishga tushiring. Ikkinchi marta "no tests to run, finishing early" chiqishini va vaqt keskin qisqarishini kuzating. Keyin Greeter.swift ga bitta yangi test qo'shing va testlar yana ishga tushishini ko'ring.
  5. Grafik. ⭐ tuist graph --format svg --no-open bilan grafik yarating (graphviz kerak: brew install graphviz) va SalomApp → Core bog'liqligini ko'ring. Keyin Project.swift ga yangi Feature target qo'shib, uni SalomApp ga bog'lang va grafik qanday o'zgarishini kuzating.
  6. **buildableFolders tajribasi.** ⭐ buildableFolders ishlatadigan loyihada project.pbxproj ning md5'ini oling (md5 *.xcodeproj/project.pbxproj), yangi .swift fayl qo'shib qayta generatsiya qiling va md5 o'zgarmasligini tasdiqlang. Keyin sources: globga o'tkazib, xuddi shu tajribani takrorlang — bu safar o'zgaradi.

11. O'zingizni tekshiring {#checklist}

  • [ ] project.pbxproj nima ekanini va u nega merge konflikt tug'dirishini tushuntira olaman.
  • [ ] Nega generatsiyalangan loyihani Git'ga commit qilmaslik kerakligini bilaman.
  • [ ] Tuist'ning ikki yuzini (generator CLI + platforma) ajrata olaman.
  • [ ] "Implicit bog'liqlik" nima va "menikida ishlayapti" muammosi bilan qanday bog'liqligini bilaman.
  • [ ] mise va Homebrew bilan Tuist o'rnata olaman va versiyani qotira olaman.
  • [ ] tuist init → tuist generate → build → tuist test → tuist graph zanjirini bajara olaman.
  • [ ] tuist build build buyrug'i emasligini va build xcodebuild bilan bo'lishini bilaman.
  • [ ] Eski buyruqlarni (tuist focus, tuist fetch, Config.swift) 2026 ekvivalentlari bilan almashtira olaman.

12. Xulosa {#xulosa}

  • Muammo — generatsiyalangan project.pbxproj ni Git'da saqlash: merge konfliktlar (biz haqiqiy konflikt ishlab chiqardik), inkonsistent setting'lar va yashirin (implicit) bog'liqliklar ("menikida ishlayapti").
  • Yechim — Tuist loyihani Swift manifestlarda (Project.swift, Tuist.swift) ta'riflaydi, tuist generate esa .xcodeproj/.xcworkspace ni hosila sifatida yaratadi; hosila gitignore qilinadi, shuning uchun konflikt tug'ilmaydi.
  • Tuist 2026-da — ikki yuz: bepul generator CLI (generate, graph, edit, migration, scaffold, inspect) + server/hisob bilan kuchayadigan platforma (module cache, selective testing, Xcode cache, insights, previews, registry, runners). Endi Bazel va Gradle'ni ham keshlaydi.
  • O'rnatish — jamoa uchun mise use tuist@4.211.1 (versiyani qotiring); yolg'iz ishlovchi uchun Homebrew. "latest" ga tayanmang.
  • O'z o'lchovlarim (M4 Pro): generate 0.7 s; sovuq build 17.3 s; tuist test 25.1 s → takror 0.94 s (selective testing, hisobsiz); buildableFolders bilan fayl qo'shilsa pbxproj o'zgarmaydi.
  • Halol gap: katta tezlik raqamlari vendor/mijoz manbalaridan, neytral benchmark yo'q. Kichik loyihada asosiy foyda — tartib va onboarding, tezlik esa miqyos oshgani sari.
  • Eskirganlardan qoching: tuist focus → tuist generate <Target>, tuist fetch → tuist install, Config.swift → Tuist.swift, tuist build <scheme> endi build qilmaydi.

Keyingi dars: 02. Manifest fayllar — Project.swift, Workspace.swift, Tuist.swift va Package.swift (2026 API) — har bir manifest faylni va Target ning barcha parametrlarini (haqiqiy Target.swift imzosi bo'yicha) sinchiklab ochamiz.


13. Manbalar {#manbalar}

  1. Tuist — Install Tuist (mise, Homebrew, versiyani qotirish)
  2. Tuist — The cost of convenience (implicit bog'liqliklar falsafasi)
  3. Tuist — Manifests (Tuist.swift, Project.swift)
  4. Tuist — Migration from v3 to v4 (o'zgargan buyruqlar)
  5. Tuist — Module cache va cache profillar (focus = all-possible)
  6. Tuist — Selective testing (faqat generatsiyalangan loyihalar)
  7. Tuist — Release channels (canary/RC/stable, dushanba promouti)
  8. Tuist — Buildable folders (changelog, 2025-08-11)
  9. Tuist — Bazel'ni qo'llab-quvvatlash (blog, 2026-09-09)
  10. Monzo case study (Tuist, 2026-05-26)
  11. Asana — Scaling a mature iOS codebase with Tuist (2023-02-21)
  12. Trendyol case study (Tuist blog, 2024-12-16)
  13. monday.com case study (Tuist, 2025-12-15)
  14. Delivery Hero case study (Tuist, 2026-05-26)
  15. Toss case study (Tuist, 2026-10-01)
  16. Tuist GitHub Releases (versiya sanalari)
  17. Apple — Xcode 27 release notes (Swift 6.4, macOS Tahoe 26.6+)
  18. mise — tool versiyalarini boshqarish

Markdown manba

iOS Lessons