티스토리 뷰

728x90
반응형

[ 문서 ]

- 공식 문서 > templates

- workshop > Bonus 2. Templates

 

[ tuist scaffold ]

tuist 는 tuist scaffold 라는 명령어를 제공하는데, 프로젝트 자동생성을 도와주는 명령어입니다.

tuist scaffold name_of_template --name Name

 

이 명령어는 Tuist/Templates 경로에 저장되어있는 템플릿을 사용하고,

템플릿은 manifest 파일과 Stencil file 을 결합하여 만듭니다. 

 

 

자세히 말하자면, 

 

1) Tuist/Templates 하위에 name_of_template 디렉토리 만들기. 

2) 해당 디렉토리에 name_of_template.swift 파일 두기.

3) name_of_template.swift 는 템플릿을 describe 하는 manifest 파일입니다. 

    이 파일에 Template 을 구성하는데, 이 때 stencil 파일이 필요하다면  templatePath 로 연결합니다. 

 

 

[ 예제 ]

 

tuist workshop 예제를 참고해서 feature module 을 만들어주는 템플릿을 작성해보겠습니다.

 

우선 tuist edit 을 실행해서 Tuist/Templates 아래에 feature 디렉토리를 만들어줍니다. 

(이 디렉토리는 문서에서 가이드하지만 필수는 아님. 하지만 있어야 유지보수가 편함) 

 

그리고 해당 디렉토리 밑에 manifest 파일인 feature.swift 를 만듭니다.

manifest 파일명이 tuist scaffold 명령어에서 name_of_template 에 해당되기 때문에, 저는 소문자로 시작하게 만들어줬어요. 

tuist scaffold name_of_template --name Name

 

 

코드는 우선 이렇게만 작성해줍니다.

Attribute 는 template 으로 전달되는 값을 의미합니다. name 을 필수로 전달받게 합니다. 

import ProjectDescription

let nameAttribute: Template.Attribute = .required("name")

let template = Template(
    description: "Creates a new feature module",
    attributes: [
        nameAttribute,
    ]
)

 

 

그리고 이 모듈이 생기면 기본으로 생겨야하는 뼈대를 stencil 형태로 작성해줍니다.

 

 

 

참고로 이렇게 하위 폴더 (Feature, Sources) 로 묶지 않아도 됩니다.

Tuist 팀에서 자동생성될 모듈이랑 똑같은 디렉토리로 파일을 배치해둔게 좋아보여 따라한 것!

 

 

간단히 project.swift 파일이랑 

import ProjectDescription

let project = Project(
    name: "{{ name }}",
    targets: [
        .target(
            name: "{{ name }}",
            destinations: .iOS,
            product: .framework,
            bundleId: "io.tuist.{{ name }}",
            deploymentTargets: .iOS("17.0"),
            sources: ["Sources/**"],
            dependencies: []
        )
    ]
)

 

 

Sources 밑에 생겨야하는 샘플 파일을 작성해줍니다. 

import Foundation

public class {{ name }} {
    public init() {}
}

 

 

그리고 feature.swift 에 가서 items 를 작성해줍니다. 

import ProjectDescription

let nameAttribute: Template.Attribute = .required("name")

let template = Template(
    description: "Creates a new feature module",
    attributes: [
        nameAttribute,
    ],
    ✅ items: [
        .file(path: "Projects/\(nameAttribute)/Project.swift", templatePath: "Feature/Project.stencil"),
        .file(path: "Projects/\(nameAttribute)/Sources/\(nameAttribute).swift", templatePath: "Feature/Sources/Feature.stencil")
    ]
)

 

 

참고: file(path:templatePath:) 

 

  • path: Path where to generate file
  • templatePath: Path of file where the template is defined

그리고 아래 명령어를 실행해보면 

tuist scaffold feature --name Settings

 

해당 모듈이 잘 만들어지는 것을 볼 수 있습니다. 

 

 

 

[ Stencil 필터 ]

 

stencil 필터를 같이 쓰면 좀 더 유용합니다.

예를들어 {{ name }} 이 아니라 {{ name | capitalize }} 를 쓰면 실수로 settings 를 입력해도 Settings 로 만들어지게 할 수 있어요. (대문자 카멜케이스 보장)

 

 

stencil 파일 뿐만아니라,  manifest 파일에서도 stencil 문법을 쓸 수 있더라구요 ?

기존의 string interpolation 인  \(nameAttribute) 말고, {{ name | capitalize }} 를 사용한 코드 입니다. 

import ProjectDescription

let template = Template(
    description: "Creates a new feature module",
    attributes: [
        .required("name"),
    ],
    items: [
       ✅ .file(path: "Projects/{{ name | capitalize }}/Project.swift", templatePath: "Feature/Project.stencil"),
       ✅ .file(path: "Projects/{{ name | capitalize }}/Sources/{{ name | capitalize }}.swift", templatePath: "Feature/Sources/Feature.stencil")
    ]
)

 

 

 

[ Template.Attribute ]

위에서 required 만 썼는데, optional 도 있습니다. 

예를들어 이렇게 optional 과 default value 를 지정해줄 수 있습니다. 

let template = Template(
    description: "Creates a new feature module",
    attributes: [
        .required("name"),
       ✅ .optional("platform", default: "ios")
    ]
    ...
)

 

 

명시적으로 platform 을 넘기면 해당 platform 으로, 아니면 default value 로 지정되게 됩니다.

tuist scaffold name_of_template --name Name --platform macos

 

 

넘어오는 값을 보고 manifest 에서 템플릿을 분기해줄 수도 있고

stencil 파일에서 코드 분기를 태울 수도 있겠습니다.

 

자꾸 까먹는 stencil 분기문법,, 

{% if condition1 %}
  <!-- condition1이 참일 때 실행 -->
{% elif condition2 %}
  <!-- condition1은 거짓이고 condition2가 참일 때 실행 -->
{% else %}
  <!-- 모든 조건이 거짓일 때 실행 -->
{% endif %}

 

 

 

[ Template.Item ]

3가지 static 메소드가 제공됩니다. 

 

위에서 사용한 file(path:templatePath:)  으로 템플릿을 복붙할 수 도 있고 

 

- string(path:contents:)  string 복붙

- directory(path:sourcePath:)  폴더 복붙 

 

도 가능!

 

문서에는 template 이 가장 flexibility 가 높고 additional stencil filters 도 쓸 수있는 방법이라고 말합니다.

 

 

 

반응형
댓글