Dart 튜토리얼 28편: JS interop 과거 방식 이해(dart:js·package:js·dart:js_util)
요약
핵심 요지
- 문제 정의: 기존 코드/패키지에서
dart:js/package:js/dart:js_util이 남아 있을 수 있는데, next-gen interop으로 갈아타려면 “무엇이 무엇이었는지”부터 이해해야 한다. - 핵심 주장: Dart 3.3부터 next-gen JS interop이 도입되었고, legacy interop 라이브러리는 deprecated이며 Wasm에서는 지원되지 않으므로 장기적으로는 마이그레이션이 필요하다.
- 주요 근거: 새 interop(
dart:js_interop,package:web)과 legacy(dart:html,dart:js,package:js,dart:js_util등)의 대응표,package:js의 클래스 기반 선언 예시,@staticInterop설명이 제시된다. - 실무 기준: 운영 코드에서 legacy interop을 발견하면 “Wasm 타깃 가능성”과 “deprecated 일정”을 기준으로 우선순위를 정해 마이그레이션한다.
문서가 설명하는 범위
- next-gen interop 도입 배경과 legacy interop의 위치(대응표 포함)
dart:js,package:js,dart:js_util의 역할 요약과 차이점- legacy interop이 Wasm에서 지원되지 않는다는 제약과 마이그레이션 방향성
읽는 시간: 16분 | 난이도: 초급
참고 자료
문제 상황
웹 프로젝트를 유지보수하다 보면 “과거 방식”이 코드에 남아 있을 수 있습니다.
그 상태에서 Wasm 타깃을 고려하거나, 최신 도구 체인으로 이동하려고 하면 interop 부분이 걸립니다.
그래서 이 글은 “이전 방식이 무엇이었는지”를 짧게 정리해, 이후 마이그레이션 판단을 쉽게 만드는 것이 목적입니다.
해결 방법
단계 1: 새 interop과 legacy interop의 대응 관계를 먼저 잡기
Why
NOTE마이그레이션은 “대체제가 무엇인지”를 알아야 시작할 수 있습니다.
대응표가 있으면, 기존 코드가 어디로 가야 하는지 방향이 잡힙니다.
What
NOTEnext-gen interop 라이브러리와 legacy 라이브러리의 대응표가 함께 제시됩니다.
예를 들어 브라우저 API는package:web로, JS interop는dart:js_interop/dart:js_interop_unsafe로 이동하는 흐름이 제시됩니다.
How
TIP기존 코드에서
dart:html또는package:js가 보이면, 각각package:web또는dart:js_interop계열로 옮겨갈 준비를 한다는 식으로 “대응표 기반 판단”을 습관화합니다.
Watch out
WARNINGlegacy interop이 Dart 3.7 기준으로 deprecated이며, Wasm에서는 legacy interop을 지원하지 않는다는 제약이 제시됩니다.
즉, Wasm 타깃을 고려한다면 legacy interop은 “기능적으로 막힌다”는 전제가 됩니다.
결론: 마이그레이션은 대응표로 방향을 잡고, Wasm 지원 여부를 기준으로 우선순위를 정합니다.
단계 2: dart:js는 “객체 래퍼 + 문자열 기반 접근”이었다
Why
NOTE예전 코드에서
dart:js가 등장하면, 접근 방식 자체가 next-gen과 다를 수 있습니다.
성능/가독성/자동 완성 측면에서 문제를 만들 수 있습니다.
What
NOTE
dart:js는 JS 객체를 감싸는 래퍼를 제공하고, 문자열 기반으로 속성 get/set/call을 수행하는 방식으로 설명됩니다.
이 방식은 래핑 비용이 있고, 문자열 기반이라 코드 완성도 어렵다는 설명이 제시됩니다.
How
TIP
dart:js가 보이면 “문자열 기반 동적 접근”이 포함되어 있을 수 있으므로, 이후 단계에서external기반 선언으로 옮겨야 하는 후보로 분류합니다.
Watch out
WARNING
dart:js의 기능 일부가 다른 interop 라이브러리로 재노출(re-exposed)되었고, 현재는 legacy로 취급된다는 흐름이 제시됩니다.
즉, 새 코드에서 선택할 이유가 거의 없습니다.
결론: dart:js는 legacy 방식이므로, 유지보수에서는 대체 경로로 옮기는 것이 목표입니다.
단계 3: package:js는 “interop 타입/멤버 선언”을 제공했지만, 차이가 있다
Why
NOTE많은 패키지가 과거에
package:js를 사용했습니다.
따라서 마이그레이션 대상에서 가장 자주 마주치는 축입니다.
What
NOTE
package:js는 클래스 기반으로 interop 타입을 선언하는 방식이 제시됩니다.
예시는 다음과 같습니다.@JS()class JSType {}
How
TIP많은 경우
package:js의 클래스 정의를 extension type로 바꾸는 방식으로 마이그레이션할 수 있다는 안내가 제시됩니다.
따라서 코드를 볼 때 “interop 타입 선언”과 “멤버 선언”을 분리해서 파악하면 전환이 쉬워집니다.
Watch out
WARNING
package:js는 동적 디스패치 허용 등 next-gen과 의미가 달라지는 부분이 있고, soundness 보장도 다르다는 차이가 설명됩니다.
즉, 단순 치환으로 끝나지 않을 수 있으며, 테스트로 확인하는 단계가 필요합니다.
결론: package:js는 next-gen과 유사한 점이 있지만 차이도 크므로, 전환은 “부분별로 검증”해야 합니다.
단계 4: dart:js_util은 “유틸 함수 모음”이었고, 지금은 대체 경로가 있다
Why
NOTElegacy 코드는
dart:js_util의 유틸(예: allowInterop, getProperty/callMethod 등)에 의존했을 수 있습니다.
이 기능이 어디로 옮겨졌는지 알아야 마이그레이션이 가능합니다.
What
NOTE
dart:js_util이 제공하던 유틸 기능이dart:js_interop/dart:js_interop_unsafe에 포함되었다는 설명이 제시됩니다.
예를 들어allowInterop는Function.toJS로 이동했다고 안내합니다.
How
TIP
dart:js_util사용 코드를 발견하면 “unsafe API로 대체되는지”를 확인하고, 가능하면 타입이 명시되는 형태(interop 타입/멤버 선언)로 정리합니다.
Watch out
WARNINGlegacy interop은 Wasm에서 지원되지 않으므로, Wasm을 고려한다면 반드시 next-gen interop으로 이동해야 합니다.
즉, 이건 “나중에 하면 좋은 리팩터링”이 아니라 “타깃 지원을 위한 전제 작업”이 될 수 있습니다.
결론: dart:js_util은 next-gen에 대체 경로가 있으므로, Wasm/미래 호환을 위해 마이그레이션을 계획해야 합니다.
공유
이 글이 도움이 되었다면 다른 사람과 공유해주세요!