728x90

 

로딩 관련 컴포넌트를 페이지에 추가할때 보통 위와 같이 추가하기 마련이다. 

그런데 위와 같이 넣을때 에러가 발생하는 경우가 있다. 그러면 습관성 삼항 연상자를 이용해서 로딩이 아닌경우  fragement(<></>) 를 리턴하게 함으로 타입 에러를 처리하고 턴을 마친다.

 

그런데 이 날따라 (혹은 이제서야) 의문이 들었다. 아니 분명 위와 같이 작성해도 문제가 되지 않는 부분도 있는데, 왜 타입 에러가 발생하는 케이스가 생기는걸까?


 

React.Element 와 React.Node 를 먼저 잠깐 살펴보자. 이를 보통 컴포넌트 props 를 넘겨줄때 children의 타입으로 지정하면서 본적이 있을 것이다. 각각의 의미를 살짝 보자면 아래와 같다.

 

React.Element

- 앱을 구성하는 작은 블록으로 일반 JavaScript 객체 형태이다.

- JSX 문법 (<MyComponent />, <div></div>)을 사용하면 Babel과 같은 트랜스파일러가 내부적으로 React.createElement() 함수 호출로 변환하여 이 객체를 생성한다.

 

React.Node

- React 컴포넌트가 렌더링 할 수 있는 모든것.

- React Node들을 담고 있는 배열 ([<li key="1">A</li>, <li key="2">B</li>]). React는 배열 내부의 노드들을 순서대로 렌더링한다.

 

쉽게 말해서 <div> 처럼 태그로 이루어진 컴포넌트 들은 Element 라고 할 수 있고,

이를 포함해서 단순한 number, string 등 화면에 그릴 수 있는 모든 값이  Node에 포함된다.

 

이제 다시 처음의 문제로 돌아가보자.

위 코드가 적혀있는 컴포넌트 children의 타입은 React.Element로 선언되어 있다. 

로딩중이라면 <LoadingScreen> 이라는 Element를 정상적으로 반환하겠지만 로딩중이 아니면 null 값이 리턴이 되는데 이는  Element범위에 속하지 않는다. 이에 타입에러가 발생했던 것이다. 

리턴되는 children의 타입을 React.Node 로 수정하면 null 이 리턴되더라도 문제가 없기에 타입에러는 사라지게된다!

 

추가적으로 React 자체 타입정의(@types/react)에서도 PropsWithChildren 유틸리티 타입을 사용하면 children의 타입이 ReactNode로 되어있는것을 확인할 수 있다. ReactNode를 사용하는게 표준으로 봐도 무방하지 않나 싶다. 

 

앞으로 children 의 타입은 ReactNode 를 사용하자~!

 

 

728x90
728x90

pm2 를 쓰고 있다면 최근에 빌드하면서 위와 같은 에러를 마주했을 수도 있다.

 RUN yarn && yarn global add pm2....

 

위와 같은 명령어로 실행시키면 저번주만해도 문제 없이 잘 진행되었지만 오늘 갑자기 아래와 같은 오류가 발생했다.

 

 

- error pm2@6.0.5: The engine "node" is incompatible with this module. Expected version ">=16.0.0". Got "14.21.3"

- error Found incompatible module

 

 

일단 코드쪽에서 버전을 변경한게 없어서  서버 관리자분께 혹시 버전 변경된게 있나 문의를 넣었지만 따로 변경된 부분은 없었다.

그러다가 pm2 가 최근에 새로운 버전이 나왔다는 것을 확인했다.

 

https://www.npmjs.com/package/pm2/v/2.0.15?activeTab=versions

 

pm2

Production process manager for Node.JS applications with a built-in load balancer.. Latest version: 6.0.5, last published: 9 days ago. Start using pm2 in your project by running `npm i pm2`. There are 1737 other projects in the npm registry using pm2.

www.npmjs.com

 

기존에는 5.4.3을 사용했는데 오늘 날짜 기준으로 9일전에 새로운 6.0.5 버전이 출시된것.. 하지만 이 6버전은 node가 14인 환경에서는 정상적으로 작동하지 않아서 해당 에러가 발생했던 것이다.

 

@근데 왜 내 버전은 갑자기 5.4.3에서 6.0.5 버전으로 변경되서 빌드가 시작된것일까?

 

그건 명령어를 yarn global add pm2 로 해두었기 때문이다.

 

