
Flutter Web의 새로운 변화: WASM 렌더러 도입과 웹 통합
Flutter로 웹 애플리케이션을 개발할 때 렌더링 엔진의 선택은 매우 중요합니다. 3.10 이전에는 CanvasKit과 HTML 랜더러 중에서 하나를 선택하여 개발하고 했습니다. 그러나, Flutter 3.10 버전부터 도입된 WASM(WebAssembly) 렌더러는 기존 CanvasKit과 HTML 렌더러의 한계를 극복하고 웹 표준을 위해 등장했다고 해도 과언이 아닌데, 과연 그럴만한지 조금 더 알아봅시다.
(특히 웹 플랫폼과의 통합 측면에서 큰 변화가 있어 이를 자세히 살펴보겠습니다.)
Flutter Web 렌더러의 변천사
Flutter Web은 처음 출시될 때부터 두 가지 렌더링 방식을 제공했습니다.
-
HTML 렌더러
- 장점: 초기 로딩 크기가 작음, 기존 웹 요소와 통합이 쉬움
- 단점: 성능이 좋지 않고 플랫폼 간 일관성이 떨어짐
-
CanvasKit 렌더러
- 장점: 뛰어난 성능과 플랫폼 간 일관된 렌더링
- 단점: 큰 초기 다운로드 크기 (~4.4MB), 웹 요소 통합이 제한적
저는 둘 다 다 써봤는데, 처음에는 CanvasKit을 사용했지만 초기 로딩 속도에서 main.dart.js 가 차지하는 파일의 크기가 크다 보니까 결국에는 HTML 렌더러로 빌드를 하게 되었습니다.
WASM 렌더러의 등장과 특징
Flutter 3.10부터 도입된 WASM 렌더러는 완전히 새로운 접근 방식을 제공합니다.
1. 성능과 번들 크기
// WASM 렌더러 활성화 방법
flutter build web --web-renderer=wasm
- CanvasKit 대비 20-30% 더 빠른 초기 로딩
- 번들 크기 ~2MB로 감소
- 점진적 로딩 지원
2. 웹 플랫폼 통합
기존 HTML 렌더러에서 사용하던 웹 통합 기능들이 WASM에서는 다음과 같이 변경되었습니다:
HTML 요소 통합
// HTML 렌더러에서의 방식
HtmlElementView(
viewType: 'iframe-view',
key: UniqueKey(),
)
// WASM 렌더러에서의 방식
PlatformViewLink(
viewType: 'iframe-view',
surfaceFactory: (context, controller) {
return HTMLSurface(
controller: controller,
onPlatformViewCreated: (id) {
// 웹뷰 생성 완료 처리
},
);
},
)
JavaScript 통신
// HTML 렌더러에서의 방식
@JS('console.log')
external void consoleLog(String message);
// WASM 렌더러에서의 방식
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
class WebAPI {
static void callJavaScript() async {
final result = await promiseToFuture(
js.context.callMethod('eval', ['console.log("Hello from WASM!")'])
);
}
}
3. 웹 API 접근성
WASM 렌더러에서는 웹 API 접근 방식이 표준화되었습니다:
// 웹 스토리지 접근
class WebStorageService {
static Future<void> saveData(String key, String value) async {
if (kIsWeb) {
final storage = html.window.localStorage;
storage[key] = value;
}
}
}
// 웹 소켓 연결
class WebSocketService {
static WebSocket? _socket;
static void connect(String url) {
if (kIsWeb) {
_socket = html.WebSocket(url);
_socket!.onMessage.listen((event) {
// 메시지 처리
});
}
}
}
마이그레이션 가이드
기존 HTML 또는 CanvasKit 렌더러에서 WASM으로 전환 시 고려사항:
1. 플랫폼 체크 코드 수정
// 기존 코드
if (kIsWeb && WebRenderer.current == WebRenderer.html) {
// HTML 렌더러 특정 코드
}
// WASM 대응 코드
if (kIsWeb) {
if (WebRenderer.current == WebRenderer.wasm) {
// WASM 특정 처리
} else {
// 기존 렌더러 처리
}
}
2. 플러그인 호환성
# pubspec.yaml
dependencies:
# WASM 호환 플러그인 버전 지정
webview_flutter: ^4.0.0 # WASM 지원 버전
url_launcher: ^6.1.0 # WASM 지원 버전
3. 웹 리소스 로딩 최적화
class AssetLoader {
static Future<void> preloadAssets() async {
if (kIsWeb && WebRenderer.current == WebRenderer.wasm) {
// WASM 특화 프리로딩 로직
await Future.wait([
precacheImage(AssetImage('assets/heavy_image.png'), context),
// 기타 리소스 프리로딩
]);
}
}
}
성능 비교 및 벤치마크
실제 프로덕션 앱에서 측정된 성능 지표입니다:
지표 | HTML | CanvasKit | WASM |
---|---|---|---|
초기 로딩 크기 | ~500KB | ~4.4MB | ~2MB |
First Paint | 6.5초 | 12.9초 | 8.0초 |
복잡한 애니메이션 FPS | 30-40 | 55-60 | 58-60 |
메모리 사용량 | 높음 | 중간 | 낮음 |
DOM 인터랙션 성능 | 좋음 | 제한적 | 매우 좋음 |
브라우저 지원 및 제한사항
지원 브라우저
- Chrome 90+
- Firefox 90+
- Safari 16.4+
- Edge 90+
알려진 제한사항
- 일부 레거시 JavaScript API 호출 방식 변경 필요
- 특정 HTML5 Canvas 기능의 제한적 지원
- WebGL 2.0 필수 요구
특히, 저같은 경우에는 회사에서 사용하는 Flutter WebApp에 다른 회사의 서비스를 이용중인데, 자바스크립트로 SDK가 제공되다보니 Wasm으로 바꾸기 좀 어려운(?) 점이 있습니다.
실제 사용 사례
1. 복잡한 데이터 시각화 앱
class DataVisualization extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: ChartPainter(),
child: GestureDetector(
onPanUpdate: (details) {
// WASM에서 더 부드러운 인터랙션
},
),
);
}
}
2. 웹 기반 이미지 편집기
class ImageEditor extends StatefulWidget {
@override
Widget build(BuildContext context) {
return Stack(
children: [
// 이미지 편집 캔버스
CustomPaint(
painter: ImagePainter(),
),
// 필터 컨트롤
if (kIsWeb && WebRenderer.current == WebRenderer.wasm)
WasmOptimizedFilters(),
// ...
],
);
}
}
결론
WASM 렌더러는 Flutter Web의 새로운 장을 열었습니다. 특히 웹 플랫폼과의 통합 측면에서 기존의 한계를 많이 극복했으며, 성능과 개발 경험 모두에서 큰 발전을 이루었습니다. 다만, 아직 실험적 기능으로 분류되어 있어 프로덕션 환경에서는 신중한 검토가 필요합니다.
그래도 빠르게 발전하고 있는 Flutter 라고 생각이 드니, WASM이 Flutter 내에서 공고하게 자리잡길 기원합니다.
참고 자료