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#

NOTE

next-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#

WARNING

legacy 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#

NOTE

legacy 코드는 dart:js_util의 유틸(예: allowInterop, getProperty/callMethod 등)에 의존했을 수 있습니다.
이 기능이 어디로 옮겨졌는지 알아야 마이그레이션이 가능합니다.

What#

NOTE

dart:js_util이 제공하던 유틸 기능이 dart:js_interop/dart:js_interop_unsafe에 포함되었다는 설명이 제시됩니다.
예를 들어 allowInteropFunction.toJS로 이동했다고 안내합니다.

How#

TIP

dart:js_util 사용 코드를 발견하면 “unsafe API로 대체되는지”를 확인하고, 가능하면 타입이 명시되는 형태(interop 타입/멤버 선언)로 정리합니다.

Watch out#

WARNING

legacy interop은 Wasm에서 지원되지 않으므로, Wasm을 고려한다면 반드시 next-gen interop으로 이동해야 합니다.
즉, 이건 “나중에 하면 좋은 리팩터링”이 아니라 “타깃 지원을 위한 전제 작업”이 될 수 있습니다.

결론: dart:js_util은 next-gen에 대체 경로가 있으므로, Wasm/미래 호환을 위해 마이그레이션을 계획해야 합니다.

공유

이 글이 도움이 되었다면 다른 사람과 공유해주세요!

Dart 튜토리얼 28편: JS interop 과거 방식 이해(dart:js·package:js·dart:js_util)
https://moodturnpost.net/posts/dart/dart-js-interop-legacy/
작성자
Moodturn
게시일
2026-01-04
Moodturn

목차