baegteun - iOS

Tuist 사용법 - 8. Scaffold, Template를 사용하여 새로운 모듈 만들기 본문

Tuist

Tuist 사용법 - 8. Scaffold, Template를 사용하여 새로운 모듈 만들기

baegteun 2023. 2. 15. 00:16

이 글은 Tuist 버전 3.16.0 기준으로 작성되었습니다.

Scaffold?

프로젝트에서 새로운 컴포넌트나 기능 만드는 것을 시작할 때 사용할 수 있는 기능입니다.
파일을 만들 때 tuist scaffold를 사용하면 템플릿으로부터 파일을 만들 수 있습니다.
템플릿은 Tuist에서 기본으로 제공해주는 템플릿을 사용할 수도 있고, 직접 만들어 사용할 수도 있습니다.

https://docs.tuist.io/commands/scaffold

tuist scaffold 사용법

tuist scaffold <template> [--json] [--path <path>] <subcommand>

사용 예시

tuist scaffold ribs --name Example

이렇게만 본다면 단순히 Xcode Template 다른게 없거나 오히려 더 불편한거 아닌가? 싶을 수 있는데, scaffold는 이미 만들어진 모듈에 새로운 파일들을 만들 때 보다는 새로운 모듈을 만들 때에 더 적합한거같습니다.

앞서 사용 예시의 상황을 더 구체화시켜보면

...
- Features
    - AboutFeature
    - UserFeature
    - SettingsFeature
    - CompeteFeature
...

위와같이 Feature를 분리하는데, 이 기준을 RIB를 기준으로 분리한다 했을때. 위의 tuist scaffold ribs --name Example을 하면 Project.swift의 내용물도 채우며 새로운 ExampleFeature 모듈을 만들것입니다.

템플릿 만들기

Tuist로 프로젝트를 하나 만들고, 그 안에 Template를 하나 만들어보겠습니다.

먼저 tuist init --platform ios으로 tuist 프로젝트 하나를 init하고 tuist edit으로 edit을 시작하겠습니다.

Plugin은 무시해주고 Manifests/Tuist 에 'Templates' 라는 이름의 Group을 하나 만듭니다. Templates는 Tuist에서 정해놓은 이름이기에 다르게 입력한다면 안에 템플릿이 있어도 인식되지 않습니다.

새로운 템플릿을 만들 때는 Templates/<템플릿이름>/<템플릿이름>.swift 로 <템플릿이름>.swift에 해당 템플릿을 나타낼 수 있습니다.

샘플을 하나 한 번 만들어보겠습니다.

Templates/ 아래에 example/ 와 example.swift를 만들어줍니다.

Attribute

다름으로 example.swift안에 내용물을 채워주는데, 첫번째로는 Attribute라고 하는 해당 커맨드의 옵션을 받는 변수를 선언해줍니다.

// example.swift

import ProjectDescription

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

이렇게하면 scaffold를 사용해 템플릿을 불러올때 tuist scaffold example --name Example 로 --<attribute명> <값> 으로 값을 전달 받을 수 있습니다.

Attribute는 필수와 옵셔널 두 종류로 받을 수 있습니다.
옵셔널은 입력하지 않으면 default값을 사용합니다.

Template

Tuist로 프로젝트나 플러그인을 만들 때처럼 템플릿도 정의합니다.

// example.swift

import ProjectDescription

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

let template = Template(
    description: <#String#>,
    attributes: <#[Template.Attribute]#>,
    items: <#[Template.Item]#>
)
  • description: 템플릿의 설명입니다. 평소에는 딱히 볼일은 없긴하지만 tuist scaffold list를 하면 표시됩니다.
  • attributes: scaffold 커맨드가 실행될때 받을 attribute리스트를 넣으면 됩니다.
  • items: 여기에 넣어준 아이템을 기반으로 결과물이 나옵니다. 타입은 string, file, directory 3종류를 만들어 낼 수 있습니다.

Item

directory는 그냥 보면 디렉토리를 만드는건가, 싶지만 사실 디렉토리는 만드는 것이 아니라 sourcePath의 디렉토리를 내용물채로 복사해서 옮겨줍니다.
파일을 만드는것은 string과 file이 있는데 이 둘의 차이는 string은 직접 문자열 "" 안에 내용물을 작성하는 것이고, file은 stencil 이라고하는 Swift를 위한 템플릿 언어를 사용하여 만드는 것입니다.

string

파라미터가 받는 그대로, path안에 파일명까지 포함해서(ex. Features/\(nameAttribute)Feature/Project.swift) 보내주시고, contents안에 해당 파일안의 내용물을 작성하시면 됩니다.

file

위와 거의 동일하게 파일명까지 포함해서 path를 넘겨주고, templatePath를 받아 해당 경로에 있는 파일의 내용물을 넣습니다.
코드를 뜯어보니 stencil만 따로 템플릿 렌더링 과정을 거치고 나머지 파일은 무슨 파일이든 읽힌 그대로 넘기는 듯 합니다.

stencil에 대한 자세한건.. stencil github에 여러모로 있으니 살펴봐주세요. Swift를 위한 Template 언어인 점을 제외하고는 뭔가 특별한 목적이 없으니 사실 별로 배울것도 없습니다. 변수, for, if 정도면 충분합니다.
여담으로 vscode extension에 stencil언어 extension도 있답니다.

directory

directory는 directory를 복사해서 옮겨줍니다. sourcePath에 받는 경로에 있는 directory를 path에 그대로 옮겨주는겁니다.

// example.swift
import ProjectDescription

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

let template = Template(
    description: "A template for new module",
    attributes: [
        nameAttribute,
    ],
    items: [
        .string(
            path: "Source.swift",
            contents: "// Source contents of name \(nameAttribute)"
        ),
        .file(
            path: "Project.swift",
            templatePath: "project.stencil"
        ),
        .directory(
            path: "destination",
            sourcePath: "source"
        )
    ]
)
{# project.stencil #}

import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.makeModule(
    name: "{{ name }}",
    product: .staticLibrary
)

우선 간단하게 만들어보았습니다. directory같은경우 Template/example/ 안에 source/ 를 만들고 그 안에 Second.swift에 대충 내용을 채워넣었습니다.

이렇게 템플릿을 만들고 나서 tuist edit을 종료해줍니다. 그후 tuist scaffold list를 하고 아래처럼 나온다면 템플릿 생성에 성공한것입니다.

그리고 터미널에 tuist scaffold example --name Test를 쳐봅니다! 아래와 같이 나온다면 성공한겁니다.

그리고 파인더를 슬쩍보면 위와같이 되어있을겁니다. (Project.swift는 내용이 덮어씌워졌습니다)

구조가 깔끔하지 않으니 겸사겸사 path를 사용해봅시다.
파인더에서 루트에 Projects/ 폴더를 하나 만들고 tuist scaffold example --name Test --path Projects/ 를 실행해봅시다. 그러면 Projects/ 아래에 만들어집니다.

그리고 이런 한 프로젝트안의 모듈용 템플릿이 아닌 글로벌로 사용하고 싶다면 $HOME/.tuist/Versions/\(Version)/Templates 안에 템플릿을 위치시켜두면 됩니다.
$HOME/.tuist/Versions/\(Version)/Templates/ 안에 swiftui용 프로젝트 템플릿도 있으니 한 번 슬쩍 뜯어보는것도 괜찮을거같습니다.

해당 글에서 작성한 내용은 깃허브에서도 볼 수 있습니다.

References By

https://docs.tuist.io/commands/scaffold/

Comments