최근 동아리에서 flutter를 공부하고 있습니다.
저는 최근까지 웹 프로젝트만을 진행했던 만큼, Flutter의 프로젝트 구조가 낯설게 느껴졌습니다.
따라서 오늘은 프론트엔트 프레임워크와 Flutter의 프로젝트 구조를 간단히 비교해 보고자 합니다.
해당 글은 개인 공부를 위해 작성된 글로, 틀린 내용이 포함될 수 있습니다.

위 사진은 제가 최근 진행한 프로젝트(Vue)의 프로젝트 구조입니다.
웹 프론트엔드의 주요 코드는 src폴더 안에 들어있습니다.
웹 프로젝트의 entry point는 main.js죠!
main.js에는
// Vue
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
또는
// React
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
요런 코드가 있을테고, 이는 App을 루트 컴포넌트로 하여 앱을 실행하겠다는 의미입니다.
한편 Flutter의 프로젝트 기본 구조는 이렇습니다.

Flutter의 주요 코드는 lib폴더 안에 위치하게 됩니다.
Flutter에서는 main.dart가 존재합니다.
import 'app.dart';
void main() {
runApp(const App());
}
여기서 runApp은 App을 루트 위젯으로 하여 위젯 트리를 구성하라는 신호를 보냅니다.
그러면 웹에서의 컴포넌트가 플러터의 루트 개념과 동일할까요?
그렇진 않습니다.
웹 프론트엔드에서 컴포넌트는 화면의 한 조각을 구성하는 단위입니다.
React나 Vue에서는 버튼, 카드, 네비게이션 바 등을 각각의 컴포넌트로 분리해 재사용합니다.
예를 들면 BottomNavbar.vue 파일로 네비게이션 컴포넌트를 만들어놓고,
// Vue
<template>
// 기타 코드들...
<BottomNavbar />
</template>
<script setup>
import BottomNavbar from '@/components/common/BottomNavbar.vue'
</script>
이런 식으로 네비게이션 바 컴포넌트를 가져와서 페이지 내부에서 사용하죠.
반면 Flutter의 위젯(Widget) 은 조금 더 포괄적인 개념이라고 생각하면 됩니다.
버튼이나 텍스트 같은 UI 요소뿐만 아니라 스타일, 앱 전체 구조 자체도 위젯이기 때문입니다. (모든 게 위젯인 세계관)
// Flutter
class MyButton extends StatelessWidget {
final String text;
const MyButton({required this.text});
@override
Widget build(BuildContext context) {
return Padding( // padding도 위젯!
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(onPressed: () {}, child: Text(text)),
);
}
}
따라서 Flutter에서는 UI를 그리는 것과 레이아웃을 배치하는 것이 동일한 개념으로 취급됩니다.
정리하자면, component가 화면 조각의 단위라면 widget은 앱 전체를 표현할 수 있는 단위입니다.

Flutter 프로젝트 또한 사진처럼 기능별로 (작은 앱의 경우 화면별로 나누어 관리하기도 한답니다.) 나누어 파일을 관리할 수 있겠네요.
pages, components 라는 폴더 대신 presentation, widgets라는 이름으로 폴더를 만들어 보었습니다.
사실 Flutter 프로젝트를 생성했을 때 제일 먼저 눈에 띄었던 폴더는 android, ios, linux, macos, windows, web입니다.

위 파일들은 플러터 앱이 여러 플랫폼에서 잘 돌아갈 수 있도록 각 플랫폼별 빌드 설정과 실행 코드를 관리하는 역할을 합니다.
lib파일 내부의 dart코드가 설계도 역할을 하고, 해당 플랫폼별 폴더들이 OS별 공장을 세팅한다는 느낌으로 이해하면 쉽습니다.
웹 프론트는 당연히 웹 환경에 한정되어 있기 때문에 해당 폴더들이 존재하지 않습니다.
Flutter 프로젝트 생성시 test 폴더가 기본으로 생기는 것을 볼 수 있습니다.
웹 FE 프로젝트에서는 test폴더가 자동으로 생성되지 않습니다. 프로젝트에서의 테스트 도입 여부에 따라 직접 폴더를 추가해서 사용하며, 테스트를 도입하는 경우 컴포넌트 렌더링 테스트를 위주로 합니다.
Flutter는 모바일/웹/데스크탑을 동시에 지원하기 때문에 테스트의 역할이 강조되기도 합니다.
Flutter는 하나의 코드로 Android, iOS, Web, Desktop을 모두 빌드하기 때문에, 테스트 없이 배포하면 앱이 깨질 수 있고,
위젯 트리가 커지면 화면 일부를 수정할 때 의도치 않은 부작용이 발생할 수 있습니다.
(Flutter의 테스트에 대해서는 다른 포스트에서 자세히 알아보겠습니다.)
이렇게 Flutter 프로젝트의 구조에 대해서 web FE와 비교하며 알아보았습니다.
사실 이 포스트를 작성하면서 구조보다 렌더링 파이프라인이나 레이아웃 모델에 대해서 비교해보며 썼다면 더 유익하고 재밌는 글이 나오지 않을까 하는 아쉬움이 있었습니다.
따라서 다음은 해당 주제 혹은 관련 주제로 찾아오도록 하겠습니다...😇
부족한 글 읽어주셔서 감사합니다. <<>>
웹 FE와 앱은 왜 이렇게 다르게 발전한걸까요....
하나 공부하면 나머지 하나는 공부 안해도 알정도로 비슷하게 만들면 안됐던 걸까요...
왜 손수 진입장벽을 높이는걸까요...