Vue에서 Next로 마이그레이션-cover

Vue에서 Next로 마이그레이션

Vue 프로젝트 콤마를 Next로 마이그레이션 해보자

Written by Given at2025.02.17

Comma 프로젝트

우리의 귀여운 프로젝트였던 콤마가 끝나고 팀도 끝났지만 콤마 프로젝트는 애정이 가는 프로젝트입니다. 그래서 더 업그레이드를 해보고 아예 SEO까지 확장하여 누구나 참여할 수 있는 프로젝트로 만들어 보고 싶었습니다. 이 글을 통해 Vue에서 Next.js로 마이그레이션했던 경험을 공유하고자 합니다.

Vue to Next

왜 Vue 기반인데 Nuxt.js가 아닌 Next.js인가?에 대한 질문에 대한 답은 사실 별거 없습니다. 이유는 Vue보다 React 생태계를 활용하며 SEO를 활성화하는데 Next.js가 더 유리하다고 판단했기 때문입니다. SEO 최적화, 서버 컴포넌트 활용 그리고 Vercel를 사용한 배포환경에서 Next를 선택하게 되었습니다.

1. 세팅

필요한 패키지들을 다운받았습니다. Vue 전용 라이브러리들 같은 경우에는 그에 대응하는 React 라이브러리를 사용했습니다. 예를 들어 Pinia 같은 경우, 완전히 Vue 개발에만 특화되어 있어 그와 비슷한 zustand를 사용하여 전역 상태관리를 진행했습니다. 두 라이브러리 모두 웹 스토리지를 사용하는 persist 기능을 지원하기에 어려움은 없었습니다.

그 외 특별히 다른 점이라면 route설정이 있는데 Vue router에는 meta 프로퍼티에 레이아웃을 설정하여 페이지별 레이아웃을 설정해줄 수 있습니다. Next에서 13버젼 이후부터는 이를 app router를 사용하여 그룹화하여 그룹별 레이아웃을 나누는 방식으로 설정할 수 있습니다.

2. 라이프사이클

React와 마찬가지로 Vue에서는 생명주기(라이프사이클)이 나누어져있습니다.

vue 라이프사이클

React 함수형 컴포넌트의 useEffect, useLayoutEffect보다 세부적으로 나누어져있는 것을 알 수 있습니다.

React 라이프사이클

React의 마운트와 언마운트 개념을 알고있다면 크게 어려운 것은 없습니다.

3. 이미지 최적화

Next.js에서는 Image 태그로 자동으로 이미지 최적화를 제공해줍니다. 우리 프로젝트는 supabase 스토리지를 사용하기 때문에 next.config.js 에서 image 프로퍼티에 supabase 이미지 도메인만 설정해주면 될 것 같았지만, OAuth에서 제공해주는 프로필 이미지들 역시 모두 설정이 필요했습니다.

images: { remotePatterns: [ { protocol: "https", hostname: "avqfmrsjdoggaaelpugz.supabase.co", port: "", pathname: "/storage/**", search: "", }, ...도메인들 ], minimumCacheTTL: 86400, // 이미지 최소 캐시 formats: ["image/avif", "image/webp"], // 최적화를 위한 이미지 포맷 },

4. 페이지 별 기능 구현

각 페이지 별로 기능 구현을 옮기는 것은 위 사항들만 감안하면 크게 어렵지는 않았습니다. 하지만 vue와 react의 상태 관리에는 차이가 있었는데, React는 기본적으로 단방향 데이터 흐름을 따르며, 상태를 props로 전달하고 이벤트 핸들러로 변경해야 하는데 vue에서는 양방향 바인딩에서 차이가 있어 상태변경을 구현하는데 있어 차이가 있습니다. 그리고 vue3의 컴포지션 api 에 경우 ref와 reactive등 상태 관리가 자바스크립트와 비슷하게 사용이 가능하지만 react의 useState 등은 명시적인 느낌은 들었지만 화면이 리렌더링되고 함수호출 위치에 따라 상태값 변경이 안되는 경우도 있어 어려움이있었습니다. 그럴경우 실시간으로 상태값이 적용되는 useRef를 사용하여 순서에 따라 상태값을 참조하고 반영할 수 있도록 구현이 가능했습니다.

특히 게임상태 관리에서...

5. SEO

기존 프로젝트는 모든 서비스를 로그인 인증이 필요했지만 이제는 커뮤니티 등 페이지는 SEO로 서버렌더링이 필요하기 때문에 일단 커뮤니티 등 READ 관련 기능들은 로그인 인증이 필요없도록 수정했습니다. 그래서 로그인이 필요한 경우와 불필요한 경우로 나누어 인증을 재설정했습니다. 이제 커뮤니티 심지어 게임 화면까지도 로그인이 필요하지는 않지만 좋아요, 댓글을 할 수 없으며, 게임점수가 등록되지않은 등 처리가 되어있습니다.

그리고 getMetaData라는 유틸 함수를 만들어 동적으로 meta정보 수정이 용이하게 하였고

export async function generateMetadata({ params }: Props) { const { name: gameName } = await params; const data = await getGameByName(gameName); return getMetadata({ title: data.display_name, ogImage: `/meta/${gameName}.png`, }); }

위와 같이 ogImage 역시 설정할 수 있습니다.

검색 결과

Google 검색 결과

ogimage

카카오 ogImage