[Vue.js] Vue2 탈출기: Vue3 마이그레이션 가이드
이전 글에 이어서 Vue2.7 upgrade + Vite 적용
+Vue3로 성공적으로 업그레이드 했습니다..!
Vue2 에서 Vue3로 업그레이드하는 거는 금방이지만, 그에 맞춰 종속된 라이브러리들을 Vue3에 맞게 리팩토링하는게 더 오래 걸린 것 같아요.
하면서 중간중간 기획개발도 같이 진행하고, QA도 진행하면서 수정개발하니 커밋 기록상 진행 일자는 아래와 같습니다.
- 프로젝트 규모 : 중규모 웹 애플리케이션
- 마이그레이션 기간 : 2024.09.03 ~ 2024.10.04 (약 1개월)
- 🗓️ 처음 시작일 : 2024년 9월 3일
- 🗓️ 마지막 QA 수정 개발 완료 : 2024년 10월 4일
- 실제 개발 기간 : 약 2주
마이그레이션의 주요 이점
- Composition API를 통한 더 나은 코드 구성과 재사용성
- 향상된 TypeScript 지원
- 더 작은 번들 크기와 더 나은 트리 쉐이킹
- 개선된 성능과 반응성 시스템
- 더 나은 개발자 경험을 제공하는 새로운 기능들
이 글에서는 실제 프로덕션 환경에서 진행한 마이그레이션 경험과 베스트 프랙티스를 공유하고자 합니다.
🐕 🐈 🐕 🐈 🐕 🐈 🐕 🐈
작업 내용
1. Vue 3 + @vue/compat 설치
- Vue 버전 업데이트 (^3.1.0)
- 제일 먼저 Vue(2.7.x, 2버전) 을 3버전으로 업그레이드 해줍니다.
- Vue 마이그레이션 빌드 @vue/compat → 추후 삭제 해야합니다!
- @vue/compat(일명 "마이그레이션 빌드")은 Vue 2의 동작이 호환되는 구성을 제공하는 Vue 3의 빌드입니다.
마이그레이션 빌드는 기본적으로 Vue 2에서 실행되며, 몇 가지 예외 케이스말고는 왠만한 공통 APIs는 Vue 2와 동일하게 사용합니다. Vue 3에서 변경되었거나 더 이상 지원되지 않는 기능을 사용하면 런타임 경고가 발생합니다.
즉, 이 패키지는 Vue 2와 Vue 3를 모두 지원할 수 있으며, 프로덕션용이 아니기 때문에 앱을 변환하는 동안에만 사용해야 합니다.
yarn add @vue/compat
2. 빌드 설정 업데이트
- vite confg 파일을 아래와 같이 수정해줍니다.
🔗 vite.config.js
export default {
resolve: {
alias: {
vue: '@vue/compat'
}
},
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
]
}
- vue-template-compiler → @vue/compiler-sfc@^3.1.0 로 교체
yarn add @vue/compiler-sfc
🔗 package.json
"dependencies": {
"vue": "^2.7.14", 👈 delete!
"vue": "^3.1.0", 👈 add!
"@vue/compat": "^3.1.0" 👈 add!
...
},
"devDependencies": {
"vue-template-compiler": "^2.6.14" 👈 delete!
"@vue/compiler-sfc": "^3.1.0" 👈 add!
}
3. Vuex / Router 업그레이드
- Vuex v4 upgrade
Vuex는 이제 더 이상 사용되지 않는 라이브러리로 간주되어 Pinia로 대체되었습니다.
추후에 공식 상태 관리 라이브러리인 pinia 로 리팩토링 할 예정이며, 빠르게 대체하기 위해 Vuex4로 업데이트 하였습니다.
- main.js 코드 수정
기존에 Vue 생성자 함수를 사용하는 대신에, createApp() 함수를 사용합니다.
🔗 main.js
import { createApp } from "vue";
const app = createApp(App);
...
// Vue 인스턴스 생성
app.mount("#app");
- Vuex 변경 내용
Vue 2에서 Vuex를 사용하려면 아래 코드를 실행합니다.
export default new Vuex.Store({
…
});
Vue 3에서 Vuex createStore를 사용하려면 아래 코드를 실행합니다.
import { createStore } from 'vuex'
export const store = createStore({
state () {
return {
count: 1
}
}
})
파일에서 사용시 Vuex 4는 useStore 함수를 사용하여 Vue 응용 프로그램의 설치 후크에서 저장소를 가져옵니다.
<scritp setup>
import { useStore } from 'vuex'
const store = useStore()
- 호환성 모드 활성화 [24.12.12 추가사항]
브라우저 네트워크 창을 켜보면, 콘솔창에 아래와 같은 에러가 나타납니다.
🔗 main.js
import { createApp } from "vue";
import { configureCompat } from "vue"; 👈 add!
// 호환성 모드 활성화
configureCompat({ INSTANCE_CHILDREN: true }); 👈 add!
const app = createApp(App);
app.mount("#app");
Vue 2 스타일 코드가 여전히 사용되고 있다면, Vue 3의 호환성 모드를 활성화해야 합니다. main.js에서 다음과 같이 설정할 수 있습니다.
해당 코드를 넣어줘야 Vue 2 방식 코드가 오류를 발생시키지 않고 동작해주기 때문에 점진적으로 Vue 3로 코드 전환을 진행하는 데 유용합니다.
- Vue-router 변경내용
참고 : https://router.vuejs-korea.org/ko/guide/migration/
Vue 2에서 마이그레이션 | Vue Router
Vue 2에서 마이그레이션 Vue 라우터 API의 대부분은 v3(Vue 2의 경우)에서 v4(Vue 3의 경우)로 재작성하는 동안 변경되지 않았지만, 여전히 애플리케이션을 마이그레이션하는 동안 발생할 수 있는 몇 가
router.vuejs-korea.org
import { createRouter, createWebHistory } from 'vue-router'
createRouter({
history: createWebHistory(),
hash: createWebHashHistory(),
abstract: createMemoryHistory()
routes: [],
})
app.use(router) 옵션을 사용합니다.
4. 글로벌 API 변경사항 적용
- 글로벌 함수 전역 등록 (Global API -> Instance API)+ vue3 용 코드로 리팩토링
: 글로벌 필터
전역적으로 등록된 필터를 앱 전체에서 사용하는 경우, globalProperties 를 통해 모든 구성 요소에서 글로벌 필터를 사용할 수 있도록 할 수 있습니다 .
🔗 common.js
import common from "@/common";
app.use(common);
🅾️ 종속된 라이브러리 변경사항
Vue2 | Vue3 | 주요 변경사항 |
vue 2.7.14 | vue 3.1.0 | Composition API, 반응성 시스템 개선 |
vue-router 3.x | vue-router 4.4.2 | 새로운 라우팅 API, TypeScript 지원 강화 |
vuex 3.6.2 | vuex 4 [추후 pinia 변경 필요] | 모듈 시스템 개선, Composition API 통합 |
vite-plugin-vue2 삭제 | @vitejs/plugin-vue": "^5.0.5 | |
@vue/compiler-sfc": "^3.1.0", | ||
vue/compat | ||
|
||
|
||
Vueformulate | FormKit | Vue3 호환용 대체 라이브러리 |
vue-step-progress: '0' | vue-step-progress: '1.0.2' | |
vue-awesome-swiper | swiper |
여기까지가 기본적인 Vue3 환경세팅입니다.
🅾️ 마이그레이션 과정에서 마주친 문제들과 해결방안
- 주요 도전 과제
1. 비동기 컴포넌트 처리
- 문제: Vue 3의 새로운 Suspense API 적용 필요
- 해결: defineAsyncComponent 활용 및 로딩 전략 재설계
2. TypeScript 통합
- 문제: 타입 정의 누락 및 호환성 이슈
- 해결: @vue/runtime-core 타입 활용 및 점진적 타입 적용
3. 레거시 코드 처리
- 문제: Options API로 작성된 대규모 컴포넌트
- 해결: 점진적 마이그레이션 전략 수립 및 우선순위화
- 학습된 교훈
1. 철저한 사전 계획의 중요성
2. 점진적 마이그레이션의 이점
3. 테스트 코드의 가치
4. 문서화의 중요성
🅾️ 향후 개선 계획
- 단기 목표 (1-3개월)
- TypeScript 적용 범위 확대
- tailwind css+ + ui library
- storybook
- 폴더 구조 재정립
- 중장기 목표 (3-6개월)
- Composition API 전면 도입
- Vuex에서 Pinia로 마이그레이션
- 마이크로 프론트엔드 아키텍처 검토
- 테스트 커버리지 80% 달성
- 성능 최적화 및 메트릭 개선
- 코드 품질 개선
- ESLint + Prettier 규칙 강화
- 코드 리뷰 프로세스 개선
에러 수정
1. Sentry
Sentry 도 Vue3에 맞게 코드를 수정해줍니다.
먼저, 사용 중인 @sentry/vue 버전을 최신으로 맞춰줍니다.
yarn add @sentry/vue@latest
- [24.12.12] "@sentry/vue": "^8.43.0",
다음으로, deprecated functions 들을 고쳐줍니다.
//before
Sentry.configureScope((scope) => { ...
//after
Sentry.getCurrentScope((scope) => ...
//before
integrations: [
new Sentry.BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
}),
],
//after
Sentry.init({
...
integrations: [
Sentry.browserTracingIntegration({ router }),
Sentry.replayIntegration()
],
Vue2에서 Vue3로의 마이그레이션은 기대했던 만큼 쉽지 않았습니다. 예상은 했지만, 패키지 업데이트 후 fix Error, fix Warnings, fix… fix… 에러 고치는데 시간이 많이 들었던 것 같네요.
먼저, Vue3의 새로운 Composition API와 기존의 Options API 간의 차이를 이해하고 적응하는 데 시간이 걸렸습니다. 특히, 기존 코드베이스를 리팩토링하면서 두 API를 혼용하는 과정에서 혼란이 발생하기도 했습니다.
또한, 일부 라이브러리와 플러그인이 Vue3와 호환되지 않아 대체 라이브러리를 찾거나 직접 호환성을 맞추는 작업이 필요했습니다. 이 과정에서 예상보다 많은 시간이 소요되었고, 프로젝트 일정에도 영향을 미쳤습니다.
특히, 폼 라이브러리인 Fomkit , Sentry와 같은 핵심 플러그인들의 새로운 버전으로의 전환이 까다로웠습니다. 기존의 설정과 코드 구조를 변경해야 했고, 이로 인해 많은 테스트와 디버깅이 필요했습니다.
결국, Vue3로의 마이그레이션은 단순한 업그레이드가 아니라, 전체 프로젝트를 다시 한 번 점검하고 개선하는 기회가 되었습니다. 비록 힘들고 시간이 많이 들었지만, 예상 목표 일정보다 훨씬 빠르게 버전을 성공적으로 올려서 뿌듯하네요!