global이 들어가 있기 때문에 최신 버전을 받아서 진행되는데, 이에 빌드할때 최신 버전인 6.0.5가 사용된것이다. 그렇다면 해당 명령어만 수정해준다면 해결될 것이다. 나의 경우 직전의 버전까지 정상작동을 확인했기 때문에 아래와 같이 pm2 설치시에 버전을 특정해주었다. 

 

$ yarn global add pm2@5.4.3

 

 

pm2가 아니더라도 global로 진행되는게 있다면 이런 문제가 발생할 수 있다는 것을 인지해두고 사용을 지양해야하지 않나 싶었다.

728x90
728x90

편한 노드 버전관리

여러 프로젝트를 넘나들다보면 node 버전이 문제가 될 때가 있다. 시간이 오래걸리는 문제는 당연아니다.

프로젝트를 실행시키거나, 커밋을 날렸을때 노드 버전관련 이슈가 나오면 "아.." 정도 한탄 한번 해주고 버전을 변경해주면 된다.

 

이를 단순화 시켜주는 방법이 .nvmrc 파일을 사용하는 것이다.

프로젝트 내에 해당 파일을 만들고 버전을 지정해주면 (ex 20.16.0), nvm use 명령어 하나로 해당 노드 버전으로 변경해준다.

 

하지만.

노드 버전 찾고 변경하고 하는것보다야 편해졌지만 프로젝트를 변경할때마다 명령어를 쳐줘야만하니 묘하게 거슬린다.

이 또한 자동화 시킬 수 있다면 얼마나 편해질까? ㅇㅈ?ㅇㅇㅈ

이미 프로출신들은 아주 편하게 자동화 시켜놨다는것..

이는 .zshrc 파일에 특정 코드를 추가해줌으로써 달성할 수 있다.

 

uvm use 자동화 시키기

vim ~/.zshrc 로 파일을 열어주고 아래 코드를 추가해 준다. 

뜬금 zshrc 나만의 팁이 있다면

1. 해당 파일에 생각보다 추가되는 코드가 많기에, 코드를 추가할때 #를 활용해서 추가되는 코드 상단에 내용을 추가해주면 나중에 확인이 편하다. 많아지면.. 이걸 왜추가했는지 기억이??

2. #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! 이 위쪽으로 추가할것 ㅎ

 

코드는 아래와 같다.

# auto nvm use
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

 

 위 코드를 추가해주고 :wq 로 저장후 나와서 source ~/.zshrc로 적용시켜주면 완료!

후에 .nvmrc 파일이 있는 프로젝트를 열면 아래와 같이 자동으로 적용되는 것을 확인 가능하다.

 

 

728x90
728x90

api의 결과물이 CORS라면, 프로 출신들은 다음의 대사가 머릿속에 떠오른다.

 

"백엔드에게 CORS 관련 설정을 추가해달라고해야지~ 해줘~"

 

하지만 그에 대한 대답이 다음과 같다면 어떨까?

 

"이미 cors 설정 다 되어있습니다."

 

"what?????????????"

 


 

 

특정 api 에서 cors가 발생하고, 관련 확인 요청을 드렸는데 위와 같은 대답이 돌아왔다.

생각해보니 같은 엔드 포인트를 가지고 있는 다른 api 들은 잘 사용하고 있었다.

그런데 왜 유독 이 api에서만 갑자기 cors 에러가 발생한것일까?

 

결론 부터 말하자면 보내는 데이터의 크기가 문제였다.

사용하는 Django의 POST요청 최대 크기 기본값은 2.5MB 였는데, 보내는 데이터가 사진으로 4MB를 넘어버렸다.

이런 상황에서 아래 두 원인중 하나로 인해서 에러가 발생했던 것이다.

 

1.  이에 서버는 400이나 413 을 응답했으나 브라우저에서 구분을 못해서 해당 CORS오류가 발생 가능성

2.  크기가 너무 커서 OPTION요청을 무시해버렸고 이 때문에 CORS 오류 처럼 보이는 메세지가 나왔을 가능성

 

해결 방법은 행복(?)하게도 백엔드에게 다시 요청드리면 된다.

 

"요청 허용 용량을 늘려주세요~"

 

그러면 백엔드에서 아래와 같은 설정을 통해 허용 용량을 늘려줄것이다.

그러고 나면 문제 해결!

 

DATA_UPLOAD_MAX_MEMORY_SIZE = {허용 사이즈}

 

 

CORS에러가 발생했을때 원인이 크기에도 있는지 상상도 못했는데,

보내는 파일이 크다면 한번 쯤 생각해보는것으로!

