최근에 팀내 개발자 중 A 개발자가 나한테 찾아와서는 템플릿 내부에 코드를 잘 작성하였는데 화면에서는 안보이고 있다고 찾아옴...

 

A 개발자 나름 문제 해결을 위해서 찾아봤는데 문제점은 template 태그가 존재하고 해당 태그의 css display가 none 이 되어 있어서 내부 코드들이 안 보이는 것 같다고 이것이 문제다! 라고 하였다...

 

 

그런데 정상적인 코드면 template 가 보일 이유가 있나?... 작성된 코드를 가보았당

 

 

어... 음 template 내부에 template 코드가 들어가있네... 

 

template 태그는 특정 디렉티브 ( v-if, v-for, v-else 등..) 이 없으면 template 엘리먼트 그냥 들어간다.. 단 최상위 탬플릿 태그랑 이런 것들은 별개 사항

 

결론은 vue 공식 문서 다 ~ 있으니까 다시 읽고 나한테 설명하라고 함

 

 

Vue.js

Vue.js - The Progressive JavaScript Framework

vuejs.org

 

출처 - vue 래퍼..

최근에 사수가 퇴사하게 되면서 팀 사정상 부서 이동이 되었고... 기존 파트에서 사용하던 vue2 프로젝트를 vue3 로 변경하는 작업을 진행 하고 있는 중입니다.

 

작업은 vue3 버전 템플릿 형태는  tempate - script (setup) - style 형태로 아래와 같이 사용하고 있는데

<template>
    <div>

    </div>
</template>

<script setup>

</script>

<style lang="scss" scoped>

</style>

 

 

컴포지션 api - setup 형태는 인스턴스 구조에 제약을 두고 있지 않다보니... 자동으로 snippet 이 적용이 안되고 있습니다.

 

그래서 개발자 개인적인 취향으로... 보기 좋게 작성 하기 위해서 vscode 내부에 snippet 를 임의로 커스텀 하여 사용 하였고 추가 된 주석은 아래와 같음..

 

 

<template>
    <div>

    </div>
</template>

<script setup>

</script>

<style lang="scss" scoped>
// ✅ 1. Import 필요한 모듈
// ✅ 2. Props & Emits 정의
// ✅ 3. 반응형 상태 선언
// ✅ 4. Lifecycle Hooks (마운트/언마운트 시 로직 실행)
// ✅ 5. Watcher (props 값 변경 감지)
// ✅ 6. 이벤트 핸들러
</style>

 

코드 snippet 은 아래 설정 사용 하였습니다...

 

"Vue 3 Setup Component": {
      "prefix": "v3s",
      "body": [
        "// ✅ 1. Import 필요한 모듈",

        "// ✅ 2. Props & Emits 정의",

        "// ✅ 3. 반응형 상태 선언",

        "// ✅ 4. Lifecycle Hooks (마운트/언마운트 시 로직 실행)",

        "// ✅ 5. Watcher (props 값 변경 감지)",

        "// ✅ 6. 이벤트 핸들러",

      ],
      "description": "Vue 3 Composition API - setup() 기본 구조 템플릿"
    }

 


 

 

사내 프로젝트를 리엑트로 만드는 중에 생긴 이슈와 관련되어 정리한 내용입니다.

현재 프로젝트 상황은 아래와 같다

 

  • 서버 데이터를 생성/수정/삭제 하는 CRUD 중 CUD 기능은 크게 사용 X
  • 대부분 Read 기능 요구이며 전달 값 (param) 에 맞게 다른 Read 요청 필요
  • 에러 핸들링은 서스팬스와 에러 바운더리 통해서 처리
  • tanstack query (react query) 는 v5
  • useQuery , useSuspenseQuery 사용 하는 훅 생성 중

이슈 1.

이런 환경 속에서 page 컴포넌트에 최초 마운트 되었을 때 필요에 따라 쿼리를 돌릴지 말지 정해야 할 필요가 있는데 useQuery의 경우 enabled 옵션을 false 하면 되지만 서스펜스를 이용하기 위하여 사용 하는 useSuspenseQuery 의 경우에는 마운트 되버리면 실행 되는 상태입니다.

 

// 커스텀 훅
const useLogin = (param) => {
	
	const fetchData = (param) => {
		//fetch 처리
	}
	
	//query 방식
	const {data1} = useQuery({
		queryKey: ['login', param],
		queryFn: () => fetchData(param),
		enabled: false
	});
	
	//suspense 방식
	const {data2} = useSuspenseQuery({
		queryKey: ['login', param],
		queryFn: () => fetchData(param),	
	})
	
	return {data1, data2}
};


// 실제 페이지

