MOM.SOFT

MOMSOFT  /  기술 블로그

Frontend

Vue 2에서 3으로 옮기며 실제로 오래 걸린 부분

문법 치환은 목록만 만들면 끝나는 일입니다. 정작 일정을 잡아먹는 건 서드파티 UI 라이브러리, 전역 API에 얽힌 암묵적 결합, 반응성 모델 교체, 그리고 빌드 도구입니다.

프로젝트 문의하기 →

결론부터: 문법은 문제가 아니었습니다

Vue 2에서 3으로 옮기는 일을 앞두고 대부분의 팀이 먼저 세는 것은 컴포넌트 개수입니다. "SFC가 몇백 개니 하나에 30분씩만 잡아도..." 같은 식으로 계산합니다. 그런데 실제로 해보면 그 계산은 거의 맞지 않습니다. 컴포넌트 하나하나를 고치는 일은 기계적이고, 상당 부분은 ESLint 룰과 일괄 치환이 대신 찾아줍니다. 일정을 무너뜨리는 것은 다른 곳에 있습니다.

시간이 실제로 몰리는 지점은 넷입니다. 첫째, 서드파티 UI 라이브러리. 둘째, 전역 API에 기대어 만들어 둔 암묵적 결합. 셋째, 반응성 구현이 Object.defineProperty에서 Proxy로 바뀌면서 생기는 조용한 동작 차이. 넷째, 빌드 도구 교체가 함께 끌고 오는 것들(테스트 러너, 환경변수, 정적 자산 처리, 별칭 설정). 이 중 하나라도 정리되지 않은 채로 시작하면, 컴포넌트를 아무리 빨리 고쳐도 앱이 뜨지 않거나, 떠도 믿을 수 없습니다.

그래서 이 글은 "Vue 3의 새 문법 소개"가 아닙니다. 마이그레이션을 일정과 리스크의 문제로 보고, 무엇을 먼저 확인해야 하는지, 한 번에 갈지 병행할지 어떻게 정하는지, 그리고 어떤 경우에는 아예 하지 말아야 하는지를 정리합니다. 파괴적 변경의 전체 목록은 공식 마이그레이션 가이드에 이미 잘 정리돼 있으니, 여기서는 목록이 아니라 판단을 다룹니다.

왜 이런 분포가 나오는가

변경의 성격이 세 종류로 갈린다

Vue 3의 파괴적 변경은 대응 비용 기준으로 세 부류로 나누는 편이 유용합니다.

첫 번째 부류는 도구로 잡힙니다. 사람이 몰릴 구간이 아닙니다. 두 번째 부류는 대체 코드를 새로 설계해야 하고 그 설계가 여러 파일에 퍼져 있어 비용이 큽니다. 세 번째 부류는 비용을 예측할 수 없다는 게 문제입니다. 빌드도 통과하고 화면도 뜨는데, 특정 조건에서만 값이 하나 어긋납니다.

이벤트 버스가 대표적인 사례

Vue 2 시절 흔했던 패턴이 있습니다.

// Vue 2 — 어디서나 쓰이던 전역 이벤트 버스
export const bus = new Vue()

// A 컴포넌트
bus.$emit('cart:updated', payload)

// B 컴포넌트 (전혀 다른 라우트)
bus.$on('cart:updated', this.refresh)

Vue 3에는 $on이 없습니다. 그래서 mitt 같은 외부 이미터로 갈아끼우면 될 것 같지만, 실제로 시간을 먹는 건 치환이 아니라 이 버스를 통해 흐르던 상태 흐름을 다시 이해하는 일입니다. 어떤 화면이 어떤 이벤트에 의존하는지 문서가 없고, 구독 해제가 빠진 곳에서 나던 버그가 마이그레이션 후 다른 형태로 재현됩니다. 이 부분은 정직하게 시간을 잡아야 합니다. 이벤트 이름을 문자열로 흩뿌려 둔 코드베이스라면 grep으로 송신처와 수신처를 짝지어 표로 만드는 작업부터 하십시오. 그 표의 행 수가 이 구간의 실제 난이도입니다.