728x90
728x90

 

 

터미널을 탐방중 루트에 올라가 보면 내가 따로 만든적은 없는 파일들이 많이 보인다.

bin, sbin, tmp...  파일 제목만으로는 무엇을 담고있는지 감이 오지는 않는다.

그런데 생각 보다 친숙한 것들이 파일들에 있다. 이중 오늘은 bin 에 대해서 살펴보자.

 

저 위에 bin 폴더는 하나밖에 안보이지만, bin 폴더는 생각보다 여기저기에 들어있다. OMG

/bin
/sbin
/usr/bin
/usr/sbin
/usr/local/bin
/usr/local/sbin

 

 

영어에 자신이 있다면, 아래 명령어를 입력하면 폴더들에 대한 설명을 볼 수 있다.

$ man hire

 

 

해당 명령어를 입력하면 각각의 폴더에 대해서 설명들을 볼 수 있다.

 

/bin/                user utilities fundamental to both single-user and multi-user environments
/sbin/              system programs and administration utilities fundamental to both single-user
                       and multi-user environments
/usr/bin/         common utilities, programming tools, and application
/usr/sbin/       system daemons & system utilities (executed by users)

/usr/local/       executables, libraries, etc. not included by the basic operating system

 

정의 자체는 위와 같고 이제 조금 더 깊이 들어가보자 (local 하위에 대한 설명은 없다ㅜ)

 

sbin

bin과는 큰 차이가 없지만, 사용시에 root 권한이 필요한 친구들이 들어있다.

가끔 명령어를 칠때 sudo.. 로 친적이 있을 것이다. 이런 루트 권한을 필요로 하는것이다.

그럼 bin만 알면 되겠구만!!

 

bin

폴더 안에 들어가보면 어떤 친구들이 들어있는지 바로 확인가능하다.

 

ls, kill, rm 등 간간히 사용했던 명령어들이 있다. 이렇듯 여러 사용자에게 기본적으로 필요한 기능들이 여기에 들어있다고 보면 되겠다.

정의로는 리눅스의 기본명령어들이 들어가있다고 볼 수 있겠다.

 

/usr/bin

 

여기는 엄청나게 많은 파일들이 있다. 익숙하지 않은 친구들도 있지만, vim, sudo 같은 친밀한 친구들도 여기에 포함된다.

ls, kill 그리고 sudo, vim은 다 비슷한 명령어 아니었던가? 뭐가 다르다고 이렇게 분류되어 있을까.

<GPT 피셜>

/bin 폴더에 있는 ls, kill 등의 명령어는 단일 기능을 수행한다. 폴더 열기, 죽이기 등.

하지만 /usr/bin 폴더에 있는 vim 명령어는 단일 기능보다는 확장된 기능을 제공한다. vim은 파일 열기 외에도 수정할 수 있는 플로우로 유저를 이동시켜주는것을 예로들 수 있겠다.

 

/usr/local/bin

 

여기는 사용자가 따로 설치한 파일들이 들어가있다.

따라서 기본적으로는 비어있고 설치한게 있다면 그때마다 추가가된다.

반가운 친구들이 보이는데 node, npm 등의 파일들은 추가로 설치했기에 여기에 위치하고 있다. 

 

 

728x90
728x90

평화로운 시기에 역시나 간간히 찾아오는 react-native 빌드 오류다.

 

yarn android —deviceId=기기 ID의 형식으로 안드로이드 기기에서 rn을 실행하는데,

위 오류가 발생했다. 에러 메세지 만으로는 쉽게 와닿지 않는 오류였다. 

이런건 보통 gradle 오류겠거니해서 clean 후 다시 설치해 보았지만 실패.

 

간단한 원인은 jdk 버전 문제였다.

rn은 정말 같이 확인해야하는게 너무 많아....

최근에 다른 프로젝트 실행을 위해서 java 버전을 잠시 변경해 두었는데

이 때문에 문제가된것..

고로 원래 사용중이던 버전으로 돌아만 간다면, 혹은 문제없는 jdk로 설정한다면 해당 오류를 수정하고 넘어갈 수 있겠다.

순서는 아래와 같다.

 

 

1. Java 버전 확인

$ java -version

 

 

2. 깔려있는 java 버전 확인

$ /usr/libexec/java_home -V

 

 

위 명려어를 치면 설치되어있던 버전들을 확인할 수 있다.

사용했던 버전이 뭔지 모른다면 위 방식으로 사용했던 자바 버전을 추측해볼 수 있겠다.

 

