Lerna를 활용한 Mono-Repo 구축 완벽 가이드 - 개념 정리 에서 Lerna
와 Mono-Repo
에 대한 개념을 잡았다면 이번 포스팅에서는 Lerna
를 설치하고 주요 명령어 및 실제로 패키지를 만들고 배포까지 따라 하면서 완벽하게 Lerna
와 Mono-Repo
를 파악하자
예제는 CLI를 통해 간단한 로그를 출력하는 패키지
로 Lerna
를 활용한 Mono-Repo
구조로 구축, 개발, 배포까지 진행할 것이다.
lerna의 독립 모드의 경우 패키지의 버전을 독립적으로 가져가며 좀 더 까다로운 면이 있기 때문에 해당 예제에서는 lerna의 고정모드(Fixed Mode)
가 아닌 독립 모드(Independent Mode)
로 구축할 것이다.
또한 npm
보다는 yarn
을 추구하고 lerna와 좋은 궁합을 보이고 Yarn Workspace
를 사용할 것이기 때문에 yarn
을 사용할 것이다.
- CLI를 통한 간단한 로그 출력 패키지
- 독립 모드(Independent Mode)
- Yarn
- Yarn Workspace
먼저 이전 포스팅에서 개념을 익혔으니 실제로 lerna를 설치해보자.
$ npm install -g lerna
위처럼 lerna를 설치하기가 싫다면 아래처럼 npx
를 통하여 바로 사용하자.
$ npx lerna init
lerna의 publish
명령어는 변경된 패키지를 일괄적으로 Git Remote Repository에 Push를 하므로 Git을 사용해야 한다. Github Repository를 미리 구축해 놓자.
Git을 통해 초기화 및 폴더까지 생성하자.
$ git init [DIR_NAME]
$ cd [DIR_NAME]
폴더를 생성하고 Git을 초기화하였다면 해당 Repository를 lerna로 구성하자.
$ lerna init --independent // or -i
lerna.json
은 lerna를 구성하는 설정 파일이다.
패키지로 배포와 관리된 packages
를 명시해 주며 version 정책을 어떻게 가져갈 것인지며 npmClint는 npm을 사용하지 yarn을 사용할지 지정해 줄 수 있다.
아래와 같이 수정하자.
{
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
]
}
우리는 version 정책을 독립 모드로 가져가기 때문에 version: "independent"
로 지정한 것이고,
yarn을 사용할 것이기 때문에 npmClient: "yarn"
그리고 yarn workspace 사용을 위해 useWorkspaces: true
로 지정하였다.
Root 경로에 있는 package.json
의 역할은 공통된 node module들의 devDependencies
와 최상위에서 실행될 script
들을 명시해준다.
아래와 같이 수정하자.
{
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^3.20.2"
}
}
lerna.json에서 yarn workspace를 사용하였기 때문에 실제로 workspace에 어떤 패키지가 담길 것인지 지정해준다. 보통 lerna.json의 packages의 경로와 일치
한다. 그리고 private: true
로 지정함으로써 Root가 NPM Repository로 배포되는 것을 막아준다.
이제 실제로 사용될 패키지를 만들어보자.
패키지는 packages
경로에 포함되어있어야 하며, 모든 패키지는 lerna.json의 packages 속성에 따른다.
수동으로 직접 폴더를 생성할 수도 있지만 lerna의 create
명령을 통해서도 기본 패키지의 구조를 Scaffolding 할 수 있다.
$ lerna create [PACKAGE_NAME]
우리는 CLI를 통한 Log 출력 패키지를 예시로 들고 있어서 log-cli
와 log-core
라는 두 패키지를 생성하자.
$ lerna create log-cli
$ lerna create log-core
log-cli
는 우리가 CLI command를 입력하여 그 값을 받아 처리하는 패키지이고, log-core
는 입력받은 command를 통해 실제로 로그를 출력하는 패키지이다.
Root 경로에 모든 패키지가 공통으로 사용될 모듈을 설치하자. lerna add
라는 명령어를 사용할 수도 있지만 lerna add
는 패키지 간 종속성 설치 시 사용하는 걸 추천한다.
그냥 사용한다 하더라고 Root 경로에 모듈은 설치되겠지만 각 패키지에 dependencies가 걸리게 되어있다. 그렇기 때문에 Root 경로의 공통 모듈을 npm
또는 yarn
을 통하여 설치하자.
공통으로 사용될 모듈로 eslint
를 설치해보자
$ yarn add eslint --dev --ignore-worksapce-root-check
$ npm install eslint --dev
yarn
을 통해 eslint를 설치하기 위해서는 workspace를 지정하였기 때문에 일반add
를 통해서는 설치가 불가능하다. 그렇기 때문에--ignore-worksapce-root-check
옵션을 지정하도록 하자.
설치 후 Root 경로의 package.json
을 보면 devDependencies
에 eslint
가 설치된 것을 확인 할 수 있다.
이제 각 패키지에 필요한 모듈을 설치해보자.
command를 입력받아야 하는 log-cli에 commander를 설치하자.
각 패키지에 모듈을 설치할 때에는 공통 모듈을 설치하는 것과는 다르게 lerna add
를 통해서 각 패키지에 설치 할 수 있다. 이 과정에서 hoisting
이 일어나고 종속성을 최적화시킨다.
lerna add
를 사용할 때는 --scope
옵션을 통해서 어느 패키지에 설치할 것인가를 명시해준다. --scope
를 주지 않을 경우 모든 패키지에 설치된다.
$ lerna add commander --scope=log-cli
위 명령어 실행 후 파일 주로를 보면 log-cli 경로에 node_modules
폴더가 생성되지 않았다. 하지만 package.json
을 보게 되면 commander 모듈이 추가되어있는 것을 볼 수 있다. 이는 종속성 최적화로 인해 Root 경로에 추가된 것이다.
log-core에서는 console.log를 출력하는 모듈을 만들 것이다.
패키지 설치 방법을 익히기 위해 임의로 로그 문구에 색상을 입힐 수 있는 chalk 모듈을 설치해보자.
$ lerna add chalk --scope=log-core
설치 방법은 log-cli에서 설치한 방법과 동일하다. 다만 다른 게 있다면 log-cli와는 다르게 log-core에는 node_modules 경로가 생성
되었다. 이 역시 hoisting
과정에서 일어난 사항이니 그게 염두에 두지 않아도 된다.
필요한 모듈은 설치가 되었기 때문에 이제 각 패키지에서 기능이 동작되도록 구현하자.
log-core.js
를 수정하자.
const { red } = require('chalk')
function core () {
console.log(red('❤ Running Core !!!!!'))
}
module.exports = core
log-core
에서는 chalk
를 사용하여 console.log
를 출력해 주는 코드를 작성하였다.
log-cli.js
와 log-cli/package.json
을 수정하자
#!/usr/bin/env node
const { program } = require('commander')
const LogCore = require('log-core')
// action
program.action(cmd => LogCore())
program.parse(process.argv)
{
"name": "log-cli",
"version": "1.0.0",
"description": "log-cli-example",
"author": "Your name",
"license": "MIT",
"bin": {
"log-cli": "lib/log-cli.js"
},
"files": [
"lib"
],
"dependencies": {
"commander": "^6.0.0"
}
}
log-cli.js
에서는 commander
와 log-core
를 추가하고 commander
를 통해 command를 입력받으면 log-core
를 수행되게 되어있다.
package.json
에서는 기본적으로 추가되어있던 main
속성 대신 bin
속성을 추가하여 CLI가 가능하게 수정한다.
기능까지 완성이 되었으니 로컬에서 만든 모듈들을 실행해보자.
최초 실행은 log-cli
를 실행하는 것이기 때문에 log-cli
를 설치 후 실행해 보자. 여기서는 npm link
를 통하여 global로 symbolic link
를 생성하였다.
$ npm link packages/log-cli
$ log-cli
log-cli
를 입력하면 결과가 출력되는 것을 확인할 수 있다.
위처럼 로컬에서 실행하면 정상적으로 동작된다. 로컬에서는 log-cli
와 log-core
연관 관계를 인지하고 있기 때문이다. 그렇기 때문에 실제로 패키지를 배포 후 배포된 패키지를 설치하여 실행한다면 아래와 같은 오류가 출력될 것이다.
이 오류는 log-cli
에서 log-core
를 삽입하였는데 실제로 log-cli
에는 log-core
가 종속되지 않았기 때문에 발생한다. 이를 해결하기 위해서는 lerna add
를 통해서 log-cli
에 log-core
를 설치해 해줘야 한다.
$ lerna add log-core --scope=log-cli
이제 모든 변경 사항을 연동된 Git Remote Repository에 반영하자. 그 전에 불필요한 리소스들이 반영되지 않도록 Root 경로에 .gitignore
작성하는 것을 잊지 말자.
아래는 .gitignore
예시이다.
.idea
node_modules
*.lock
*lock.json
$ git add .
$ git commit -m "deploy"
$ git push -u origin master
이제 패키지 배포 이전의 모든 작업이 끝이 났다. 실제로 지금까지 만든 log-cli
와 log-core
를 NPM Repository
에 배포해 보자. NPM Repository에 대해서는 빠르게 배우는 NPM 패키지 생성부터 배포까지 완벽 가이드을 참고하자.
NPM 설정이 준비되었다면 lerna publish
를 통해서 모든 패키지를 배포하자.
NPM Repository에 배포하기 전 log-cli와 log-core의 package.json에서
name
속성을 변경하자. 해당 명칭은 이미 배포된 다른 모듈과 충돌이 나므로 변경해야 한다.
$ lerna publish
위 명령어를 입력하면 log-cli
와 log-core
가 동시에 NPM Repository로 배포된 것을 확인할 수 있다.
NPM Repository에 배포된 패키지는 72시간이 지나면 직접 지울 수 없어서 불필요하다면 즉시 삭제하기 바란다.
$ npm unpublish log-core -f
$ npm unpublish log-cli -f
log-cli
에서 log-core
가 종속되어있기 때문에 log-cli
먼저 삭제해야 한다.
이제 실제로 배포된 패키지를 설치하여 사용해 보자.
$ npm install -g log-cli // or PACKAGE_NAME
lerna에서 독립 모드(Independent)로 사용하게 되면 릴리즈 노트가 걸릴 것이다. 릴리즈 노트는 보통 CHANGELOG.md
로 남게 되는데 이를 위해서는 lerna.json
을 아래와 같이 설정해 주면 기본적인 CHANGELOG
를 사용할 수 있다.
{
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
],
"command": {
"publish": {
"conventionalCommits": true
}
}
}
lerna의 publish
명령어를 실행하면 conventiaonalCommit
이 실행되도록 conventionalCommits
옵션을 지정해 주었다. Conventional commits는 이곳에서 참고하자.
conventionalCommits
옵션을 지정하면 semver
에 따른 버전이 결정되고 commit message
의 기록에 따라 CHANGELOG.md
가 각 패키지 별로 생성된다.
기본적인 옵션 이외에 lerna-changelog를 사용하면 더 적합한 릴리즈 노트를 작성할 수 있다.
여기까지 해서 Lerna를 활용한 Mono-Repo 구축 완벽 가이드 - 개념 정리부터 예제를 통하여 Lerna
와 Mono-Repo
에 대해 알아보았다.
여기서 집고 넘어갈 것은 Lerna
는 단순히 Mono-Repo
를 구축하는 데 도움을 주는 도구에 불과하다. 귀찮고 오래 걸리겠지만 Mono-Repo
의 구조에서 수동으로 생성, 배포, 설치 모두 할 수 있는 것이다. Mono-Repo
의 구조로 간다면 패키지의 관리와 배포가 쉬워지니 반영해 볼 기회가 있다면 적극적으로 추천한다.
해당 글의 원본은 Dev.DY에서 확인할 수 있습니다.