Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Pnpm Workspace를 통한 모노레포 도입 #332

Open
wants to merge 61 commits into
base: develop
Choose a base branch
from

Conversation

wuzoo
Copy link
Contributor

@wuzoo wuzoo commented Dec 2, 2024

해당 이슈 번호

closed #330


체크리스트

  • 🔀 PR 제목의 형식을 잘 작성했나요? e.g. [feat] PR을 등록한다.
  • 💯 테스트는 잘 통과했나요?
  • 🏗️ 빌드는 성공했나요?
  • 🧹 불필요한 코드는 제거했나요?
  • ✅ 컨벤션을 지켰나요?
  • 💭 이슈는 등록했나요?
  • 🏷️ 라벨은 등록했나요?
  • 🙇‍♂️ 리뷰어를 지정했나요?

💎 PR Point

pnpm workspace를 통해 모노레포를 도입하였어요 ! 모노레포를 도입하는 과정을 순서대로 한 번 작성해볼게요.

도입하게 된 과정

먼저 모노레포를 어떻게 도입하게 되었느냐를 말씀드리고 싶어요. 먼저 저희 티키는 랜딩 페이지가 있어요. 지금은 현재 '/'이라는 Url의 루트에 라우팅되어 있는데, 프로덕트를 분리해야겠다라는 필요성을 느꼈습니다. 왜냐면 랜딩이라는 하나의 서비스는 사용자에게 티키에 대한 서비스를 홍보하고 설명하며, 다른 가이드를 제공해주고, 최종적으로 데스크탑 앱으로 출시될 티키의 메인 서비스를 설치할 수 있는 페이지에요.

즉, 랜딩 페이지는 퍼블릭 웹사이트에요. 모든 사용자들이 구글과 같은 브라우저 엔진을 통해 검색하여 드나들 수 있는 도메인이여 하고, 따라서 SEO 측면으로도 데스크탑 앱인 메인 서비스보다 신경써서 구현할 필요가 있을 것이라는 생각을 했습니다. (그래서 Next로 개발할 생각입니다.)
따라서 프로덕트를 아예 분리해버리는 것이 관심사 분리라는 측면에서도 효과적이라고 생각했고, 배포 주기나 개발의 진행도 또한 랜딩과 티키 메인 서비스라는 두 가지 도메인이 분명 분리되어 관리될 것이라는 생각을 했기 때문에 모노레포를 도입하였습니다.

두 번째 이유는 저희의 UI 컴포넌트 볼륨이 점점 커져가는 것이였습니다. 즉 컴포넌트 하나를 개발하더라도 전체 티키 프로덕트를 다시 빌드해야하는 단점이 있었어요. 모든 코드가 하나의 프로덕트 안에 종속되어 있기 때문에, 사소한 코드 하나를 변경하거나 일부 기능을 구현한다 하더라도 전체 프로덕트를 모두 빌드하는 것은 효과적이지 못하다고 생각했습니다.
따라서 ui와 같은 패키지를 따로 생성하여 그곳에서 관리하도록 구현하였어요. 또한 icon, utils 패키지를 추가적으로 설정하여 각 패키지가 관리하는 코드들은 해당 패키지의 빌드를 통해서 사용할 수 있도록 하였습니다.

도입 과정

1️⃣ 워크스페이스 설정

먼저 프로젝트 루트 디렉토리에 pnpm-workspace 파일을 통해 패키지를 명시해주어야 합니다. 저는 서비스를 담당하는 apps와 유틸 혹은 UI 패키지를 제공하는 packages로 분리하였어요. 루트에도 package.json이 존재하는데 워크스페이스 특성 상, 루트 디펜던시에 지정한 라이브러리들은 하위 모든 패키지에서 사용이 가능합니다.

따라서 필수적이라고 생각하는 라이브러리들만 루트에 설치하여 의존성으로 명시하였습니다.

또한 scripts도 중요한데, --filter 옵션을 통해 특정 하위 패키지의 명령어로 해당 커멘드를 제한시킬 수 있습니다. 이 말은 즉슨 그냥 pnpm add react를 한다면 에러가 발생해요. 왜냐하면 내가 루트에 특정 라이브러리를 설치할 것이라면 pnpm add react -w 커멘드를 사용해야 해요. 루트뿐만 아니라 하위의 다른 패키지들이 존재하기 때문에 어느 패키지에서 설치할 것인지를 명시해주어야 합니다.

pnpm --fliter add client react

라고 한다면 client라는 하위 패키지에 react를 설치하겠다 라는 의미입니다. 따라서 루트의 package.json 스크립트에 특정 하위 패키지에 쉽게 커맨드를 입력할 수 있도록 scripts를 만들어두었습니다.

위의 커맨드는 다음과 같아요

pnpm client add react

라고 입력한다면 client 패키지에 리액트가 설치되게 됩니다.
만약 특정 패키지에 다른 워크스페이스 내의 패키지를 설치하고 싶다면 다음과 같이 명령하면 됩니다.

pnpm client add @tiki/tsconfig --workspace

이렇게 입력한다면 client라는 패키지에 @tiki/tsconfig라는 워크스페이스 내 패지키를 설치하겠다는 것입니다. 설치 후 package.json을 보면 다음과 같아요.

"devDependencies": {
    "@tiki/tsconfig": "workspace:^"
}

즉 워크스프에스 내에 있는 @tiki/tsconfig라는 패키지를 dev 의존성으로 설치했다라는 의미입니다.

2️⃣ 각 패키지 세팅

