라이브러리
라이브러리 (Libraries)
코드가 커지면 파일을 나누고, 재사용하면서도 공개 범위를 조절하고 싶어져요. Dart의 import와 library 지시자는 바로 그런 모듈화된, 공유 가능한 코드베이스를 만드는 데 도움을 줘요.
출처: Dart 공식 문서
본문
라이브러리는 API를 제공할 뿐 아니라 프라이버시의 단위예요. 밑줄(_)로 시작하는 식별자는 라이브러리 안에서만 보이죠. 모든 Dart 파일(그리고 그것의 파트들)은 library 지시자를 쓰지 않아도 하나의 라이브러리*가 돼요. 라이브러리는 패키지를 통해 배포할 수 있어요.
*라이브러리는 Dart의 단일 컴파일 단위로, 기본 Dart 파일과 그것의 파트들로 구성돼요.
Dart는 public, protected, private 같은 접근 수정자 키워드 대신 밑줄을 사용해요. 다른 언어의 접근 수정자 키워드가 더 세밀한 제어를 제공하는 반면, Dart의 밑줄과 라이브러리 기반 프라이버시는 간단한 설정 메커니즘을 제공하고, 동적 접근의 효율적인 구현을 돕고, 트리 셰이킹(죽은 코드 제거)을 개선해요.
라이브러리 사용하기 (Using libraries)
import를 써서 한 라이브러리의 네임스페이스를 다른 라이브러리의 유효 범위에서 어떻게 사용할지 지정해요. 예를 들어 Dart 웹 앱은 일반적으로 dart:js_interop 라이브러리를 쓰는데, 이렇게 import해요.
import 'dart:js_interop';
import에 필요한 유일한 인자는 라이브러리를 지정하는 URI예요. 내장 라이브러리에는 특별한 dart: 스킴이 있어요. 다른 라이브러리에는 파일 시스템 경로나 package: 스킴을 쓸 수 있죠. package: 스킴은 pub 도구 같은 패키지 관리자가 제공하는 라이브러리를 지정해요.
import 'package:test/test.dart';
URI는 uniform resource identifier의 약자예요. URL(uniform resource locator)은 URI의 흔한 종류죠.
라이브러리 접두사 지정하기 (Specifying a library prefix)
충돌하는 식별자를 가진 두 라이브러리를 import한다면 한쪽 또는 양쪽에 접두사를 지정할 수 있어요. 예를 들어 library1과 library2가 모두 Element 클래스를 가진다면, 코드는 이렇게 될 수 있어요.
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
와일드카드 이름 _를 쓴 import 접두사는 결합(binding)되지 않지만, 그 라이브러리의 비공개가 아닌 확장에는 접근할 수 있게 해줘요.
라이브러리의 일부만 import하기 (Importing only part of a library)
라이브러리의 일부만 쓰고 싶다면 선택적으로 import할 수 있어요.
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
라이브러리 지연 로딩 (Lazily loading a library)
지연 로딩(deferred loading, lazy loading이라고도 함)은 웹 앱이 라이브러리가 필요할 때 그때 그 자리에서 요청에 따라 로드하게 해줘요. 지연 로딩은 다음 조건 하나 이상을 충족하고 싶을 때 쓰세요.
- 웹 앱의 초기 시작 시간을 줄인다.
- A/B 테스트를 수행한다 — 예를 들어 알고리즘의 대안 구현을 시험해 본다.
- 선택 화면, 다이얼로그처럼 드물게 쓰는 기능을 로드한다.
이게 Dart가 모든 지연 컴포넌트를 시작 시점에 로드한다는 뜻은 아니에요. 웹 앱은 필요할 때 웹을 통해 지연 컴포넌트를 다운로드할 수 있죠.
dart도구는 웹이 아닌 다른 타깃에서는 지연 로딩을 지원하지 않아요. Flutter 앱을 만들고 있다면 Flutter 가이드의 deferred components 문서에서 그 구현을 확인하세요.
라이브러리를 지연 로드하려면 먼저 deferred as로 import해요.
import 'package:greetings/hello.dart' deferred as hello;
라이브러리가 필요해지면 라이브러리의 식별자로 loadLibrary()를 호출해요.
Future<void> greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
위 코드에서 await 키워드는 라이브러리가 로드될 때까지 실행을 멈춰요. async와 await에 대해 더 알고 싶다면 비동기 프로그래밍(asynchronous programming) 문서를 확인하세요.
loadLibrary()는 라이브러리에 여러 번 호출해도 문제없어요. 라이브러리는 한 번만 로드되죠.
지연 로딩을 쓸 때 다음을 기억해 두세요.
- 지연 라이브러리의 상수는 import하는 파일에서는 상수가 아니에요. 이 상수들은 지연 라이브러리가 로드될 때까지 존재하지 않는다는 점을 기억하세요.
- import하는 파일에서는 지연 라이브러리의 타입을 쓸 수 없어요. 대신 인터페이스 타입을 지연 라이브러리와 import 파일 양쪽에서 import되는 라이브러리로 옮기는 걸 고려하세요.
- Dart는
deferred as *namespace*로 정의한 네임스페이스에loadLibrary()를 암묵적으로 넣어줘요.loadLibrary()함수는Future를 돌려줍니다.
library 지시자 (The library directive)
라이브러리 수준의 문서 주석이나 메타데이터 어노테이션을 지정하려면 파일의 시작 부분에 있는 library 선언에 붙이세요.
/// A really great test library.
@TestOn('browser')
library;
라이브러리 구현하기 (Implementing libraries)
패키지를 구현하는 방법에 대한 조언은 Create Packages 문서를 참고하세요. 다음을 포함해요.
- 라이브러리 소스 코드를 어떻게 구성할지
export지시자를 어떻게 쓸지part지시자를 언제 쓸지- 여러 플랫폼을 지원하는 라이브러리를 구현하려고 조건부 import와 export를 어떻게 쓸지