패키지 의존성의 개념
Dart에서 패키지 의존성 관리는 프로젝트가 다른 라이브러리나 패키지에 의존하는 경우에 필요한 작업이다. Dart 프로젝트는 여러 개의 외부 패키지를 필요로 할 수 있으며, 이 패키지들은 프로젝트의 동작에 중요한 역할을 한다. Dart 생태계에서는 pubspec.yaml
파일을 통해 이러한 패키지들을 관리한다.
pubspec.yaml
파일은 프로젝트의 메타데이터와 의존성을 정의하는 핵심 파일로, 여기에는 다음과 같은 정보가 포함된다:
- 프로젝트 이름, 설명
- 프로젝트가 의존하는 패키지 목록과 그 버전
- 추가적으로 사용할 수 있는 dev_dependencies
패키지 의존성 관리를 효율적으로 하기 위해서는 버전 관리를 잘 설정하고, 각 패키지가 서로 충돌하지 않도록 해야 한다.
버전 규칙과 호환성
Dart는 패키지 의존성 관리에서 세맨틱 버전 관리(Semantic Versioning, SemVer)를 따른다. SemVer은 패키지의 버전을 세 부분으로 나누어 관리한다:
- Major: 주 버전은 API가 불안정해질 때 증가한다.
- Minor: 부 버전은 새로운 기능이 추가될 때 증가하지만, 이전 버전과의 호환성은 유지된다.
- Patch: 패치 버전은 버그 수정 등 작은 변경 사항일 때 증가한다.
Dart에서 버전 번호 앞에 다음과 같은 제약을 사용할 수 있다:
- ^: 호환 가능한 버전 범위를 나타낸다. 예를 들어,
^1.2.3
은>=1.2.3 <2.0.0
범위 내에서의 패키지 버전을 허용한다. - >=: 해당 버전 이상을 허용한다.
- <: 해당 버전 미만을 허용한다.
pubspec.yaml 파일 예시
다음은 pubspec.yaml
파일의 예시이다. 여기서 프로젝트가 특정 패키지들에 의존하고 있음을 확인할 수 있다:
name: my_project
description: A sample Dart project
version: 1.0.0
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
http: ^0.13.0
json_annotation: ^4.0.0
dev_dependencies:
build_runner: ^2.0.0
json_serializable: ^4.1.0
위 파일에서 dependencies
항목은 프로젝트에서 사용되는 패키지들의 목록을 나타내며, dev_dependencies
는 개발 환경에서만 필요한 패키지를 정의한다.
이와 같은 구조는 패키지 간 의존성을 명확하게 정의하며, 프로젝트를 빌드하거나 배포할 때 일관성 있는 환경을 유지하는 데 도움을 준다. 특히, build_runner
와 같은 패키지는 코드 생성이나 빌드 프로세스를 자동화하는 데 사용되며, 일반적으로 개발 단계에서만 필요하다.
의존성 충돌 해결
프로젝트가 여러 패키지를 의존하게 될 때, 동일한 패키지의 서로 다른 버전이 요구될 수 있다. 이를 의존성 충돌이라고 하며, Dart에서는 이러한 충돌을 해결하기 위해 pub resolve 메커니즘을 사용한다. pub get
명령을 실행하면 Dart는 pubspec.lock
파일을 생성하여 실제로 사용되는 패키지 버전들을 고정시킨다.
Dart에서 의존성 충돌을 해결하는 방법에는 두 가지가 있다:
- 버전 제약을 완화: 의존하는 패키지의 버전 범위를 넓게 설정하여 충돌을 피할 수 있다. 예를 들어, 특정 패키지의 버전을
^1.0.0
에서^1.0.0 <=1.2.3
으로 확장할 수 있다. - 패키지 업데이트: 호환되지 않는 버전의 패키지를 최신 버전으로 업데이트하여 충돌을 해결할 수 있다. 이를 통해 최신 API를 사용하면서 호환성을 유지할 수 있다.
pubspec.lock 파일
pubspec.lock
파일은 pubspec.yaml
파일의 의존성을 기반으로 Dart 패키지 관리자(pub)가 해결한 실제 패키지 버전을 기록하는 파일이다. 이 파일은 프로젝트의 의존성 트리를 고정된 상태로 유지하여, 동일한 패키지 버전을 사용하도록 보장한다. pubspec.lock
파일이 없다면, 다른 개발자가 동일한 코드를 실행할 때 패키지 버전이 달라질 수 있어, 예기치 않은 버그나 비호환 문제가 발생할 수 있다.
pubspec.lock
파일의 주요 목적은 다음과 같다:
- 프로젝트의 의존성을 특정 버전으로 고정하여 환경 간의 일관성을 유지
- 패키지 버전 충돌을 방지
- 동일한 의존성을 갖는 다른 개발자가 협력할 때의 재현 가능성 확보
pub get
과 pub upgrade
명령어
Dart에서 패키지 의존성을 관리할 때 자주 사용하는 두 가지 명령어가 있다: pub get
과 pub upgrade
.
pub get
pub get
명령어는 pubspec.yaml
파일을 기반으로 필요한 패키지를 설치하고, 그 패키지들의 정확한 버전 정보를 pubspec.lock
파일에 기록한다. 이 명령어는 일반적으로 프로젝트를 처음 시작할 때 또는 새로운 패키지를 추가한 후 실행한다. pub get
은 이미 pubspec.lock
에 기록된 버전 정보를 우선적으로 사용하여, 의존성 버전이 변하지 않도록 보장한다.
$ dart pub get
pub upgrade
pub upgrade
명령어는 패키지들의 버전을 최신으로 업데이트한다. 만약 특정 패키지가 새로운 기능이나 버그 수정을 포함한 버전을 출시했다면, 이 명령어를 통해 의존성 목록을 최신 상태로 유지할 수 있다. pub upgrade
는 기존의 pubspec.lock
파일을 무시하고, 가능한 최신 버전으로 패키지들을 다시 해결한다.
$ dart pub upgrade
버전 충돌 해결 시나리오
다음과 같은 예시를 통해 버전 충돌을 해결하는 과정을 살펴보자. 만약 두 개의 패키지가 서로 다른 버전의 http
패키지에 의존하고 있다면, Dart 패키지 관리자는 이를 해결하려고 시도할 것이다.
- 패키지 A는
http: ^0.12.0
버전을 요구 - 패키지 B는
http: ^0.13.0
버전을 요구
이러한 상황에서는, 두 패키지가 모두 만족할 수 있는 호환 가능한 버전을 찾는 것이 중요하다. Dart의 의존성 해결 알고리즘은 가능한 경우 두 버전을 모두 충족할 수 있는 최적의 버전을 찾아낸다. 만약 호환 가능한 버전이 존재하지 않으면, 에러가 발생하고 개발자는 의존성을 수정해야 한다.
dev_dependencies와 의존성 분리
프로젝트의 의존성은 크게 두 가지로 분류된다:
- dependencies: 애플리케이션 코드에서 실제로 사용되는 패키지들
- dev_dependencies: 테스트나 빌드 도구와 같은 개발 단계에서만 사용되는 패키지들
예를 들어, test
패키지와 같은 도구는 애플리케이션이 배포될 때는 필요하지 않지만, 개발 중에는 필수적이다. 이러한 개발 의존성은 dev_dependencies
섹션에 따로 정의할 수 있다. 이렇게 분리함으로써, 애플리케이션 배포 시 불필요한 패키지들을 포함하지 않도록 최적화할 수 있다.
pubspec.yaml
의 의존성 제약 설정
pubspec.yaml
파일에서 의존성을 설정할 때, Dart에서는 다양한 방식으로 의존성을 제어할 수 있다. Dart 프로젝트는 외부 패키지뿐만 아니라 로컬 패키지나 Git에서 가져온 패키지, 그리고 패키지 아카이브에서 직접 설치한 패키지를 사용할 수 있다. 각 의존성은 아래와 같은 방식으로 정의된다:
패키지 의존성
가장 일반적인 방법은 pub.dev에서 제공하는 패키지를 dependencies
에 추가하는 것이다. 패키지는 버전 제약과 함께 추가되며, pub가 이를 자동으로 다운로드하고 관리한다.
dependencies:
http: ^0.13.0
json_annotation: ^4.0.0
Git 의존성
특정 패키지를 Git 저장소에서 직접 가져오고 싶을 때는, Git URL을 사용하여 의존성을 추가할 수 있다. Git 의존성은 저장소 URL뿐만 아니라 특정 브랜치나 태그, 커밋 해시로도 지정할 수 있다.
dependencies:
my_package:
git:
url: https://github.com/username/my_package.git
ref: master
로컬 패키지 의존성
로컬 디렉토리에서 패키지를 의존성으로 추가할 수도 있다. 프로젝트 내부의 다른 모듈을 테스트하거나 공유할 때 사용된다.
dependencies:
my_local_package:
path: ../my_local_package
의존성 관리 자동화 도구
의존성 관리는 Dart 생태계에서 자동화된 도구로 더욱 효율적으로 처리할 수 있다. 이러한 도구는 패키지 관리뿐만 아니라 코드 빌드 및 테스트에도 도움이 된다.
- Pub: Dart 패키지 관리 도구로,
pub get
과pub upgrade
같은 명령을 통해 의존성을 쉽게 설치하고 업데이트할 수 있다. - Build Runner: Dart와 Flutter 프로젝트에서 코드 생성과 빌드를 자동화하는 도구이다. 주로 코드 제너레이션과 같은 작업에 사용되며,
build_runner
패키지를 통해 실행된다.
$ dart run build_runner build
이러한 도구를 사용하면 수작업으로 패키지를 설치하거나 관리할 필요 없이, 프로젝트에서 사용하는 패키지들을 자동으로 관리할 수 있다. 이를 통해 개발자는 더 빠르고 일관된 개발 환경을 유지할 수 있다.
Pub 캐시 관리
Pub는 패키지를 설치할 때 캐시 디렉토리를 사용하여 동일한 패키지를 여러 번 다운로드하지 않도록 한다. 기본적으로 ~/.pub-cache
경로에 패키지가 저장되며, 이는 동일한 패키지를 사용하는 여러 프로젝트가 있을 때 다운로드 시간을 절약해 준다. 때로는 캐시된 패키지에 문제가 발생하거나, 버전 충돌이 있을 경우 캐시를 지워야 할 수도 있다.
캐시를 삭제하는 명령어는 다음과 같다:
$ dart pub cache clean
이 명령어는 모든 캐시된 패키지를 삭제하며, 이후 프로젝트에서 다시 필요한 패키지를 다운로드하게 된다.
의존성 감사와 보안
의존성 관리에서 중요한 부분 중 하나는 외부 패키지의 보안이다. Dart 생태계에서는 패키지의 안전성을 보장하기 위해 몇 가지 툴을 제공한다. 예를 들어, 패키지가 신뢰할 수 없는 소스에서 다운로드된 경우, 경고가 발생하며 개발자가 이를 확인할 수 있도록 한다.
또한 pub.dev
에서는 각 패키지에 대해 Dart 패키지 스코어를 제공하여, 패키지의 품질과 유지 관리 상태를 점검할 수 있다. 이러한 점수는 패키지의 최신 버전 여부, 문서화 수준, 그리고 코드의 품질을 기반으로 평가된다.
보안적인 관점에서, 패키지를 사용할 때는 반드시 최신 버전으로 유지하고, 가능하면 의존성을 주기적으로 감사하여 문제를 예방하는 것이 중요하다.