단일 루트가 아니어도 되는 것의 부작용

Vue 3는 프래그먼트를 허용합니다. 좋은 변화지만, Vue 2 시절 코드는 "루트가 하나"라는 전제 위에 서 있습니다. 부모가 자식에게 넘긴 class·style·이벤트 리스너가 자동으로 붙던(속성 폴스루) 동작이, 루트가 여럿이 되는 순간 사라집니다. 이때 Vue는 어디에 붙일지 모르는 속성이 있다고 경고하고, 개발자가 v-bind="$attrs"로 붙을 자리를 직접 지정해야 합니다.

게다가 Vue 3는 $listeners$attrs로 합쳤기 때문에, v-on="$listeners"로 이벤트를 내려보내던 래퍼 컴포넌트는 전부 손봐야 합니다. 여기서 자주 나오는 증상이 핸들러 이중 호출입니다.

// emits 를 선언하지 않으면 부모의 @click 은
// 컴포넌트 이벤트이면서 동시에 루트 엘리먼트의 네이티브 리스너로도 붙습니다.
export default {
  emits: ['click'],        // 선언하면 $attrs 에서 빠집니다
  methods: {
    onClick(e) { this.$emit('click', e) }
  }
}

이런 종류의 문제는 컴파일 에러로 잡히지 않습니다. 런타임에, 그것도 특정 조합에서만 드러납니다. 그래서 "고친 시간"보다 "고쳤다고 믿었다가 다시 찾은 시간"이 훨씬 깁니다. 공용 래퍼 컴포넌트(버튼·인풋·모달)는 전부 emits를 명시적으로 선언하고 넘어가는 편이 결국 빠릅니다.

반응성 구현 교체가 만드는 조용한 버그

Vue 3가 Vue.set을 없앨 수 있었던 이유는 반응성 구현이 Proxy로 바뀌었기 때문입니다. 객체에 나중에 추가한 속성도, 배열 인덱스 대입도 그냥 감지됩니다. 명백한 개선이고, 그래서 대부분의 팀이 이 항목을 "제거만 하면 되는 것"으로 분류합니다. 그런데 Proxy는 원본 객체와 다른 객체입니다. 여기서 나오는 문제가 따로 있습니다.

const raw = { id: 1 }
const state = reactive({ list: [raw] })

state.list[0] === raw               // false — 프록시가 반환됩니다
state.list.find(o => o === raw)     // undefined

일부 배열 메서드는 Vue가 원본까지 함께 조회하도록 보정해 주지만, 직접 ===로 비교하는 코드는 보정 대상이 아닙니다. "선택된 항목"을 객체 참조로 들고 다니던 코드, 외부에서 받아온 객체를 상태에 넣고 나중에 원본과 대조하던 코드가 조용히 어긋납니다. 참조 비교가 필요하면 toRaw()로 벗겨서 비교하거나, 애초에 참조 대신 id로 비교하도록 바꾸는 편이 안전합니다.

더 흔한 사고는 Vue와 무관한 라이브러리 인스턴스를 data에 넣어 둔 경우입니다. 차트, 지도, 리치 텍스트 에디터, WebSocket 클라이언트 같은 것들이 여기 해당합니다. Vue 2에서는 defineProperty가 훑고 지나가도 대개 무사했지만, Vue 3에서는 이 인스턴스 전체가 프록시로 감싸입니다. 내부에서 this 동일성이나 instanceof에 의존하는 라이브러리는 여기서 깨지고, 거대한 객체 그래프를 통째로 반응형으로 만들면서 성능도 함께 나빠집니다.

import { markRaw } from 'vue'

export default {
  data() {
    return {
      // 차트·지도·에디터 인스턴스는 프록시로 감싸지 않습니다
      chart: markRaw(createChart(this.$refs.el))
    }
  }
}

