개요: 기존 프로젝트 구조
처음에는 한개의 vite 프로젝트로 구성해 개발을 시작했습니다.
하지만 이후 해당 프로젝트에 몇개의 앱이 추가되었는데요, 당시에는 빠른 개발을 위해 vite의 설정 파일에 mode를 인자값으로 조절하여 각 mode 마다 필요한 플러그인을 가져오고, 파일의 경로를 지정해 1개의 vite 설정 파일로 여러가지 앱을 빌드하며 개발하고 있었습니다.
하지만 프로젝트가 점점 복잡해지면서 코드 관리가 어려워졌고, 추가적으로 프로젝트를 진행하면서 새로운 앱이 추가될 수 있는 구조다 보니 코드 분리와 의존성 관리, 새로운 기술 스택 도입 등의 다양한 측면에서 고려해봤을 때, 모노레포를 도입하기로 했습니다.
쉽게 프로젝트 마이그레이션하기
마이그레이션 과정은 확인해야 할 사항도 많고, 대규모 작업이 될 수 있어 많은 시간을 소요해야 할 수도 있습니다.
이런 과정을 단축하기 위해서 개발 도구를 몇가지 사용했습니다.
zx
: 자바스크립트에서 쉘 명령어를 호출하고 응답 값을 반환받을 수 있는 래핑 함수를 제공합니다.dependency-cruiser
: 프로젝트의 의존성을 분석 및 시각화 하는 도구입니다.jscodeshift
: JavaScript/TypeScript 코드 변경 도구로, 대규모 코드베이스에서 반복적으로 필요한 코드 수정 작업에 활용하기 좋습니다.
dependency-cruiser
으로 의존성을 분석하고, jscodeshift
로 기계적으로 코드를 수정하고, 이런 과정을 zx
로 스크립트 형태로 작성하면서 진행했습니다.
1. 각 앱이 가지고 있는 의존성 파악하고, 사용하는 의존성만 package.json 파일에 남기기
기존에는 1개의 vite 프로젝트로 개발하다보니, 모든 의존성이 하나의 package.json
파일에서 관리되고 있었습니다. 어떤 앱이 어떤 패키지를 사용하는지를 파악해야 했는데요, 실행해보면서 참조 에러가 생기는 패키지를 하나씩 추가하거나 모든 소스코드를 읽기에는 어려워서 dependency-cruiser
를 통해 분석해봤습니다.
dependency-cruiser 셋업하기
npx dependency-cruiser --init
로 프로젝트를 초기화 해주고, node_modules
를 참조하는 경우도 분석 대상에 포함시켜주기 위해서 설정 파일의 doNotFollow
항목에 주석처리해서 node_modules
도 분석 대상에 포함시켜줘야 합니다.
앱이 가지고 있는 의존성 분석하기
아래 명령어로 특정 파일들을 분석해 어떤 라이브러리를 참조하는지 분석할 수 있습니다. json 형태가 아닌 svg로 시각화 하는 것도 가능합니다.
이후 dependency.json
파일을 열어 summary.violations
를 보면 아래 json 데이터 처럼 어떤 파일에서 어떤 라이브러리를 참조했는지를 알 수 있습니다.
이제 package.json
파일을 복사한뒤, 참조하는 라이브러리를 분석해 각 앱이 사용하고 있는 패키지만 남겨놓도록 스크립트를 작성할 수 있습니다.
이제 package.json
파일에서, 앱에서 사용하는 의존성만 남겨놓을 수 있습니다.
다만 일부 라이브러리 (개발 의존성 등)은 코드 내에서 직접 참조하지 않는 경우가 있기 때문에 실행하면서 빠진 패키지가 있나 확인해줘야 합니다.
2. 공통 설정 적용하기
이후에는 tsconfig나 eslint 등 프로젝트 공통으로 사용할 코드들을 분리하고 적용해줬습니다.
기존에는 단일 프로젝트 였다보니 사용하던 tsconfig나 eslint를 패키지로 만들고, 이를 app
에서 가져와 사용하면 됩니다.
3. 공통 모듈 참조 코드 수정하기
기존에도 각 앱에서 공통적으로 사용하던 코드를 shared
라는 폴더로 만들어 관리했었는데요. 이를 package
로 옮기면서 모듈을 import 하는 코드를 대량으로 수정해줘야 했습니다.
하지만 상대 경로로 import 하고 있었기 때문에, 코드 위치에 따라 ../shared
, ../../../../shared
등 import 코드가 달랐습니다. 그리고 vscode에서 폴더와 파일 위치를 옮기면서 기존 폴더를 모두 temp
라는 임시 폴더에 넣어두고 작업하다보니, vscode의 import 코드 업데이트 기능으로 인해 임시 폴더를 import 하게 된 경우도 있었습니다.
이런 경우에는 단순 정규식으로 잡아 처리하기 까다로워서, jscodeshift
등 코드 변환 도구를 사용하면 비교적 쉽게 해결할 수 있습니다.
shared
라는 이름은 공통 모듈에서만 사용하고 있었어서, 단순하게 shared
라는 이름이 포함된 import 구문이면 새로운 경로로 수정하도록 수정했습니다.
jscodeshift -t transform.cjs ./src --parser=tsx
커맨드로 실행하면 src
폴더 하위에 있는 코드 중 shared
라는 경로를 import 하는 코드가 @repo/shared/<이후 경로>
로 수정됩니다.
4. 앱에서 다른 앱을 참조하는 경우를 찾아 제거하기
이후 자잘한 에러를 수정하고, 코드를 둘러보며 앱을 실행해보고 있는데 하나의 앱에서 다른 앱의 코드를 참조하는 경우를 발견했습니다.
각 앱은 독립된 코드로 구성하고, 공통적인 부분을 package
로 만들어서 사용하려고 했는데 기존 코드에서는 명확한 분리가 없다보니 이런 케이스가 발생했던 것 같습니다.
이를 찾는 과정도 node_modules
를 참조하는 코드를 찾는것과 동일하게 dependency-cruiser
를 활용해서 찾을 수 있습니다.
이를 통해 어떤 코드에서, 어떤 다른 앱의 코드를 참조했는지를 찾을 수 있습니다.
결론
개인적으로 다른프로젝트에서 특정 파일의 번들 사이즈가 너무 크게 만들어지는 이슈를 dependency-cruiser
를 사용해서 편하게 참조가 잘못된 코드를 찾을 수 있었는데요, 코드베이스를 수정하는 규모의 작업에서도 편하게 사용할 수 있는 것 같습니다.
대규모로 코드를 수정해야 하는 작업이 필요하다면, 기계적으로 수정하는 jscodeshift
와 의존성을 분석하는 dependency-cruiser
, zx
를 사용해 빠르고 편하게 작업할 수 있습니다.