Flutter 튜토리얼 54편: 웹 성능 최적화
Flutter 웹 성능 최적화
Flutter 웹 앱은 모바일과 다른 성능 특성을 가집니다. 이 튜토리얼에서는 웹 환경에서 Flutter 앱의 성능을 측정하고 최적화하는 방법을 배웁니다.
학습 목표
- Flutter 웹의 렌더링 방식 이해하기
- Chrome DevTools로 성능 분석하기
- 웹 특화 최적화 기법 적용하기
- 프로파일 모드 활용하기
1. Flutter 웹의 특성
Why: 웹 환경이 다른 이유
Flutter 웹은 모바일과 다른 환경에서 실행됩니다. 브라우저 위에서 동작하므로 브라우저의 특성과 제약을 이해해야 합니다.
What: 렌더러 옵션
Flutter 웹은 두 가지 렌더러1를 제공합니다.
| 렌더러 | 장점 | 단점 | 적합한 경우 |
|---|---|---|---|
| HTML | 작은 크기, 빠른 초기 로드 | 렌더링 차이 발생 가능 | 텍스트 중심 앱 |
| CanvasKit | 일관된 렌더링, 애니메이션 성능 | 큰 초기 로드 | 그래픽 중심 앱 |
| auto | 환경에 맞게 자동 선택 | 예측 어려움 | 일반적인 경우 |
How: 렌더러 지정하기
# CanvasKit으로 빌드flutter build web --web-renderer canvaskit
# HTML로 빌드flutter build web --web-renderer html
# 자동 선택 (기본값)flutter build web --web-renderer auto실행 시에도 렌더러를 지정할 수 있습니다:
# CanvasKit으로 실행flutter run -d chrome --web-renderer canvaskitWatch out: 주의사항
CanvasKit은 약 2MB의 추가 다운로드가 필요합니다. 모바일 웹 사용자가 많다면 초기 로드 시간을 고려하여 HTML 렌더러를 선택할 수 있습니다.
2. Chrome DevTools 활용
Why: Chrome DevTools가 필요한 이유
Flutter DevTools는 Dart 코드 레벨의 성능을 분석합니다. 웹 앱의 전체적인 성능(네트워크, JavaScript, 렌더링)은 Chrome DevTools로 분석해야 합니다.
What: Performance 패널 이해하기
How: 성능 녹화하기
- Chrome에서 Flutter 웹 앱을 엽니다
- F12를 눌러 DevTools를 엽니다
- Performance 탭을 선택합니다
- 녹화 버튼(⏺)을 클릭하거나 Ctrl+E를 누릅니다
- 성능을 측정할 동작을 수행합니다
- 녹화 중지 버튼을 클릭합니다
How: Timeline 분석하기
녹화 결과에서 다음을 확인합니다:
| 색상 | 의미 | 문제 시 조치 |
|---|---|---|
| 노란색 | JavaScript 실행 | Dart 코드 최적화 |
| 보라색 | 레이아웃/스타일 계산 | 위젯 트리 단순화 |
| 녹색 | 페인팅 | 리페인트 최소화 |
| 회색 | 유휴 시간 | 정상 |
How: 특정 구간 분석하기
프레임 드롭이 발생한 구간을 확대하여 어떤 작업이 오래 걸렸는지 확인합니다.
Watch out: 주의사항
Chrome DevTools의 Performance 탭은 많은 정보를 표시합니다. 처음에는 Main Thread와 FPS 그래프에 집중하세요. 빨간색 막대가 있는 곳이 성능 문제가 발생한 지점입니다.
3. 디버그 플래그 활용
Why: 상세한 타이밍 정보가 필요한 이유
Chrome DevTools는 전체적인 성능을 보여주지만, Flutter 내부에서 어떤 작업이 오래 걸렸는지는 알 수 없습니다. 디버그 플래그를 사용하면 Flutter 내부의 타이밍 정보를 확인할 수 있습니다.
What: 사용 가능한 디버그 플래그
import 'package:flutter/rendering.dart';
// 위젯 빌드 타이밍bool debugProfileBuildsEnabled = false;
// 사용자 위젯만 프로파일링bool debugProfileBuildsEnabledUserWidgets = false;
// 레이아웃 타이밍bool debugProfileLayoutsEnabled = false;
// 페인트 타이밍bool debugProfilePaintsEnabled = false;| 플래그 | 측정 대상 | 사용 시점 |
|---|---|---|
debugProfileBuildsEnabled | 모든 위젯 빌드 | 빌드 병목 찾기 |
debugProfileBuildsEnabledUserWidgets | 사용자 위젯만 | 내 코드에 집중 |
debugProfileLayoutsEnabled | 레이아웃 계산 | 레이아웃 병목 찾기 |
debugProfilePaintsEnabled | 페인팅 | 렌더링 병목 찾기 |
How: 디버그 플래그 활성화
import 'package:flutter/foundation.dart';import 'package:flutter/rendering.dart';import 'package:flutter/material.dart';
void main() { // 프로파일/디버그 모드에서만 활성화 if (kDebugMode || kProfileMode) { debugProfileBuildsEnabled = true; debugProfileBuildsEnabledUserWidgets = true; debugProfileLayoutsEnabled = true; debugProfilePaintsEnabled = true; }
runApp(const MyApp());}How: 타임라인에서 확인하기
디버그 플래그를 활성화한 후 Chrome DevTools의 Performance 패널에서 녹화하면 Flutter 이벤트가 타임라인에 표시됩니다:
Build: MyHomePage (1.2ms) Build: Scaffold (0.8ms) Build: AppBar (0.3ms) Build: Column (0.5ms)Layout: RenderFlex (0.4ms)Paint: RenderDecoratedBox (0.2ms)Watch out: 주의사항
디버그 플래그는 성능에 영향을 줍니다.
배포 빌드에서는 반드시 비활성화해야 합니다.
kDebugMode 또는 kProfileMode 체크를 잊지 마세요.
4. 프로파일 모드 사용
Why: 프로파일 모드가 필요한 이유
디버그 모드는 많은 검사와 디버깅 기능이 활성화되어 있어 실제 성능을 측정하기 어렵습니다. 프로파일 모드는 릴리스에 가까운 성능을 보여주면서 디버깅 도구를 사용할 수 있습니다.
What: 빌드 모드 비교
| 모드 | JIT/AOT | 성능 | 디버깅 |
|---|---|---|---|
| Debug | JIT | 느림 | 전체 가능 |
| Profile | AOT | 빠름 | 제한적 가능 |
| Release | AOT | 가장 빠름 | 불가 |
How: 프로파일 모드로 실행
# 웹에서 프로파일 모드 실행flutter run -d chrome --profileVS Code 설정:
{ "configurations": [ { "name": "Flutter Web (Profile)", "request": "launch", "type": "dart", "deviceId": "chrome", "flutterMode": "profile" } ]}How: 프로파일 빌드 후 테스트
# 프로파일 모드로 빌드flutter build web --profile
# 로컬 서버로 테스트cd build/webpython -m http.server 8000# 브라우저에서 http://localhost:8000 접속Watch out: 주의사항
웹에서 프로파일 모드는 flutter run으로만 사용할 수 있습니다.
정적 파일로 빌드하면 프로파일 기능을 사용할 수 없으니 주의하세요.
5. 웹 특화 최적화
Why: 웹만의 최적화가 필요한 이유
웹 환경은 모바일과 다른 특성이 있습니다. 네트워크 지연, 브라우저 캐싱, 초기 로드 시간 등을 고려해야 합니다.
What: 초기 로드 최적화
How: 지연 로딩 구현
// 지연 임포트 선언import 'package:myapp/features/heavy_feature.dart' deferred as heavy;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( routes: { '/': (context) => const HomePage(), '/heavy': (context) => FutureBuilder( future: heavy.loadLibrary(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return heavy.HeavyFeaturePage(); } return const LoadingPage(); }, ), }, ); }}How: 이미지 최적화
// 웹에 최적화된 이미지 로딩Image.network( 'https://example.com/image.webp', // WebP 형식 사용 loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ); },)How: 폰트 최적화
flutter: fonts: - family: Roboto fonts: - asset: fonts/Roboto-Regular.ttf - asset: fonts/Roboto-Bold.ttf weight: 700웹에서는 폰트 서브세팅을 고려하세요:
// 사용하는 글자만 포함된 폰트 사용// 또는 Google Fonts의 텍스트 파라미터 활용What: 렌더링 최적화
// 불필요한 리빌드 방지class OptimizedWidget extends StatelessWidget { const OptimizedWidget({super.key}); // const 생성자
@override Widget build(BuildContext context) { return const Column( // const 위젯 children: [ Text('고정 텍스트'), Icon(Icons.star), ], ); }}
// RepaintBoundary로 리페인트 영역 제한RepaintBoundary( child: ComplexAnimatedWidget(),)Watch out: 주의사항
지연 로딩을 과도하게 사용하면 사용자 경험이 저하될 수 있습니다. 자주 사용하는 기능은 메인 번들에 포함시키고, 드물게 사용하는 대용량 기능만 지연 로딩하세요.
6. 웹 성능 체크리스트
초기 로드 최적화
- 적절한 렌더러 선택 (HTML/CanvasKit)
- 지연 로딩 적용
- 이미지 최적화 (WebP, 적절한 크기)
- 폰트 최적화 (서브세팅)
- 불필요한 패키지 제거
런타임 성능
- const 생성자 활용
- 불필요한 리빌드 방지
- RepaintBoundary 적절히 사용
- 무거운 작업은 분리 (Isolate/Web Worker)
측정 및 분석
- 프로파일 모드로 테스트
- Chrome DevTools Performance 분석
- Lighthouse 점수 확인
- 실제 디바이스에서 테스트
마무리
이번 튜토리얼에서는 Flutter 웹 앱의 성능을 측정하고 최적화하는 방법을 배웠습니다.
핵심 정리
| 주제 | 핵심 내용 |
|---|---|
| 렌더러 선택 | HTML (빠른 로드) vs CanvasKit (일관된 렌더링) |
| 분석 도구 | Chrome DevTools Performance 패널 |
| 디버그 플래그 | debugProfileBuildsEnabled 등 |
| 최적화 전략 | 지연 로딩, const, RepaintBoundary |
다음 단계
- Flutter 튜토리얼 55편: 플랫폼 통합 기초에서 Flutter가 지원하는 플랫폼과 네이티브 코드 통합 방법을 배워보세요.
참고 자료
Footnotes
-
렌더러(Renderer)는 Flutter 위젯을 실제 화면에 그리는 엔진입니다. 웹에서는 HTML 또는 CanvasKit 중 선택할 수 있습니다. ↩
공유
이 글이 도움이 되었다면 다른 사람과 공유해주세요!