const Page = () => {
	const [test, setTest] = useState({});
	const {data} = useLogin(test);
	
	const handleClick = (e) => {
		// 이래저래 이벤트 처리 후 obj 객체 생성하여
		setTest(obj);
	}
	
	return (
		<>
			<button onClick={handleClick}>클릭</button>
			로그인 여부 :{data.isLogin}
		</>
	)
	
}

 

 

이슈 2

위 작업 중에 fetch 에러가 발생하여 throw Error 를 할 경우 에러바운더리로 던져지는 작업 하고 싶은데 실제로 에러 바운더리로 던져지긴 하지만 에러 로그가 2번 이상 발생 되는 상황이 발생 됩니다.

 

const fetchData = (param) => {
	return await axios.get('/',param)
	.then((res) => { return res})
	.catch((err) => { throw err});
}


	//query 방식
	const {data1} = useQuery({
		queryKey: ['login', param],
		queryFn: () => fetchData(param),
		enabled: false
	});
	
	//suspense 방식
	const {data2} = useSuspenseQuery({
		queryKey: ['login', param],
		queryFn: () => fetchData(param),	
	})

 

이런식으로 코드를 작성하면 query 에서는 queryFn 에서 return 되는 data 값이 없다고 에러 1번 발생 되고 fetchData 에서 발생 된 throw 관련 에러도 발생 되면서 필요 없는 에러가 여러번 발생 되고 있습니다 . 

 

 


 

이슈에 대한 생각

이곳 저곳 커뮤니티나 다른 개발자 분들에게 질문 외에도 래퍼나 내가 놓친 것이 없는지 다시 되돌아 공부해보면서 나온 결과입니다.

 

이슈 1.

먼저 이슈 1의 경우에 react의 suspense 목적은 이해하고 있었다고 생각했지만 제대로 이해하지 못한 상태로 사용한 문제로 생긴 이슈입니다.

 

애초에 suspense는 fetching 하는 동안 특정 UI 화면을 보여주기 위한 목적으로 사용 되어야 하는데 저는 에러 바운더링을 사용하기 위해서는 꼭 사용해야하는 기능이라고 생각하여 사용하였고, 그로 인하여 react-query 내장 함수 중 useSuspenseQuery 를 사용하게 된 것입니다.

 

개발 의도에 따르면 최초 마운트 되었을 때 실행 처리를 다르게 해야 하는데 무조건 실행 되어야하는 suspense 기능 때문에 훅이 자동으로 돌게 되는 것...

 

그렇기 때문에 개발 의도에 맞게 사용하려면 useSuspenseQuery가 아닌 useQuery 를 사용해야 하고, 옵션 (enabled : false 또는 useRef로 마운트 못하게 하기...) 등을 통해서 분기를 생성 해야 한다는게 결론입니다.

 

이슈 2.

 

사실 에러 관련 된 내용은 서스팬스 작업 때 발생 되는 오류들 중 하나라서 크게 이슈 될 문제는 아니라고 하는 피드백이 대부분이였지만... 해결책을 찾지는 못했다 ... (이럴꺼면 애초에 이슈라고 남기지도 말껄  ㅠ ..)

 

추가적으로 리엑트 쿼리나 리엑트에 대해서 위 이슈 같은 내용들이 나올 때마다 기록을 남겨두는 습관을 만들 계획이다

 

 

vue-cli 에서 vite 프로젝트로 변경 하던 와중 기존 파일 명칭(실제로 index.vue가 있음)을 생략하고 폴더명만 작성해도 불러왔던 코드들이 제대로 실행 되지 않는 오류가 발생 됨

// 작성된 코드
import dirComponent from './component/dir';

// 이렇게 작성해야지 파일을 찾음...
import dirComponent from './component/dir/index.vue';

 

여러 구글링을 통해서 확인한 결과 위와 같이 실제 내부에는 index.vue 파일이 존재하지만 간략히 작성할 경우에는 vite에서는 찾지를 못하기 때문에 꼭 파일명과 확장자명을 작성해줘야 한다는 글들을 확인했음.... (그러면 생략한 몇백 몇천개의 파일을 하나하나 .vue 확장자명을 붙혀야함...)

 

하지만... 다른 js, ts, jsx, tsx 등과 같은 파일 확장자명은 잘만 찾아 오던데?... 라는 의심으로 레퍼런스를 잘 찾아본 결과 vite는 참 불친절하게도 .vue 파일 확장자 명을 제외한 다른 애들은 잘 가져온댄다.

 

 

그래서 당장 vite.config.js 파일을 켜서 수정 해버림

 

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue2'

export default defineConfig({
     plugins: [vue()],
     resolve: {
        extensions:['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json', '.vue'] //.vue 추가!
     } 
})

 

잘된다... 야호

 

참고 : https://ko.vitejs.dev/config/shared-options.html#css-postcss

 

Vite

Vite, 차세대 프런트엔드 개발 툴

ko.vitejs.dev

 

+ Recent posts