체크리스트에 이 항목을 넣으십시오. data·reactive에 담기는 값 중 "Vue가 만든 것이 아닌 인스턴스"를 전부 찾아 markRaw 또는 shallowRef로 감싼다. 증상이 이상하고 재현이 어려운 버그의 상당수가 여기서 나옵니다.

Options API를 유지할 것인가

가장 먼저 정해야 하는 것이자, 가장 많이 잘못 정하는 항목입니다. 결론부터 말하면 마이그레이션 범위에 Composition API 전환을 넣지 마십시오.

Vue 3는 Options API를 제거하지 않았습니다. 지원 중단 계획이 발표된 것도 아닙니다. 즉 "Vue 3로 옮긴다"와 "Composition API로 다시 쓴다"는 완전히 분리 가능한 두 개의 작업입니다. 그런데 두 가지를 한 번에 하면 이런 일이 벌어집니다.

마이그레이션은 동작이 같아야 하는 작업이고, 리팩터링은 구조를 바꾸는 작업입니다. 두 성격을 섞으면 검증 비용이 더해지는 게 아니라 곱해집니다. 검증 기준 자체가 사라지기 때문입니다.

그럼 언제 Composition API로 옮기나

마이그레이션이 끝나고 안정화된 뒤, 다음 조건에 해당하는 모듈부터 선택적으로 옮기는 편이 낫습니다.

반대로, 단순한 표시용 컴포넌트를 Composition API로 바꾸는 것은 이득이 거의 없습니다. 잘 돌아가는 Options API 컴포넌트는 그대로 두십시오. 판단 기준은 취향이 아니라 "지난 6개월간 이 파일을 몇 번 고쳤나"입니다. 안 고친 파일은 안 건드리는 게 맞습니다.

Vue 2.7을 경유하는 선택지

Vue 2의 마지막 마이너 버전인 2.7은 Composition API와 <script setup>을 백포트했습니다. 즉 Vue 2에 머문 채로 새 코드 스타일을 먼저 도입할 수 있습니다. 팀이 Composition API에 익숙하지 않다면, 마이그레이션 전에 2.7에서 신규 기능만 새 스타일로 작성해 보며 학습 곡선을 미리 소진하는 것이 유효한 전략입니다. Vue 2는 2023년 말 공식 지원이 종료됐으므로 2.7이 종착지가 될 수는 없지만, 중간 정거장으로는 쓸모가 있습니다. 2.7로 올리는 과정에서 나오는 경고를 정리하는 것만으로도 3으로 갈 때 할 일이 줄어듭니다.

전역 API 변경 — 표면은 작고 뿌리는 깊다

전역 API 변경 자체는 몇 줄입니다.

// Vue 2
import Vue from 'vue'
Vue.use(SomePlugin)
Vue.prototype.$http = axiosInstance
Vue.mixin({ /* ... */ })
new Vue({ router, store, render: h => h(App) }).$mount('#app')

// Vue 3
import { createApp } from 'vue'
const app = createApp(App)
app.use(SomePlugin)
app.config.globalProperties.$http = axiosInstance
app.mixin({ /* ... */ })
app.use(router).use(store).mount('#app')

핵심은 전역이 앱 인스턴스 단위로 좁아졌다는 것입니다. 이건 설계상 옳은 변경이지만, Vue 2 코드가 그 전역성에 얼마나 기대고 있었는지를 드러냅니다.

Vue 2 패턴Vue 3에서 생기는 문제대응
Vue.prototype.$util컴포넌트 인스턴스 밖(순수 JS 모듈, 스토어 액션 등)에서 접근 불가globalProperties 대신 그냥 모듈 import로 되돌리기
전역 이벤트 버스인스턴스 이벤트 API 삭제외부 이미터 또는 스토어 상태로 재설계
Vue.observable없음reactive/ref
Vue.set/Vue.delete없음Proxy 기반이라 불필요. 그냥 대입/삭제
전역 필터필터 문법 자체가 삭제메서드·computed 또는 전역 함수 import
전역 믹스인으로 공통 훅 주입동작은 하지만 추적성이 더 나빠짐컴포저블 또는 플러그인으로 명시화