pnpm init을 통해 특정 디렉토리에 package.json을 생성해줄 수 있어요. 그렇다면 이때부터 해당 디렉토리는 하나의 패키지로 사용할 수 있게 됩니다. apps/client가 기존의 티키 프로덕트에요. 특정 패키지의 패키지명은 package.json의 "name" 프로퍼티 값입니다.
apps/landing에는 랜딩 프로덕트를 개발할 예정이에요. SEO 최적화를 위해서 next로 개발할 예정이기 때문에, next 초기 세팅을 해주었습니다.

3️⃣ tsconfig 설정

가장 애먹었던 부분입니다. 해당 패키지가 어떻게 타입스크립트 환경에서 컴파일될 것인지, 모듈을 어떻게 정의할 것인지 등등을 해당 설정 파일에서 작성해주어야 해요.

일단 패키지 중에 @tiki/tsconfig를 설정하여 모든 프로덕트 혹은 패키지가 tsconfig 패키지 안에 있는 특정 json 파일을 상속하여 사용하도록 하였습니다. 기본은 base.json이에요.

tsconfig의 각 속성에 대해서는 너무 많기도 하고, 아직은 저도 어떤 속성이 다른 속성에 의존성을 갖고 있는지, 세부적인 속성에 대한 정확한 이해를 하고 있지 못한 것 같아서 추후에 정리하여 다시 올리겠습니다.

4️⃣ tsup을 통한 번들링

iconui 패키지는 tsup이라는 번들 툴을 사용하였습니다.

번들링이라는 것들은 모듈에 필요한 각 파일들을 하나의 파일로 결합하는 행위입니다. 사실 티키라는 프로덕트 안에서만 사용할 패키지라면, 번들링이 필요하지 않을 수도 있을 것이라고 생각했어요. 브라우저에서 다양한 모듈 시스템의 사용을 지원하기 위해 결국 번들링을 하는 것인데, 저희 티키의 메인 서비스에서만 사용할 것이라면 그냥 esmodule만을 지원하면 되기 때문이에요. (현재 클라이언트 패키지가 es모듈)

하지만 iconui 패키지는 추후 npm 배포까지 고려하고 싶었습니다. 그렇다면 저희의 아이콘과 UI 패키지를 사용하려는 모든 모듈 시스템을 지원해야 하며 또한 최적화까지 신경써야 할 것이라고 생각했어요. 여기서 최적화는 코드 스플리팅이나 트리쉐이킹과 같은 현대 번들러들이 지원하는 최적화 기능들이에요.

따라서 tsup이라는 번들러를 도입했습니다. 해당 툴을 사용하면 cjs 혹은 esm과 같은 다양한 모듈 시스템 지원이 가능하고, 당연히 기존 번들러들이 지원했던 최적화까지 해줄 수 있었어요.

5️⃣ 패키지 활용법

tsconfigutils는 기본적으로 그냥 워크스페이스 내의 로컬 의존성이라 해당 패키지에서 작성한 코드들은 바로 clientlanding 패키지에서 활용 가능합니다.

하지만 iconui는 기본적으로 빌드 후 생성된 dist 폴더를 기준으로 다른 패키지에서 사용하는 것이라, 변경사항이 있다면 build를 해주고 다른 패키지에서 사용해야합니다 !

icon 패키지는 먼저 svgr을 통해 assets 폴더 내의 svg 파일들을 src 폴더 아래에 컴포넌트로 만들어주고, generate 명령을 통해 index.ts 파일에서 export default 처리를 해주어야 합니다. 그 후 build 해주고 다른 패키지에서 사용하면 돼요 !!

ui 패키지 또한 컴포넌트를 추가/삭제/변경한다면 다시 build해주고 사용하면 됩니다 !

  1. 번들러를 통해 build
  2. dist 내에 index.js와 같이 번들된 파일이 생성됨
  3. package.json에서 mainmodule 프로퍼티에 적혀있듯이 해당 패키지는 dist 내의 index파일을 진입점으로 여긴다라는 의미. 즉 다른 패키지에서는 빌드되어 번들링된 해당 파일 코드를 사용하는 것.

참고

파일 변경이 너무 많은데 기존 코드 중에는 SideNavBar 컴포넌트만 보시면 될 것 같아요. Item 컴포넌트의 prop 구조를 일부 수정했습니다.

각 패키지에서 tsconfigpackage.json는 기본적으로 확인 부탁드려요 !

ui 패키키지와 utils 패키지는 기존의 컴포넌트 혹은 훅들을 옮긴 것 뿐입니다. icon 패키지에서는 svgr 활용한 거나 generateIcon 파일 정도 확인해주시면 감사하겠습니다 !

Copy link

github-actions bot commented Dec 3, 2024

🚀 Storybook 확인하기 🚀

Copy link

github-actions bot commented Dec 3, 2024

🚀 Storybook 확인하기 🚀

Copy link

github-actions bot commented Dec 3, 2024

🚀 Storybook 확인하기 🚀

Copy link

github-actions bot commented Dec 3, 2024

🚀 Storybook 확인하기 🚀

Copy link
Member

@namdaeun namdaeun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모노레포 도입 정말 고생많으셨습니다 🚀✨

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next 초기 세팅할 때 수반되는 불필요한 파일들은 제거해주는 게 좋을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다 !

"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 옵션 true로 해준 이유가 있나요 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어.. 따로 없는데 landing에서의 tsconfig 파일은 추후에 tsconfig 패키지의 next.json으로 대체할 예정이라 남겨두었습니다 !

}
case 'team': {
return variant.logoUrl ? (
<img src={variant.logoUrl} alt="팀 프로필 이미지" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린 리더기가 이미 img 태그를 이미지로 인식하고 있기 때문에 alt 메시지에 -이미지 라는 워딩은 불필요하다고 합니다 ! 참고해서 수정해주심 좋을 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다 !!

Copy link

github-actions bot commented Dec 3, 2024

🚀 Storybook 확인하기 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pnpm Workspace를 통한 모노레포 도입
3 participants