3. 버전 설정

$ export JAVA_HOME=$(/usr/libexec/java_home -v 11)

 

변경하고자 하는 버전을 선택해서

위 11의 자리에 원하는 버전을 설정해주면 버전을 변경 할 수 있다.

 

그리고나서 빌드를 돌리면..!? 

예전과 같이 빌드가 잘 됨을 확인해볼 수 있겠다.

 

여러분의 rn을 응원합니다ㅎ

728x90
728x90

 

 

turbo 는 모노레포를 사용시 많이들 사용하는 것중에 하나이다.

본인도 하나의 프로젝트에서 turbo를 잘 사용하고 있는데,

lock 파일을 업데이트 이후에 빌드중에 위 에러가 발생했다.

x Found `pipeline` field instead of `tasks`

문제없이 잘 되다가 갑자기 빌드가 실패하면 언제나 지끈거리는 머리다.. 하지만 위 에러는 그렇게 큰 노력(?)을 요하지는 않는다.

에러 그대로 수정만 해준다면 정상적인 빌드가 가능하다!

 

루트 폴더의 turbo.json 파일 수정만 가볍게 해주면 된다.

 

기존 turbo.json

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    }
  }
}

 

현재는 'pipeline' 으로 되어있었지만 특정 버전 이전에는 'tasks' 로 값이 쓰였다고 한다. 

 

변경 후 turbo.json

{
  "tasks": {  // pipeline -> tasks
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    }
  }
}

 

 

해당 파일을 수정하고나서 turbo 빌드를 다시 실행시키면 정상적으로 빌드된다.

 

 

 

728x90
728x90

해프닝

프런트엔드의 재미난(?) 고충 중의 하나. 특정 기기에서 이상하게 보인다는 것이 qa를 통해서 들어왔다. 분명 내 화면에서는 문제가 없었는데 왜 그럴까... 하아~ 내가 겪은 문제는 아래와 같았다.

 

아래는 내가 구현해둔 로딩 페이지이다. 로딩 중이라는 텍스트를 inset-0이라는 속성을 이용해서 화면 가운대 배치를 했다.

inset: 0 속성은 fixed나 absolute의 요소를 중앙 배치 하기 위해서 쓰기 아주 좋은 속성이다.

inset: 0은 top: 0, bottom: 0, right: 0 , left: 0의 기능을 하기에 4개나 써야하는 속성을 하나의 값으로 해결할 수 있다.

 

그런데 구형 ios 버전을 가지고 있는 기기에서는 중앙정렬이 되지 않고,

아래와 같이 구석에 콕 박혀있게 디스플레이되게끔 나오는것이다... 

 

 

중앙정렬 관련해서는 inset 속성을 사용했기에 해당 css를 검색해보기로 했다.

 

다큐먼트를 보면서 최하단에 이렇게 호환가능한 버전이 써있는건 여러번 봤을 것이다.  (존재는 알았지만 눈여겨본적이 없느...)

여기서 ios 14.5 버전 이후로 지원한다고 되어있는데, 테스트한 기기는 14.5 보다 낮은 버전의 기기였다. 그래서 inset 속성이 정상적으로 지원하지 않는것 같다.

 

해결

해결 방법은 간단하다. inset의 무엇을 의미한다고 했던가? 4가지 속성을 한번에 표현한다고 했는데 그 속성을 각각 모두 써주면 된다. 고로 아래와 같이 모두 풀어서 써주면 원하는 css를 다시 입힐 수 있다.

// 구버전 ios 에서 지원 X
inset: 0

// 수정 코드
top: 0
bottom: 0
right: 0
left: 0

 

 


 

이와 비슷하게  display: flex 의 속성을 사용했을때 gap의 속성도 구버전에서는 정상적으로 작동하지 않는 경우가 있다.

이럴때는 flex의 설정을 grid로 변경하거나 (grid의 gap은 정상적으로 작동한다..!) gap 대신 margin 속성을 이용해서 원하는 디자인을 구현해야한다.

 

 

예상치 못한 구현버전의 위협....멈춰...! 

728x90
728x90

엑셀 파일을 다운로드 기능을 구현할때가 있다.

오늘은 해당 기능에 대해서 살펴보려한다.

보통 엑셀 다운로드용 api를 받아서 사용하는데, GET과 POST 2가지 방법이있다. 

값을 받아서 구현하는 순서는  아래와 같다.

 

 

