storybook 배포를 위한 monorepo 환경 구축하기

storybook 배포를 위한 monorepo 환경 구축하기

생성일
2023년 06월 05일
태그
yarn workspace
storybook
MonoRepo

Background

최근 사이드 프로젝트에서 컴포넌트 주도 개발(CDD)와 공통 컴포넌트 문서화를 위해 storybook을 도입하였다. 로컬에서 작성한 storybook 코드를 팀원들에게도 공유하기 위해 배포를 해야하는 상황에서 배포할 겸 monorepo 를 도입하기로 결정하였다.
monorepo 도입을 통해 한 번의 컴포넌트 작성으로 실제 서비스에서도 사용이 가능하고, 배포된 storybook에서도 사용이 가능해 재사용성을 높일 수 있다는 기대감에 도입하려고 한다. 또한, 서비스 모니터링을 위한 관리자 페이지도 다른 도메인으로 배포할 예정이었는데, 이도 monorepo 로 도입을 하게 되면 하나의 프로젝트에서 전부 관리할 수 있다는 편리함이 있다.
monorepo 를 어떤 환경으로 구성할까 고민하던 중에 turborepoyarn workspace 둘 중 하나로 하기로 했다. Lerna 는 상대적으로 진입장벽이 있다고 판단하였다. 사이드 프로젝트는 현재 yarn berry 환경으로 구성되어있기 때문에 yarn workspace 를 사용하기로 결정하였다.

적용하기

workspacemonorepo 의 하위 프로젝트를 의미한다. 정식으로 배포되는 서비스의 디렉토리는 client 로, storybook을 위한 디렉토리는 design-system 으로 정했고, 이 두 가지가 각각 workspace 라 할 수 있겠다.

package.json

root 디렉토리의 package.json 에 다음과 같은 세팅을 해준다.
{ "workspaces": { "packages": [ "apps/*" ] }, "packageManager": "yarn@3.5.0" }
apps 디렉토리 하위의 모든 폴더들을 workspace로 지정한다는 의미이다.
notion image
 
apps/design-system 디렉토리를 생성하고 해당 경로로 들어가서 다음과 같은 커맨드를 입력해준다.
$ npx storybook@latest init
ReactWebpack5 를 선택해주면 다음과 같이 패키지들을 설치해준다.
// 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/clientpackage.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
notion image
해당 에러는 plug n play 방식이 node_modules 로 모듈을 관리하는 방식이 아니기 때문이다.
따라서, devDependencies에 typescript를 추가하고, vscode에서 typescript를 쓰기 위한 세팅을 해준다.
$ yarn add typescript -D $ yarn dlx @yarnpkg/sdks vscode
 
새로운 에러를 발견하였다.
notion image
해당 에러는 apps/client 경로의 node_modules 를 지우고, root 에서 새롭게 설치했더니 해결이 됐다.
notion image
 
이번엔 storybook이 말썽이다.
notion image
storybook 관련 모듈들의 호이스팅이 제대로 작동하지 않는 것 같았다. 분명히 @storybook/react-webpack5 가 설치되어있는데 로딩이 실패한다는 오류이다.
이 부분에서 굉장히 고생을 많이 했는데, 추측된 문제는 다음과 같다.
  1. yarn workspace에서 storybook는 webpack5를 사용해야 하는 점
  1. 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 의 모듈 관리 방식에 대해서 조금 더 공부해봐야할 것 같다.
notion image
성공적으로 화면을 볼 수 있게 되었다.
 
기본적인 세팅은 완료하였고, 다음에는 apps/design-system 에 있는 공통 컴포넌트들을 apps/client 에서 사용할 수 있게 의존성을 주입하고, AWS Amplify를 활용하여 monorepo를 배포해보려고 한다.

References

댓글

guest