여기서 실무적으로 중요한 조언 하나. globalPropertiesVue.prototype의 1:1 대체재로 쓰지 마십시오. 그렇게 쓰면 Vue 2의 나쁜 결합을 그대로 옮겨오는 것이고, 나중에 타입을 붙일 때 선언 병합(module augmentation)까지 따라옵니다. 마이그레이션의 좋은 부수 효과는 이런 전역들을 걷어낼 명분이 생긴다는 점입니다. 다만 같은 작업 안에서 걷어내려 하지 말고, 목록만 만들어 두고 순차로 처리하십시오.

렌더 함수를 직접 쓰거나 JSX를 쓰는 코드가 있다면 별도로 세십시오. Vue 3에서는 h가 렌더 함수의 인자로 들어오지 않고 vue에서 import 해야 하며, VNode에 넘기던 속성 구조가 props·attrs·domProps로 나뉘어 있던 형태에서 평평한 하나의 객체로 바뀌었습니다. 템플릿과 달리 이쪽은 자동 치환이 거의 불가능해 손으로 다시 써야 합니다. 비동기 컴포넌트도 defineAsyncComponent로 감싸는 형태로 바뀌었으니, () => import(...)components에 그대로 넣어 둔 자리를 함께 찾아 두십시오.

라우터와 스토어

Vue Router 4와 Vuex 4는 생성 방식이 팩토리 함수로 바뀌었습니다(createRouter, createStore). 히스토리 모드 지정이 옵션에서 함수로 바뀌고(createWebHistory()), 와일드카드 라우트 '*''/:pathMatch(.*)*' 같은 파라미터 문법으로 대체됐습니다. 네비게이션 가드에서 next를 생략하고 값을 반환하는 방식도 가능해졌습니다. 라우터 이동은 프로미스를 반환하고 중복 이동·가드에 의한 중단은 실패로 처리되므로, 처리되지 않은 프로미스 거부 로그가 늘 수 있습니다. 이건 버그가 아니라 규약이므로 isNavigationFailure로 구분해 걸러 주십시오.

스토어를 Pinia로 갈아탈지 묻는 경우가 많은데, 이것도 마이그레이션과 분리하는 편이 낫습니다. Vuex 4로 먼저 뜨게 만들고, 안정화 뒤 모듈 단위로 Pinia로 옮기십시오. 두 라이브러리는 공존이 가능하므로 한꺼번에 갈아탈 이유가 없습니다.

가장 오래 걸린 것 — 서드파티 UI 라이브러리

솔직히 말해, 마이그레이션 일정의 성패는 여기서 거의 결정됩니다. 앱 코드는 우리가 고칠 수 있지만 라이브러리는 그럴 수 없기 때문입니다.

Vue 3 대응 상황은 라이브러리마다 성격이 다릅니다.

그래서 착수 전 첫 작업은 코드가 아니라 의존성 인벤토리여야 합니다. package.json의 모든 항목에 대해 Vue 3 지원 여부, 대응 버전 이름, 파괴적 변경의 규모, 그리고 그 라이브러리를 쓰는 화면 수를 한 줄씩 적으십시오. 여기에 하루를 쓰는 것이, 한참 뒤에 "이 라이브러리는 답이 없다"를 발견하는 것보다 압도적으로 쌉니다.

특히 놓치기 쉬운 것들: 리치 텍스트 에디터, 차트, 날짜 피커, 드래그 앤 드롭, 무한 스크롤, 그리고 사내에서 만든 공용 컴포넌트 패키지. 마지막 항목은 "우리 것이니 금방 고치죠"라고 넘어갔다가, 그 패키지를 쓰는 다른 앱들이 아직 Vue 2라서 한동안 두 버전을 동시에 빌드·배포해야 한다는 사실이 뒤늦게 드러나는 일이 흔합니다. 사내 패키지는 마이그레이션 대상이 아니라 선행 과제로 따로 떼어 일정을 잡으십시오.

