Tuist Clean Architecture Plugin
The ClarchPlugin is a tool that helps iOS developers scaffold projects following the Clean Architecture pattern using Tuist. It promotes Domain-Driven Design (DDD) by structuring code around core business logic and separating concerns into layers like Presentation, Domain, and Data. At the same time, it encourages Test-Driven Development (TDD) by generating testable modules and boilerplate test files, making it easier to write and maintain tests from the start. This plugin streamlines the setup process, enforces architectural consistency, and supports scalable, maintainable app development.
Clarch Architecture & Dependencies
Directory Structure
[Project]
├── Workspace.swift
├── App/
│ ├── {{ appName }}/
│ │ ├── Project.swift
│ │ ├── Sources/
│ │ └── Resources/
│ ├── {{ name }}DIContainer/
│ │ ├── Project.swift
│ │ └── Sources/
│ ├── {{ name }}Coordinator/
│ │ ├── Project.swift
│ │ └── Sources/
│ └── {{ name }}CoordinatorInterface/
│ ├── Project.swift
│ └── Sources/
│
├── Feature/
│ └── {{ name }}Feature/
│ ├── Project.swift
│ ├── Interface/
│ │ └── Sources/
│ ├── Implementation/
│ │ ├── Sources/
│ │ └── Resources/
│ ├── Testing/
│ │ └── Sources/
│ ├── Tests/
│ │ └── Sources/
│ └── Example/
│ └── Sources/
│
├── Domain/
│ ├── {{ name }}BaseDomain/
│ │ ├── Project.swift
│ │ └── Sources/
│ ├── {{ name }}RepositoryInterfaces/
│ │ ├── Project.swift
│ │ └── {{ repositoryName }}RepositoryInterface/
│ │ └── Sources/
│ └── {{ name }}Domain/
│ ├── Project.swift
│ ├── Interface/
│ │ └── Sources/
│ ├── Implementation/
│ │ └── Sources/
│ ├── Testing/
│ │ └── Sources/
│ └── Tests/
│ └── Sources/
│
├── Data/
│ ├── {{ name }}BaseData/
│ │ ├── Project.swift
│ │ └── Sources/
│ └── {{ name }}Data/
│ ├── Project.swift
│ ├── Interface/
│ │ └── Sources/
│ ├── Implementation/
│ │ └── Sources/
│ ├── Testing/
│ │ └── Sources/
│ └── Tests/
│ └── Sources/
│
├── Infrastructure/
│ └── {{ name }}Infrastructure/
│ ├── Project.swift
│ ├── Interface/
│ │ └── Sources/
│ ├── Implementation/
│ │ └── Sources/
│ └── Tests/
│ └── Sources/
│
├── Core/
│ └── Core{{ name }}/
│ ├── Project.swift
│ └── Sources/
│
└── Shared/
└── Shared{{ name }}/
├── Project.swift
└── Sources/
To do this, open your Tuist project for editing by running the following command in your project directory:
tuist edit
1. Add the plugin to your project configuration
In your Tuist/Config.swift file:
// Example
let config = Config(
plugins: [
.git(url: "https://github.com/JHKits/ClarchPlugin", tag: "1.1.0") // ClarchPlugin
],
generationOptions: .options()
)2. Set up your workspace using ClarchPlugin
In your Workspace.swift file:
@preconcurrency import ProjectDescription
import ClarchPlugin
let workspace = Workspace(
name: "name",
projects: ClarchConfiguration.workspacePaths
)or
@preconcurrency import ProjectDescription
let workspace = Workspace(
name: "name",
projects: [
"App/**",
"Feature/**",
"Data/**",
"Infrastructure/**",
"Core/**",
"Shared/**"
]
)ℹ️ Note: Suffixes like
Domain,Data, andRepositoryInterfaceare automatically appended.
Modules underCoreandSharedare designed to be accessible from any layer.
[App Layer]
App
Represents the main application target, including the app's entry point, main UI, and configuration.
directory: App/{{ appName }}
use: /Sources, /Resources
dependable: .diContainer, .coordinatorInterface
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .app(appName: "appName")DIContainer
Contains the Dependency Injection Container for managing and resolving dependencies across modules.
directory: App/{{ name }}DIContainer
use: /Sources
dependable: all
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .diContainer(moduleName: "name")Coordinator
Defines the app's navigation logic and flow using the Coordinator pattern.
directory: App/{{ name }}Coordinator
use: /Sources
dependable: .coordinatorInterface
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .coordinator(moduleName: "name")CoordinatorInterface
Exposes the protocol interfaces for coordinators, allowing decoupled communication between modules.
directory: App/{{ name }}CoordinatorInterface
use: /Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .coordinatorInterface(moduleName: "name")[Feature Layer]
Feature
Represents a business feature or user-facing functionality. It typically includes Interface, Implementation, Example, and Resources directories.
directory: Feature/{{ name }}Feature
use: /Interface/Sources, /Implementation/Sources, /Implementation/Resources, /Testing/Sources, Tests/Sources, /Example/Sources
dependable: .coordinatorInterface, .domain
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .feature(moduleName: "name")[Domain Layer]
Domain
Contains the core business logic, such as use cases and domain entities, separated into interface and implementation.
directory: Domain/{{ name }}Domain
use: /Interface/Sources, /Implementation/Sources, /Testing/Sources, Tests/Sources
dependable: .baseDomain, .repositoryInterfaces
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .domain(moduleName: "name")BaseDomain
Contains shared domain entities or utilities that are reused across multiple domain modules.
directory: Domain/{{ name }}BaseDomain
use: /Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .baseDomain(moduleName: "name")RepositoryInterfaces
Contains shared domain entities or utilities that are reused across multiple domain modules.
directory: Domain/{{ name }}RepositoryInterfaces
use: /{repositoryName}RepositoryInterface/Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .repositoryInterfaces(
moduleName: "name",
repositoryTargetNames: [
// repositoryNames
]
)[Data Layer]
Data
Implements data access logic, typically fulfilling the contracts defined in the repository interfaces.
directory: Data/{{ name }}Data
use: /Interface/Sources, /Implementation/Sources, /Testing/Sources, Tests/Sources
dependable: .baseData, .repositoryInterfaces, .infrastructure
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .data(moduleName: "name")BaseData
Shared data components or utilities used across multiple data modules, such as network or persistence setup.
directory: Data/{{ name }}BaseData
use: /Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .baseData(moduleName: "name")[Infrastructure Layer]
Infrastructure
Handles cross-cutting concerns like logging, analytics, and external service integrations (e.g., Firebase, CoreData).
directory: Infrastructure/{{ name }}Infrastructure
use: /Interface/Sources, /Implementation/Sources, Tests/Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .infrastructure(moduleName: "name")[Additional Layer]
Core
Shared foundational logic specific to the current project (e.g., design system, extensions, or architecture tools).
directory: Core/Core{{ name }}
use: /Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .core(moduleName: "name")Shared
General-purpose shared modules reusable across different features or layers, such as constants, common UI components, or helpers.
directory: Shared/Shared{{ name }}
use: /Sources
dependable: nil
@preconcurrency import ProjectDescription
import ClarchPlugin
nonisolated(unsafe) let project: Project = .shared(moduleName: "name")
+) Create SwiftUI Modules Easily with clarch.sh
- Download the
clarch.shscript to workspace
curl -o clarch.sh https://raw.githubusercontent.com/JHKits/ClarchPlugin/main/clarch.sh- Create the module with command.
╔═══════════════════════════════════════════════════════╗
║ ClarchPlugin ║
╠═══════════════════════════════════════════════════════╣
║ Usage: ./clarch.sh <module> --name <name> [options] ║
╚═══════════════════════════════════════════════════════╝
📁 Supported Modules
[App]
app --name <name>
diContainer [--name <name>] (default: "")
coordinator [--name <name>] (default: "")
coordinatorInterface [--name <name>] (default: "")
[Feature]
feature --name (required)
[Domain]
domain --name <name>
baseDomain --name <name>
repositoryInterfaces [--name <name>] (default: "")
[--repository-names <name1,...>]
[Data]
data --name <name>
baseData --name <name>
[Infrastructure]
infrastructure --name <name>
[Core]
core --name <name>
[Shared]
shared --name <name>
[Header Setting Options]
--author <name> (default: Mac User Name)
--current-date <MM/DD/YY> (default: Current Date)
--copyright-year <YYYY> (default: Current Year)
--organization <name>
※ If the organization is missing,
the copyright notice will not be generated.
ClarchPlugin is available under the MIT license.
See the LICENSE file for more information.
If you have any questions, suggestions, or issues, feel free to reach out:
Email: l06094@gmail.com
You're more than welcome to submit a pull request or open an issue.
Community contributions are always appreciated!
