Melos로 Multi Package Flutter프로젝트 관리

Andrew Lee
andrewlee1228
Published in
12 min readDec 13, 2021

Flutter 프로젝트는 기본적으로 단일 패키지로 생성이 됩니다.
즉, 모든 기능과 유틸리티가 하나의 패키지에 존재하게 됩니다.

하지만 앱의 규모가 커지면서 우리는 기능을 재활용하고 문제를 더 잘 분리하기 위해서 여러 패키지로 나누고자 하는 필요성이 제기됩니다. 그리고 우리의 기술력을 뽐내기 위해서 패키지중 일부를 오픈 소스로 만들 수 있습니다. (당근마켓과 같은 회사들은 앱에서 사용하는 디자인 시스템을 오픈소스로 공개중입니다 : ) )

Multi패키지가 필요한 상황이 궁금하신가요?
좀 더 구체적으로 제가 그동안 개발했던 도메인에서의 경험으로 다음과 같은 예시를 보여드리겠습니다.

  • 여러명의 개발자가 합류하여 협업
    플러터 개발자 여럿이서 협업하기 위해서 문제를 분리하고 나누어 개발을 진행하고 그결과를 하나로 통합하여 기능을 완성합니다.
  • 엔터프라이즈급 앱으로의 성장 — “여기놀자”
    7년전에 우리는 모텔의 위치와 전화번호를 제공하는 서비스를 시작했습니다. 지금은 시리즈 A,B,C,D 의 투자를 거치며 비즈니스가 급성장 하였고 비즈니스 도메인은 모텔에서 시작했지만 항공,고속버스,해외숙박,국내레저,해외 액티비티등을 포함하는 슈퍼앱으로 확장하고 있습니다.
  • B2B 와 B2C가 결합되어 고객에게 제공되는 서비스 개발
    예를 들어 동대문 도매상과 소매를 연결한다거나 , 음식점과 배달원과 고객이 사용하는 O2O 서비스를 만들려면 각각의 앱이 공통된 비즈니스 로직을 공유 할 수 있습니다.
  • 네이버의 사례
    네이버와 같은 크고 많은 제품을 만드는 곳에서는 핵심기능들을 앱 모듈(=패키지)로 만들어 각각의 프로덕션들이 가져다 사용할 수 있도록 하는 별도의 개발팀이 존재합니다. 예를들어 네이버 앱과 네이버 지식인앱은 화상채팅 기능을 공통된 모듈로 제공받아 만들어지고 있습니다.

그렇다면 우리도 Multi Package 한번 만들어 볼까요?

이전 글에서 monorepo로 플러터에서 멀티패키지를 관리하는 가장 기본적인 방법을 소개하였습니다. — 이전 글 보기

오늘은 다른 방법으로 접근해보고자 합니다.

MELOS를 소개합니다.

멜로스는 Multi Package Dart/Flutter 프로젝트를 관리하기 위한 CLI 도구 입니다.

Melos 는 Flutter 커뮤니티에서 잘 알려진 팀, 즉 invertase 에 의해 개발되었습니다 . 웹사이트에서 Melos에 대한 자세한 내용을 읽어 보시겠지만 간단하게 설명하자면 다음과 같습니다.

  • 자동 버전 관리 및 변경 로그 생성.
  • pub.dev에 패키지를 자동으로 게시합니다
  • 로컬 패키지 연결 및 설치.
  • 패키지 전체에서 동시 명령 실행.
  • 로컬 패키지 및 해당 종속성 목록.

이제 Melos를 사용하여 위의 모든 작업을 수행하는 방법을 살펴보겠습니다.

참고 : 직접 해보면서 배우려면 스타터 프로젝트를 다운로드 하세요 . 프로젝트의 최종 버전을 찾을 수 있는 또 다른 분기가 있습니다.

멜로스 설치

먼저 멜로스를 설치해 보겠습니다.
사전에 Flutter SDK가 설치되어 있어야 합니다.

터미널에서 다음 명령을 실행합니다.

dart pub global activate melos

다음 단계는 IDE에서 스타터 프로젝트를 여는 것입니다. Intellij를 사용하는 것을 선호하며 Melos에서 제공하는 몇 가지 멋진 GUI 기능을 보여 드리겠습니다. 프로젝트 구조는 다음과 같아야 합니다.

이제 앱의 루트 디렉토리에 melose.yaml 파일을 만듭니다.
파일의 내용은 다음과 같습니다.