스타일도 의존성입니다. UI 라이브러리를 메이저 업그레이드하면 클래스 이름과 DOM 구조가 함께 바뀌는데, 그 구조에 ::v-deep으로 손을 뻗어 둔 커스텀 CSS가 있다면 화면이 미묘하게 어긋납니다. 컴파일도 되고 콘솔도 조용하기 때문에, 이건 사람이 눈으로 봐야만 발견됩니다. <transition-group>이 만들어 주던 래퍼 엘리먼트에 그리드나 플렉스를 걸어 둔 코드도 같은 부류이니, tag를 명시해 렌더링 결과를 고정해 두는 편이 안전합니다.

빌드 도구 교체 — 축을 하나씩 분리하라

Vue CLI는 유지보수 모드로 들어갔고, 공식 권장은 Vite입니다. 그래서 대부분의 팀은 Vue 3 전환과 Vite 전환을 한 번에 하려 합니다. 여기서 자주 무너집니다.

Vite 전환은 번들러만 바꾸는 일이 아닙니다. 실제로는 이런 것들이 함께 딸려옵니다.

// Vue 2 + webpack
const modules = require.context('./modules', true, /\.js$/)

// Vite
const modules = import.meta.glob('./modules/**/*.js')

여기서 특히 조심할 것은 개발 서버와 프로덕션 빌드의 동작이 다르다는 점입니다. Vite 개발 서버는 소스를 네이티브 ESM으로 그대로 서빙하고, 프로덕션은 번들링을 거칩니다. 그래서 "로컬에서는 되는데 빌드하면 안 되는" 문제가 마이그레이션 중간에 나오면 원인 후보가 두 배로 늘어납니다. CI에서 프로덕션 빌드와 프리뷰 서버를 매 커밋 돌려서 이 간극을 초반에 드러내십시오.

권장하는 순서는 Vue 2 상태에서 먼저 Vite로 옮기는 것입니다. Vue 2.7은 전용 플러그인으로 Vite에서도 동작하므로, 프레임워크는 그대로 둔 채 빌드 축만 먼저 정리할 수 있습니다. 이렇게 하면 "빌드가 깨진 건지 프레임워크가 깨진 건지"를 구분할 수 있고, 각 단계가 독립적으로 배포 가능한 상태가 됩니다.

물론 팀 사정상 한 번에 가야 한다면 그럴 수도 있습니다. 다만 그 경우 실패 시 되돌릴 지점이 없다는 점만은 명확히 인지하고 시작하십시오.

타입은 언제 넣나

Vue 3는 TypeScript 지원이 훨씬 좋아졌고, 그래서 "이참에 타입도 같이 넣자"는 제안이 반드시 나옵니다. 답은 같이 넣지 마십시오입니다. 이유는 Composition API 전환을 미루라는 것과 동일합니다. 변경 축이 늘어날수록 원인 규명 비용이 곱으로 늘어납니다.

현실적인 순서는 이렇습니다.

  1. 마이그레이션 중: 타입 도입 없음. 기존 JS 그대로. 다만 vue-tsc를 CI에 넣을 자리만 비워 둡니다.
  2. 안정화 직후: 신규 파일만 <script setup lang="ts">로 작성. strict는 끄고 시작합니다.
  3. 그다음: API 응답 타입과 스토어 상태 타입처럼 경계부터 정의합니다. 컴포넌트 내부보다 경계에 타입을 붙일 때 얻는 이득이 훨씬 큽니다.
  4. 마지막: 자주 고치는 컴포넌트부터 점진 전환. 손대지 않는 파일은 끝까지 JS로 둬도 무방합니다.

