라이브러리

라이브러리 (Libraries)

코드가 커지면 파일을 나누고, 재사용하면서도 공개 범위를 조절하고 싶어져요. Dart의 importlibrary 지시자는 바로 그런 모듈화된, 공유 가능한 코드베이스를 만드는 데 도움을 줘요.

출처: 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 키워드는 라이브러리가 로드될 때까지 실행을 멈춰요. asyncawait에 대해 더 알고 싶다면 비동기 프로그래밍(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를 어떻게 쓸지

더 알아보기