Background
최근 사이드 프로젝트에서 컴포넌트 주도 개발(CDD)와 공통 컴포넌트 문서화를 위해 storybook을 도입하였다. 로컬에서 작성한 storybook 코드를 팀원들에게도 공유하기 위해 배포를 해야하는 상황에서 배포할 겸
monorepo
를 도입하기로 결정하였다.monorepo
도입을 통해 한 번의 컴포넌트 작성으로 실제 서비스에서도 사용이 가능하고, 배포된 storybook에서도 사용이 가능해 재사용성을 높일 수 있다는 기대감에 도입하려고 한다. 또한, 서비스 모니터링을 위한 관리자 페이지도 다른 도메인으로 배포할 예정이었는데, 이도 monorepo
로 도입을 하게 되면 하나의 프로젝트에서 전부 관리할 수 있다는 편리함이 있다.monorepo
를 어떤 환경으로 구성할까 고민하던 중에 turborepo
와 yarn workspace
둘 중 하나로 하기로 했다. Lerna
는 상대적으로 진입장벽이 있다고 판단하였다. 사이드 프로젝트는 현재 yarn berry
환경으로 구성되어있기 때문에 yarn workspace
를 사용하기로 결정하였다.적용하기
workspace
란 monorepo
의 하위 프로젝트를 의미한다. 정식으로 배포되는 서비스의 디렉토리는 client
로, storybook을 위한 디렉토리는 design-system
으로 정했고, 이 두 가지가 각각 workspace
라 할 수 있겠다.package.json
root 디렉토리의
package.json
에 다음과 같은 세팅을 해준다.{ "workspaces": { "packages": [ "apps/*" ] }, "packageManager": "yarn@3.5.0" }
apps 디렉토리 하위의 모든 폴더들을 workspace로 지정한다는 의미이다.
apps/design-system
디렉토리를 생성하고 해당 경로로 들어가서 다음과 같은 커맨드를 입력해준다.$ npx storybook@latest init
React
와 Webpack5
를 선택해주면 다음과 같이 패키지들을 설치해준다.// apps/design-system/package.json { "name": "@Jusy-Pay/design-system", "dependencies": { "@types/react": "^18.0.35", "@types/react-dom": "^18.0.11" }, "devDependencies": { "@babel/preset-env": "^7.22.4", "@babel/preset-react": "^7.22.3", "@storybook/addon-essentials": "^7.0.18", "@storybook/addon-interactions": "^7.0.18", "@storybook/addon-links": "^7.0.18", "@storybook/blocks": "^7.0.18", "@storybook/react": "^7.0.18", "@storybook/react-webpack5": "^7.0.18", "@storybook/testing-library": "^0.0.14-next.2", "@types/babel__preset-env": "^7", "@types/prop-types": "^15", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", "storybook": "^7.0.18" }, "scripts": { "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" } }
이제,
apps/client
의 package.json
을 설정해준다. // apps/client/package.json { "name": "@Jusy-pay/client", "version": "0.1.0", "private": true, "packageManager": "yarn@3.5.0", "dependencies": { "@tanstack/react-query": "^4.29.3", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.23", "@types/react": "^18.0.35", "@types/react-dom": "^18.0.11", "@types/react-router-dom": "^5.3.3", "axios": "^1.4.0", "eslint": "^8.38.0", "eslint-plugin-react-app": "^6.2.2", "react": "^18.2.0", "react-content-loader": "^6.2.1", "react-dom": "^18.2.0", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", "styled-components": "^5.3.9", "styled-reset": "^4.4.6", "typescript": "^4.9.5", "web-vitals": "^2.1.4", "yarn": "^1.22.19" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@types/eslint": "^8", "@types/prettier": "^2", "@types/prop-types": "^15", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", "@yarnpkg/sdks": "^3.0.0-rc.42", "babel-plugin-named-exports-order": "^0.0.2", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.32.2", "prettier": "^2.8.7", "prop-types": "^15.8.1", "webpack": "^5.84.1" } }
tsconfig.json
전역에서
tsconfig.base.json
세팅을 해주고, 하위 workspace에서 확장하여 사용이 가능하다.// apps/client/tsconfig.json { "extends": "../../tsconfig.base.json" }
root의
package.json
에 커맨드를 추가해준다.{ "scripts": { "start": "yarn workspace @just-pay/client start", "storybook": "yarn workspace @just-pay/design-system storybook" } }
Issues
apps/client
디렉토리에서 커맨드를 입력하였더니 다음과 같은 오류가 발생하였다.$ yarn start
해당 에러는 plug n play 방식이
node_modules
로 모듈을 관리하는 방식이 아니기 때문이다.따라서, devDependencies에 typescript를 추가하고, vscode에서 typescript를 쓰기 위한 세팅을 해준다.
$ yarn add typescript -D $ yarn dlx @yarnpkg/sdks vscode
새로운 에러를 발견하였다.
해당 에러는
apps/client
경로의 node_modules
를 지우고, root 에서 새롭게 설치했더니 해결이 됐다.이번엔 storybook이 말썽이다.
storybook 관련 모듈들의 호이스팅이 제대로 작동하지 않는 것 같았다. 분명히
@storybook/react-webpack5
가 설치되어있는데 로딩이 실패한다는 오류이다.이 부분에서 굉장히 고생을 많이 했는데, 추측된 문제는 다음과 같다.
- yarn workspace에서 storybook는 webpack5를 사용해야 하는 점
- pnp 모드로 모듈을 관리하는데 호이스팅이 제대로 이루어지지 않는다는 점
1번 이슈는 다음과 같은 방법으로 해결이 가능하다.
// package.json { "resolutions": { "@storybook/core-common/webpack": "^5", "@storybook/core-server/webpack": "^5", "@storybook/react/webpack": "^5" } }
2번 이슈는
app/design-system
에도 설치되어있는 @storybook/react-webpack5
를 root의 package.json
에도 설치해줌으로써 해결하였다. 해당 이슈는 yarn berry
의 모듈 관리 방식에 대해서 조금 더 공부해봐야할 것 같다.성공적으로 화면을 볼 수 있게 되었다.
기본적인 세팅은 완료하였고, 다음에는
apps/design-system
에 있는 공통 컴포넌트들을 apps/client
에서 사용할 수 있게 의존성을 주입하고, AWS Amplify를 활용하여 monorepo를 배포해보려고 한다.
댓글