예외가 하나 있습니다. 앱이 작고(화면 수십 개 수준), 팀 전원이 TypeScript에 이미 익숙하며, 어차피 상당 부분을 새로 쓸 예정이라면 동시에 진행하는 편이 더 쌀 수 있습니다. 판단 기준은 "타입 에러가 났을 때, 이게 마이그레이션 때문인지 아닌지 팀원이 즉시 구분할 수 있는가"입니다. 구분하지 못한다면 나누십시오.

한 번에 갈 것인가, 병행할 것인가

이 질문에는 앱 규모보다 배포 주기와 라이브러리 상황이 더 큰 변수로 작용합니다.

조건한 번에(빅뱅)병행(점진)
기능 개발을 몇 주 멈출 수 있나가능하다불가능하다
주요 UI 라이브러리 Vue 3 대응전부 준비됨일부 미대응 또는 검증 필요
앱 구조단일 SPA, 라우트 결합도 높음라우트/도메인 단위로 분리 가능
자동화 테스트회귀를 잡아줄 수준으로 있음거의 없음(수동 검증 필요)
롤백 요구배포 한 번 되돌리면 됨부분 롤백이 필요함

병행을 택했다면 방법은 세 가지

1) 마이그레이션 빌드(@vue/compat) — Vue 3 런타임 위에서 Vue 2 동작을 상당 부분 흉내 내며, 폐기된 기능을 쓰면 콘솔에 경고를 냅니다. 번들러 별칭으로 vue@vue/compat으로 돌려두고, 경고를 하나씩 없애 가며 기능별로 compat 플래그를 꺼 나갑니다.

// vite.config.js (요지)
resolve: {
  alias: { vue: '@vue/compat' }
}
// 그리고 vue 플러그인의 compilerOptions 에 compatConfig 를 지정합니다.
// 런타임 쪽은 configureCompat 으로 기능별 플래그를 끕니다.

장점은 "한 저장소 안에서 조금씩" 갈 수 있다는 것입니다. 단점은 compat 모드가 만능이 아니라는 점입니다. 특히 서드파티 라이브러리가 내부에서 Vue 2 전용 API를 쓰는 경우는 compat으로도 덮이지 않는 일이 있습니다. 그러니 착수 전에 핵심 라이브러리 몇 개로 스파이크를 먼저 돌려 보십시오. 그리고 compat은 어디까지나 임시 상태입니다. 기한과 "언제 이 별칭을 지우는가"를 정해 두지 않으면 그 상태로 1년이 갑니다.

2) 라우트 단위 분리 배포 — 앱을 둘로 나누고 리버스 프록시에서 경로별로 다른 번들을 서빙합니다. 두 앱은 완전히 독립이라 서로 깨뜨리지 않습니다. 대신 세션·인증 공유, 공통 헤더의 중복 구현, 두 번 로드되는 벤더 번들 같은 비용을 감수해야 합니다. 화면 간 이동이 잦지 않은 관리자 도구류에서 특히 잘 맞습니다.

3) 신규 기능만 Vue 3로 — 기존 앱은 동결하고 새 앱을 Vue 3로 시작해, 화면이 넘어갈 때마다 옛 앱에서 삭제합니다. 가장 느리지만 가장 안전하고, 제품이 계속 성장 중일 때 유일하게 현실적인 방식일 때가 있습니다. 위험은 옛 앱이 영원히 안 죽는 것입니다. 삭제 일정을 백로그에 못 박아 두지 않으면 반드시 그렇게 됩니다.

세 방법 모두 공통 조건이 하나 있습니다. "지금 어느 상태인가"를 누구나 볼 수 있어야 한다는 것입니다. 남은 compat 경고 수, 남은 Vue 2 화면 수처럼 줄어드는 숫자 하나를 대시보드나 README에 박아 두십시오. 그 숫자가 없으면 병행 전환은 반드시 흐지부지됩니다.

