1. 서론
Vue 3와 관련한 내용들을 한 줄씩으로 요약하자면 아래와 같습니다.
- Vue Router 4
- createRouter, createWebHistory, useRoute, useRouter 기반 라우팅 구조 이해
- Pinia
- defineStore로 도메인별 store 정의, state / getters / actions로 전역 상태 관리
- <script setup>
- Composition API를 가장 간단하게 쓰는 SFC 문법
오늘의 목표는 지금까지 배운 Vue 3 생태계를 한 번에 정리하고
Ve 2 → Vue 3 마이그레이션을 앞두고 어디를 어떻게 볼지 기준을 세우는 것입니다.
2. Vue 3 프로젝트 기본 뼈대
Vue 3 공식 문서와 Quick Start에서는
Vite 기반 프로젝트를 만들고 이런 형태를 기본 구조로 제시합니다.
src/
main.js
App.vue
router/
index.js
stores/
...
components/
views/
주요 파일 별 역할을 다시 정리해보겠습니다.
- main.js
- createApp(App)으로 앱 생성
- app.use(router), app.use(pinia)로 플러그인 등록
- app.mount('#app')로 DOM에 마운트
- router/index.js (Vue Router 4)
- createRouter, createWebHistory
- routes 배열에 URL ↔ 컴포넌트 매핑
- <RouterView>, <RouterLink>로 실제 화면 전환
- stores/ (Pinia)
- defineStore('id', { state, getters, actions })
- useXXXStore()로 컴포넌트에서 사용
- Vue 컴포넌트 (.vue)
- <template> + <script setup> + <style>
- Composition API(ref, reactive, computed, watch, onMounted 등)를 사용
이 구조 자체가 Vue 3 + Router 4 + Pinia + <script setup> 조합의 표준적인 모양새라고 보면 됩니다.
3. [Vue 2 + Vuex + Router 3] vs [Vue 3 + Pinia + Router 4]
이제 마이그레이션 준비를 위해 Vue 2 조합과 Vue 3 조합을 묶어서 보는 것이 중요합니다.
1️⃣ 앱 초기화 코드 (main.js)
- Vue 2 + Router 3 + Vuex
import Vue from 'vue'
import App from './App.vue'
import router from '/router'
import store from './store'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
- Vue 3 + Router 4 + Pinia
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.use(createPinia())
app.mount('#app')
- 변경점
- 전역 Vue 생성자 → createApp()
- new Router() → createRouter()
- new Vuex.Store() → defineStore() + createPinia()
2️⃣ 라우터 설정 (router/index.js)
- Router 3 (Vue 2)
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/Home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{ path: '/', name: 'home', component: Home }
]
})
- Router 4 (Vue 3)
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/HomeView.vue'
const routes = [
{path: '/', name: 'home', component: HomeView}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
- 변경점
- Vue.use(Router) → 제거
- mode: 'history' → history: createWebHistory()
- Composition API에서는 $route 대신 useRoute(), $router 대신 useRouter() 사용 가능
3️⃣ 상태 관리 (stores/*.js)
- Vuex
const store = new Vuex.Store({
state: { count: 0 },
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment({ commit }) {
commit('increment')
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
- Pinia
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount(state) {
return state.count * 2
}
},
actions: {
increment() {
this.count++
}
}
})
- 변경점
- Vuex는 mutations 필수, Pinia는 mutations 없이 actions에서 바로 수정
- Vuex는 this.$store.state.xxx, Pinia는 const store = useXXXStore() 후 store.xxx
4. <script setup> (views/*.vue)
Vue 3를 본격적으로 쓸 거라면 새로 짜는 코드는 전부
<script setup> + Composition API로 수정하는 것이 훨씬 깔끔합니다.
- Options API 버전
<script>
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
- <script setup> + Composition API 버전
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
5. 마이그레이션 체크리스트
이번 글은 기존에 Vue 2 기반으로 생성된 프로젝트를
Vue 3 구조에 어떻게 끼워 맞출지 관점에서 체크리스트를 만드는 게 목표입니다.
라우터 관련
- router/index.js에서 new Router / mode / routes 구조 파악
- 네비게이션 가드(beforeEach, beforeResolve, afterEach) 사용하는 위치 체크
- $route, $router를 사용하는 컴포넌트 목록 대략 파악
- 동적 라우트(/something/:id) 중첩 라우트, lazy loading 사용 여부 체크
→ Vue 3에서 Router 4로 옮길 때 createRouter/createWebHistory + useRoute/useRouter로 어떻게 바꿀지 계획 세우기
상태 관리 관련
- Vuex 사용 여부 확인 (store 폴더 / new Vuex.Store / modules 구조)
- 어떤 모듈이 있는지: user, auth, cart, post 등 도메인 정리
- mapState, mapGetters, mapActions, mapMutations 사용 위치 체크
- 전역 상태 vs 특정 페이지에서만 쓰는 상태 구분
→ Pinia로 옮긴다면 defineStore('user'), defineStore('post') 같은 도메인 단위로 쪼갤 수 있을지 고민해 보기
컴포넌트/로직 구조
- mixin 사용 여부 (mixins: [...])
- filter 사용 여부({{ value | something }}) - Vue 3에서 제거 예정이라 computed나 methods로 옮겨야 함
- Options API의 data/methods/computed/watch가 복잡하게 섞여 있는 컴포넌트 후보 찾기
- 공통 로직을 composable(useXXX)로 빼낼 수 있을지 아이디어 메모
→ 이 컴포넌트는 그대로 Options API로 둘지, Composition API로 바꿀지 우선순위 정하기
6. 앞으로의 마이그레이션 전략
이번 글까지는 Vue 3 생태계에 대한 감 잡기였고,
이제 앞으로는 실제 Vue 2 → Vue 3 마이그레이션에 더 초점을 맞춘 글을 작성할 것입니다.
- 새 코드는 Vue 3 스타일로
- 새로 만드는 페이지/컴포넌트는 <script setup> + Router 4 + Pinia 기준으로 작성
- 레거시는 유지하되, 새 코드만이라도 Vue 3 방향으로 맞춰두기
- 레거시는 위험도/효과 순으로 점진적 전환
- 공통 UI, 헬퍼성 로직, mixin부터 composable로 옮기기
- Vuex 모듈을 하나씩 Pinia Store로 옮겨보고, Vuex와 Pinia가 잠시 공존하는 기간을 허용하기
- 문서화 해두기
- 이전 구조 vs 새 구조를 도식이나 표로 정리해서 팀/미래의 나에게 남겨두기
출처
Vue 공식 문서 - Vue 3 Migration Guide
Vue Router 공식 문서 - Vue 2에서 마이그레이션
'Framework > Vue' 카테고리의 다른 글
| Vue 2의 Vue.use에서 Vue 3 Global API, createApp로 마이그레이션 (0) | 2025.11.27 |
|---|---|
| Vue 2에서 Vue 3로: 공식 마이그레이션 가이드 구조 한 눈에 정리 (0) | 2025.11.27 |
| Vue 3 + Router 4 + Pinia로 미니 SPA 만들기 (0) | 2025.11.26 |
| Vue3 <script setup> 정리: defineProps, defineEmits, defineExpose (0) | 2025.11.26 |
| Pinia 입문: Vuex 대신 선택하는 Vue 3 공식 상태 관리 라이브러리 (0) | 2025.11.26 |