먼저, 현재 다니는 회사에 입사 후 제가 제일 먼저 한 업무는 Vue SPA 프로젝트 도입 이였습니다.

 

벌써 2년 넘게 근무한 회사이지만 초기 입사 시기 회사 특성 상 프론트 관련 된 프로젝트나 부서는 없었다 보니 .. 회사에 근무 하시던 분들은 온전한 vue 기능을 사용하지 않고 있었으며... 실제로 vue 프로젝트는 cdn으로 스크립트를 가져와서 작성 되어 있었다...

 

 


 

 

시간이 지날 때마다 코드는 수정한다고 하였지만 .. 오전 출근 하자마자 오류건을 발견하여 간단히라도 기록 남겼습니다.

 

 

먼저 바뀌기 전 코드

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8" />
        <title>타이틀</title>
        <style lang="scss">
        	body {
            	.wrap {
                	//....자식 관련 리소스들
                }
            }
        </style>
    </head>
    <body>
		<div class="wrap">
        	//.... 자식 관련 리소스들
        </div>
	</body>
</html>

 

바뀐 코드

 

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8" />
        <title>타이틀</title>
        <style>
        	body {
            	// body 관련 코드..
            }
            
            body .wrap {
               // wrap 코드..
            }
            
            body .wrap ....자식코드들 {
            
            }
        </style>
    </head>
    <body>
		<div class="wrap">
        	//.... 자식 관련 리소스들
        </div>
	</body>
</html>

 

 


 

원인

  • 기존 css 네스팅방식은 sass, less 등 에서만 사용 하였지만 css 에서도 사용할 수 있게 되면서 최신 브라우저에서는 호환이 됨
  • 그러나 최신 브라우저에서 '만' 가능한 부분이기 때문에 구형 웹 브라우저 또는 모바일에서는 사용 할 수 없음
  • style lang ="scss" 는 vue cli 에서 편의를 위해 제공하는 기능이기 때문에 *.vue 확장자가 아니라면 사용 X

결론

  • 구형 웹브라우저 등을 위한 컴파일 된 스타일 형태로 전달하거나 css 형태로 전달하기
  • style lang = "scss" 사용하고 싶으면 vue파일 사용해라

 

참조

https://developer.chrome.com/docs/css-ui/css-nesting?hl=ko

 

CSS 중첩  |  Chrome for Developers

즐겨 사용하는 CSS 전처리기 기능 중 하나인 중첩 스타일 규칙이 이제 이 언어에 내장되어 있습니다.

developer.chrome.com

https://www.mizzu-creations.xyz/css-nesting

 

더 나은 CSS 코드 작성을 위한 CSS Nesting

CSS Nesting의 시대가 도래했다! CSS Nesting을 통해 CSS 코드 작성을 개선하는 방법

www.mizzu-creations.xyz

https://cli.vuejs.org/guide/css.html#pre-processors

 

Working with CSS | Vue CLI

Working with CSS Vue CLI projects come with support for PostCSS, CSS Modules and pre-processors including Sass, Less and Stylus. Referencing Assets All compiled CSS are processed by css-loader, which parses url() and resolves them as module requests. This

cli.vuejs.org

 

react로 만든 프로젝트 또는 storybook 프로젝트와 같이 node 웹 서버를 사용 하는 프로젝트는 개발 시 로컬 서버를 구동하면 되는 부분이지만 개발자 외 다른 사용자가 볼 수 있도록 특정 ip 서버 쪽에 반영하여 지속적으로 운영 해야하는 상황이 생겼음....

 

이를 위해서 서버 관리자에게 개발용 서버를 발급 받았고 이 서버에서 node 웹 서버를 지속적으로 실행하기 위하여 docker 를 이용하기로 생각함...

 


 

 

Docker에서 node.js 이미지 다운 받은 후 프로젝트 웹 서버를 실행 시키는 방법

 

1. node.js 이미지 다운로드

이미지를 단로드 받기 위한 터미널은 아래와 같이 입력 (예시)

docker pull node:버전

 

 

docker images | grep node



REPOSITORY                 TAG       IMAGE ID       CREATED         SIZE
node                       18.15.0   9615572c45b7   16 months ago   997MB

 

 

2. node 컨테이너 실행

다운 받은 node 이미지를 사용하여 컨테이너를 실행 하고, docker cp 명령어를 이용하여 복붙

docker run -it -d 포트번호:포트번호 --name=컨테이너이름 도커이미지:버전

 

  • docker run 도커이미지:버전 => 도커이미지를 이용하여 컨테이너를 생성 후 실행 시켜라
  • --name : 이름 => 컨테이너 이름을 '이름'으로 지정
  • -d => 컨테이너를 백그라운드에서 실행 시켜라
  • -p 포트번호:포트번호 => 컨테이너의 앞포트번호 포트를 뒷번호포트번호 포트와 연결시켜라

이후에 Docker의 exec  명령어를 통하여 컨테이너를 사용합니다.

 

docker exec -it 컨테이너이름 /bin/bash

 

위 명령어 사용하면 bash 창이 뜨며 정상적으로 명령어를 제어 할 수 있음

 


위 방식 외에도 .yml 코드 또는 dockerfile 를 작성하여 자동화 시켜야 할 필요가 있는데 이 부분은 조금 더 docker 에 대하여 이해하고 사용 하겠습니다.

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

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

 

  • 서버 데이터를 생성/수정/삭제 하는 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