실제 작업 순서 체크리스트

  1. 의존성 인벤토리. 모든 런타임 의존성의 Vue 3 대응 여부·대체 패키지·파괴적 변경 규모·사용 화면 수를 표로 만든다. 대응 불가 항목이 하나라도 있으면 여기서 전략을 다시 정한다.
  2. 전역 것들의 목록화. Vue.prototype 확장, 전역 믹스인, 전역 필터, 이벤트 버스, Vue.observable, 직접 작성한 렌더 함수·JSX 사용처를 전부 찾아 적는다. 이것이 실제 난이도의 지표다.
  3. Vue 2.7로 먼저 올린다. 여기서 나는 경고를 정리하고, 필요하면 이 상태에서 Vite 전환까지 마친다. 각 단계는 배포 가능한 상태로 끝낸다.
  4. 테스트/스모크 경로 확보. 커버리지를 올리라는 뜻이 아니라, 핵심 사용자 흐름 열 개 남짓을 E2E나 체크리스트로 고정하라는 뜻이다. 마이그레이션은 "동작이 같아야 하는" 작업이므로 비교 기준이 없으면 검증 자체가 성립하지 않는다.
  5. 기계적 치환. 라이프사이클·디렉티브 훅·트랜지션 클래스·:deep()·필터 제거를 ESLint 룰과 일괄 치환으로 처리한다.
  6. 진입점·라우터·스토어. createApp, Router 4, Vuex 4까지 올려 일단 앱이 뜨게 만든다. 화면이 깨져도 상관없다. 이 시점이 첫 번째 중간 목표다.
  7. UI 라이브러리 교체. 가장 오래 걸리는 구간. 공용 컴포넌트(버튼·모달·테이블·폼)부터 정리하면 하위 화면이 한꺼번에 따라온다.
  8. 런타임 회귀 사냥. 프래그먼트·속성 폴스루·emits 미선언·v-model 규약 변경(value/inputmodelValue/update:modelValue, .syncv-model:argv-ifv-for 우선순위·프록시 동일성에서 오는 조용한 버그를 찾는다.
  9. 안정화 후에야 Composition API·TypeScript·Pinia를 순서대로 논의한다.

8번까지가 "옮기는 일"이고, 9번은 "더 좋게 만드는 일"입니다. 이 둘을 같은 티켓에 넣지 마십시오.

언제는 하지 말아야 하는가

Vue 2가 공식 지원 종료 상태라는 사실이 곧 "모든 앱을 지금 옮겨야 한다"는 뜻은 아닙니다. 다음 경우에는 미루거나, 아예 다른 결론을 내는 편이 맞습니다.

정리

Vue 2에서 3으로 가는 일의 난이도는 컴포넌트 개수가 아니라 결합의 종류가 결정합니다. 전역 프로토타입에 얼마나 얹었는지, 이벤트 버스로 얼마나 흘렸는지, 남의 UI 라이브러리에 얼마나 깊이 묶였는지, 프레임워크가 모르는 객체를 반응형 상태에 얼마나 넣어 뒀는지가 실제 일정입니다. 문법 변경은 목록화만 되면 끝나는 작업이고, 그 목록은 공식 마이그레이션 가이드에 이미 있습니다.

그래서 계획을 세울 때 순서를 이렇게 잡으십시오. 의존성 인벤토리 → 전략 결정(빅뱅/병행) → 축 분리(빌드 먼저, 프레임워크 다음, 개선은 마지막) → 검증 수단 확보 → 착수. 그리고 마이그레이션 티켓 안에 "이참에"로 시작하는 항목이 들어오면, 그건 다른 티켓으로 옮기십시오. 마이그레이션이 실패하는 가장 흔한 이유는 기술적 난이도가 아니라, 한 번에 너무 많은 것을 바꾸려 한 데 있습니다.

같은 주제의 다른 글

맘소프트는 19년 넘게 금융 · 엔터프라이즈 · 모바일 시스템을 만들어 왔습니다. 여기 적는 글은 그 과정에서 실제로 부딪히고 해결한 것들입니다.

기술 판단이 필요하신가요

맘소프트는 소프트웨어 개발과 CTO 대행 · 기술 자문을 제공합니다. 편하게 문의해 주세요.

[email protected]