try{
 const res = await excelFile(); // 엑셀 데이터 넘겨주는 함수
 const url = window.URL.createObjectURL(
  new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
 );
}....

 

여기서 res.data, 즉 엑셀데이터의 값은 우리가 알아들을 수 없이 'PK\x03\x04\x14\x00\x00\x0..' 이런식으로 데이터가 반환된다. 이런 데이터가 넘어온다면 당황하지 말고 잘하고 있다고 판단하면 된다 :)

api 를 통해 받아온 값을 url 화 한다. URL.createObjectURL() 함수는 객체가 가르키는 URL을 반환하는 역할을 한다.

해당 URL은 이걸 생성한 document가 사라지면 사라진다!

{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } 이 값은 엑셀포멧에 맞는 값이다. 우린 엑셀을 다운로드 할 것이기에 해당 타입을 사용해준다.

 

try{
 const res = await excelFile(); // 엑셀 데이터 넘겨주는 함수
 const url = window.URL.createObjectURL(
  new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
 );
 
 const link = document.createElement('a');
 link.href = url;
 link.setAttribute('download', fileName);
 document.body.appendChild(link);
 link.click();
 document.body.removeChild(link);
}....

 

준비는 끝났고 다운로드만 해주면된다!

위에서 만든 url을 가상으로 만든 a 태그에 연결해주고

click()을 강제로 실행하여 다운로드 절차를 밟을 수 있다. 여기에 fileName을 추가하여 원하는 파일로 다운로드 받을 수 있게끔 할 수 있다.


 

이렇게 진행되고 엑셀 파일이 정상적으로 다운되더라도 파일이 열리지 않는 경우도 있다.

그건.. api 요청시에 타입을 제대로 지정해주지 않았을 확률이 있다.

아래 처럼 GET 인지, POST인지에 따라서 responseType을 꼬옥 추가or 확인해 보기를 추천한다.

 

// GET
export excelGETDownload = () => {
 const res = await api.get(
  '/execel/download',
  {responseType: 'blob'}
 )
}

// POST
export const excelPOSTDownload = (payload) => {
 const res = await api.post(
   '/execel/download',
   {...payload},
   {responseType: 'blob'}
 )
}

 

728x90
728x90

 

Nextjs로 

평소와 같은 작업을 하고 머지 후 빌드를 돌렸다.

그런데 로컬에서 나지 않던 문제가 갑자기 발생했다.

 

"Expected positive integer for height but received 0 of type number"

 

로컬에서는 잘만 나왔는데 갑자기 빌드에서 안된다라?  이 사실 자체가 두근거리게 한다 ^^; 

yarn run dev로 돌릴때는 문제 없었는데 로컬에서 빌드를 돌려도 위와같은 에러가 똑같이 발생했다.

 

에러문구는 새롭게 추가된 특정 이미지와 sharp 관련된 부분을 에러로 찍어내고 있었다.

뭔가 높이가 0이라고 하는것도 같은데...

 

 

이슈 : https://github.com/vercel/next.js/issues/40602

 

Error in next/image with high aspect ratio images · Issue #40602 · vercel/next.js

Verify canary release I verified that the issue exists in the latest Next.js canary release Provide environment information Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Ver...

github.com

 

 

원인

next js의 next-image-loader.js 의 에러 때문이었다.

특정 값(blurHeight) 계산할때 미세한 높이가 0으로 반올림이되는데,

이에 해당 이미지를 image/next 의 Image 태그로 사용하면 에러가 발생하게 됬던것이다.

(문제가된 나의 이미지 파일도 가로 길이는 400px인 반면에 높이는 9px도 되지 않았고, next의 Image 태그를 사용했다)

 

해결

현재 Next 특정 버전에서 문제가 발생하여 새로운 버전들에서는 문제가 되지 않는것 처럼 보인다.

다만 버전을 올릴수 없거나 하는 상황이면 어떻게 해야할까? (회사에선 거의 그러하다)

next-image-loader.js는 nextjs의 내부 파일이기 때문에 수정해서 관리하기는 껄끄럽다.

 

이럴땐,

넓이에 비해 너무 작은 이미지 사용을 피하거나, Image 태그 대신에 next-image-loader를 사용하지 않는 html 기본 img 태그를 사용하는것이다.

 

후자의 방법으로 수정하고나니 빌드에러에서 해방될 수 있었다!

디자이너님 이제 너무 얇고 긴 이미지는 안돼요!!!!!!!!!!!

 

 

 

728x90

+ Recent posts