name: melos_demopackages:
- utility/**
- feature/**
- '*'

위 스크립트에 대해 설명하겠습니다.
name: 프로젝트 이름을 지정합니다. pubspec.yaml 파일을 열어보면 프로젝트 이름을 찾을 수 있습니다.

package: 이 목록에는 프로젝트 내의 개별 패키지에 대한 경로를 작성합니다.

Melos Bootstrap(미리 준비된 프로젝트)

우리는 프로젝트를 3개의 레이어로 나누었습니다.

첫 번째 계층은 프로젝트의 다른 모든 패키지에 적용되는 공통 구성을 보유하는 루트 프로젝트입니다.

두 번째 레이어에는 서로 의존하지 않는 독립적인 기능 패키지가 있습니다.

세 번째 계층은 여러 기능 패키지에서 사용되는 유틸리티 패키지로 구성됩니다.

우리가 직면한 문제?

하나의 패키지로 구성된 flutter 프로젝트에서 다음 작업을 실행하는 것은 매우 간단합니다.

flutter pub getflutter testflutter analyzeflutter test --coverage // 코드 커버리지 생성하기

그러나 Multi 패키지 프로젝트에서는 내부의 모든 패키지에 대해서 해당 작업을 반복하고 작업이 완료 될 때 요약된 결과를 제공해야 하기 때문에 어려울 수 있습니다.

이러한 문제를 melos 어떻게 해결하고 있는지
먼저 melos 프로젝트에 세팅하고 알아보겠습니다!

이제 프로젝트의 루트에서 다음의 명령어를 입력합니다.
melos bootstrap

그러면 melos가 모든 로컬 패키지를 연결하고 종속성을 자동으로 업데이트 합니다. 터미널에서 다음과 같이 출력이 됩니다.

melos bootstrap 은 중요한 명령어 중에 하나 입니다.
패키지의 버전관리를 자동으로 해주고 프로젝트를 정리해주는데요
왜 해당 명령어를 써야 하는지 자세한 이유는 여기를 봐주세요

Melos Clean

프로젝트에서 다중 패키지들의 임시 파일을(빌드 아티팩트, pub 파일 등) 제거하려는 경우 이 명령을 실행할 수 있습니다. 명령은 다음과 같습니다.

melos clean

명령들

다양한 명령들을 사용해보겠습니다.

특정 패키지의 테스트 케이스를 실행하기
melos.yaml 파일에 다음 명령을 추가합니다.

name: melos_demopackages:
- utility/**
- features/**
- '*'

scripts:
test:selective_unit_test:
run: melos exec --dir-exists="test" --fail-fast -- flutter test --no-pub --coverage
description: Run Flutter tests for a specific package in this project.
select-package:
flutter: true
dir-exists: test

위 스크립트에 대해서 설명할게요
1) 사용자 정의 스크립트를 만들었습니다. 즉 test:selective_unit_test
실행되면 단위 테스트를 실행할 패키지를 선택하는 옵션이 표시됩니다.

2) Melos는 필터 기준에 맞는 패키지를 선택할 수 있는 강력한 필터링 옵션을 제공합니다. 위의 스크립트에서는 --dir-exists="test"필터링 옵션으로 사용 했습니다. test폴더 로 구성된 모든 패키지를 필터링 합니다. 웹 사이트에서 더 많은 필터링 옵션을 찾을 수 있습니다.

3) --fail-fast테스트 케이스가 실패하면 스크립트 실행을 즉시 종료합니다.

4) description섹션 을 사용하여 각 스크립트에 사람이 읽을 수 있는 설명을 제공할 수 있습니다 .

5) 이 명령의 이름을 test:selective_unit_test와 같이 지정한 이유가 궁금할 것입니다. 다음 명령이 질문에 대답할 것입니다. 😃

6) melos exec가 하는 일을 여기에서 자세히 읽을 수 있습니다. 기본적으로 프로젝트 내의 모든 패키지에서 명령 또는 스크립트를 실행합니다.

다음의 명령어로 테스트를 실행합니다.

melos run test:selective_unit_test

위의 명령으로 test 폴더가 포함된 패키지를 찾을 수 있었습니다. 옵션으로 2를 입력하면 다음 출력이 표시됩니다.

모든 패키지에서 테스트 케이스를 실행해 보겠습니다.

이제 프로젝트의 모든 단위 테스트 케이스를 실행할 다음 명령어를 작성하십시요. 그러면 이제 옵션을 선택하라는 메시지가 표시되지 않습니다.

scripts:
test:
run: melos run test:selective_unit_test --no-select
description: Run all Flutter tests in this project.

위 스크립트 명령어를 분석하겠습니다.

  1. 이 명령은 기본적으로 이전 명령을 --no-select인수로 실행합니다 . 즉, 모든 단위 테스트를 실행합니다.
  2. melos run test이 명령을 실행 하는 데 사용할 수 있습니다 . 이전 단계인 테스트: selective_unit_test에서 만든 것과 같은 여러 가지 테스트 명령 변형이 있을 수 있기 때문에 이 명령 테스트의 이름을 지정했습니다. 또한 테스트 : e2e_test, 테스트 : bdd_test 등 더 많은 변형을 만들 수 있습니다. 모든 변형을 함께 결합하고 단일 명령인 테스트에서 실행할 수 있습니다.

모든 패키지에서 analyze 명령어 실행

analyze:
run: melos exec -- flutter analyze .
description: Run `dart analyze` in all packages.

모든 패키지에서 실행 melos run analyze하도록 실행할 수 있습니다

전체 프로젝트의 Code Coverage 생성

combine_coverage.sh 에 사용자 정의 스크립트가 있습니다.
이 스크립트는 서로 다른 패키지의 모든 lcov.info 파일이 하나의 lcov.info 파일로 병합되도록 합니다.
그런 다음 이 방법을 사용하여 lcov.info 파일을 HTML로 변환할 수 있습니다.

combine_coverage.sh 스크립트 파일은 다음과 같아요

#!/usr/bin/env bashescapedPath="$(echo `pwd` | sed 's/\//\\\//g')"if grep flutter pubspec.yaml > /dev/null; then
if [ -d "coverage" ]; then
# combine line coverage info from package tests to a common file
if [ ! -d "$MELOS_ROOT_PATH/coverage_report" ]; then
mkdir "$MELOS_ROOT_PATH/coverage_report"
fi
sed "s/^SF:lib/SF:$escapedPath\/lib/g" coverage/lcov.info >> "$MELOS_ROOT_PATH/coverage_report/lcov.info"
rm -rf "coverage"
fi
fi

해당 스크립트를 melos 스크립트 섹션 아래에 다음과 같이 작성하여 같이 동작하도록 합니다.

gen_coverage: melos exec -- 
"\$MELOS_ROOT_PATH/combine_coverage.sh"

MELOS_ROOT_PATH 변수는 MELOS.YAML이 저장된 경로, 즉 루트 프로젝트를 제공합니다.
스크립트의 실행이 완료된 후에. 우리는 프로젝트에서 커버리지 보고 폴더를 볼 수 있을 것 입니다.
이제 우리는 전체 프로젝트에 대한 보고서 하나의 lcov.info 파일을 가지게 되었습니다.

이제 우리의 melos.yaml 파일은 다음과 같습니다.

name: melos_demopackages:
- utility/**
- features/**
- '*'
scripts:
test:selective_unit_test:
run: melos exec --dir-exists="test" --fail-fast -- flutter test --no-pub --coverage
description: Run Flutter tests for a specific package in this project.
select-package:
flutter: true
dir-exists: test
test:
run: melos run test:selective_unit_test --no-select
description: Run all Flutter tests in this project.
analyze:
run: melos exec -- flutter analyze .
description: Run `dart analyze` in all packages.
gen_coverage: melos exec -- "\$MELOS_ROOT_PATH/combine_coverage.sh"

IDE에서 GUI 옵션 활용하기

터미널을 통해 이러한 명령을 실행하고 싶지 않고 GUI를 사용하여 실행하고 싶다면 이를 멜로스가 지원합니다.
모든 명령을 추가한 후 부트스트랩 명령을 다시 실행할 수 있습니다. 이렇게 하면 일부 구성이 생성되고 다음과 같은 GUI 옵션이 표시됩니다.

이제 터미널에 아무 것도 입력하지 않고 이 모든 명령을 실행할 수 있습니다.

Next Steps

이것은 빙산의 일각에 불과합니다. Melos 웹사이트에서 훨씬 더 많은 필터링 옵션과 명령을 배울 수 있습니다.

오늘도 도움이 되었기를 바랍니다 :)
모두 건강하게 해피 코딩하세요 ~

--

--