티스토리 뷰

아주 간단하게 만든 'Quick News' 프로젝트를 배포하고 싶었다.

Next JS로 구현했고, 이를 쉽게 배포할 수 있는 방법 중 하나가 'Vercel'이라는 것은 강의를 통해 알고 있었다.

배포한 적은 있었지만, 강의를 따라서 해봤을 뿐, 직접 처음부터 스스로 해본 적은 없었다. (다른 서비스를 이용한 적은 있었다)

그래서 "이번에 한 번 배포해보자"라는 생각으로 시도했다.

 

그런데, 에러가 발생했다.

 

"도대체 에러가 몇 개야.."

 

첫 번째 에러, ESLint 에러

error - ESLint: Failed to load config "airbnb-typescript" to extend from. Referenced from: /vercel/path0/quick-news/.eslintrc.json

 

위 에러를 찾아보니, "airbnb-typescript를 설치해야 하는 것이었다. 그래서 npx를 활용해 설치를 진행했다. 그런데 또 에러가 발생했다.

 

error - ESLint: Plugin "react-hooks" was conflicted between ".eslintrc.json" and ".eslintrc.json » eslint-config-next/core-web-vitals » /vercel/path0/quick-news/node_modules/eslint-config-next/index.js » plugin:react-hooks/recommended".

 

위의 에러를 찾아보니, ".eslintrc.json"파일에 "react-hooks" 플러그인을 포함하지 않아서 발생한 문제였다. 그리고 "rules"에 관련 규칙을 설정해야 한다는 것을 알게 되었다. 그래서 다음과 같이 ".eslintrc.json"파일에 "react-hooks" 라이브러리를 포함시키고 다시 배포를 시도했더니, 위의 문제를 해결되었다.

 

"plugins": ["@typescript-eslint", "prettier", "react-hooks"],

"rules": {
    ...,
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }

 

두 번째 에러, 모듈을 찾을 수가 없다고?

그 다음 문제는, 특정 컴포넌트의 모듈을 찾을 수 없다고 나온다. 구글 검색을 해보니, 로컬 저장소. 즉, 내 컴퓨터에 저장된 컴포넌트의 파일명과 원격 저장소(Git)에 저장되어 있는 파일명이 달라서 발생한 것이라고 한다.

 

Type error: Cannot find module '../page/loading' or its corresponding type declarations.

 

"그런데? 로컬 저장소와 원격 저장소의 파일명은 같은데? 도대체 왜 에러가 나는거지?"

 

구글 검색만 계속 하다가 Chat GPT에게 물어보니 바로 정답을 알려주었다.

대부분의 파일 시스템은 대소문자를 구분한다. 위의 에러에서는 'loading' 파일을 찾지 못하는 문제였다.

 

"아니, 내 로컬 저장소에도, 원격 저장소에도 Loading.tsx로 잘 되어 있는데?"

 

그렇다. 저장소에는 'Loading'으로 대문자로 저장이 되어 있었고, 오류 메시지에는 'loading'으로 소문자로 나와 있었다.

로컬 환경의 파일명과 원격 저장소의 파일명이 같아야 해결이 되는 문제였다.

 

Map의 index 값을 사용하지 못해?

Do not use Array index in keys

'map()'를 사용하다보면, index 값을 사용할 때가 있다. 바로 key 값을 위해서 말이다. 그런데 eslint를 사용하니 index 값을 사용하지 한다는 에러가 발생했다.

 

index 값을 사용하면 항상 key 값이 고유하지 않을 수 있기 때문에 발생한 문제였다.

 

그렇다면, 어떻게 해결해야 할까?

고유의 값을 사용할 수 있는 'uuid'를 설치해 key 값에 부여해 문제를 해결했다.

 

아! 그리고 React 컴포넌트를 사용할 때는 다음과 같이 사용해야 에러를 해결할 수 있다.

// 문제
<>
  <div>{f.format(today)}</div>
</>

// 수정
<div>{f.format(today)}</div>

 

문제되는 eslint 규칙들을 'off'하자

코드를 작성하다보면, eslint 규칙에 위반된다는 에러가 발생할 때가 있다.

내가 사용하고 싶은 코드 작성 방식이 있는데, 그 방식들을 정해진 규칙때문에 사용할 수 없게 된다.

그래서 그 규칙들을 꺼주고 싶을 때, 'eslintrc.json' 파일의 코드를 수정해야 한다.

 

나는 props 규칙, export 규칙들을 꺼주었다.

"rules": {
    "react/jsx-props-no-spreading": "off"
    "import/prefer-default-export": "off"
}

 

pages 폴더에 포함되어야 할 파일과 아닌 파일들

배포 과정에서 가장 많은 시간이 소요됐던 에러였다.

나는 인터페이스, 타입, 상수, Recoil 등 공통적으로 사용될 파일들을 'pages' 폴더 내에 'constants' 폴더에 저장하고 있었다.

그런데, 배포를 하고 나니 다음과 같은 에러가 발생하였다.

Build optimization failed: found pages without a React Component as default export in
pages/constants/interfaces
pages/constants/pageSizeAtom
pages/constants/types
pages/constants/variable

무슨 문제인가 여러 번 찾아보고 폴더의 위치를 변경도 해보고, pages 폴더와 같은 위치에 'utils' 폴더를 생성하고 파일들을 'utils' 폴더로 옮겼다.

'export default'를 하지 않은 파일들은 'export default'로 수정하여 내보내기를 시도했다.

 

그럼에도 불구하고 이 에러는 해결되지 않았다. 그래서 다시 원상복구를 시켰더니, 에러도 그대로 원상복구!

 

나중에 알고보니, 내가 에러를 제대로 읽지 않았던 것이다. 정말 최악의 습관인데 내가 그걸 가지고 있었다.

에러를 그대로 읽어보면 쉽게 이해할 수 있듯이, React 컴포넌트가 아닌 파일들은 'pages' 폴더에서 사용할 수 없다는 것이었다.

 

즉, 다음과 구조가 아닌 경우에는 'pages' 폴더에 위치할 수 없다는 것을 늦게 알아차렸다.

function a() {
	...
    
    return (
    	<div>
        	...
        </div>
    )
}

export default a

 

에러가 발생한 4개의 파일들은 React 컴포넌트 형식이 아닌, ts 파일 형식으로 되어 있는 데이터를 내보내는 형식이었기 때문에 에러가 발생한 것이었다.

 

그래서 'pages' 폴더와 같은 위치에 'interfaces' 폴더, 'types' 폴더, 'contants' 폴더를 생성하였고, 'interfaces' 폴더에는 인터페이스 선언 파일을, 'types' 폴더에는 타입 선언 파일을, 'contants' 폴더에는 상수 선언과 Recoil Atom 파일을 옮겼다.

 

그랬더니, 위의 문제가 해결되었다.

 

그런데, 'GeoLocation' 값을 가져오는 파일에 대한 에러가 발생하였다.

Error occurred prerendering page "/components/info/GetGeoLocation". Read more: https://nextjs.org/docs/messages/prerender-error

위에서 발생한 4개의 파일의 에러와 전혀 달라서 다른 문제인 줄 알았다.

그러나, 에러 메시지만 다를 뿐, 결과적으로 'GetGeoLocation' 파일이 'pages' 폴더 내에 위치해서 발생한 에러였다.

왜냐하면, 'GetGeoLocation' 파일도 React 컴포넌트 형식이 아닌 위도와 경도 값만 내보내는 파일이었기 때문이다.

그래서 'GetGeoLocation' 파일도 'constants' 폴더로 이동시켰고 해당 문제를 해결할 수 있었다.

 

dangerouslySetInnerHTML 문제

네이버 검색을 이용해서 뉴스 데이터를 가져오는 파일에서 해당 문제가 발생했다.아무래도 네이버 검색을 이용해서 뉴스 데이터를 가져오면 HTML 태그가 그대로 출력되어 사용자가 보기에는 좋지 않다.그래서 'dangerouslySetInnerHTML'를 사용해서 HTML 태그를 제거하였다.그런데, 'eslint' 규칙에서는 dangerouslySetInnerHTML는 사용면에서도 보안면에서도 안전하지 않기 때문에 에러로 처리하지는 않지만, 사용의 위험성이 있다는 경고를 전달했다.

 

그래서 다른 방법이 있는지 찾아보았지만, HTML 태그를 제거한 채 출력하는 방법을 찾지 못했다.결국, 경고를 무시한 채 'dangerouslySetInnerHTML'를 사용하고 있다.

 

Vercel 배포 시, .env.local 파일에 저장한 Key 값을 정상적으로 가져오지 못하는 문제위의 문제들을 모두 해결하고 나서 배포까지 성공했지만, 날씨 데이터, 뉴스 데이터를 가져오지 못한 채 에러가 발생했다.

process.env.NEXT_PUBLIC_WEATHER_KEY
...

위 처럼, 보안을 위해 '.env.local'에 저장한 Key 값들을 Vercel에서 가져오지 못하는 문제였다.

그 이유는, '.env.local'은 단어 그대로 로컬 환경에서만 사용할 수 있기 때문이다.

 

그렇다면 어떻게 해결해야 할까?

Key 값 가져오기

방법은 생각보다 단순했다. Vercel에서 배포한 프로젝트에 들어가서 'Setting' 메뉴로 들어가 'Environment Variables'로 들어간다. 그리고 Import 버튼을 눌러서 '.env.local' 파일을 찾아 추가하면 자동으로 내가 작성한 모든 key 값이 저장이 된다.

 

그리고 나서 다시 배포한 주소로 들어가면 해당 문제가 해결된 것을 확인할 수 있었다.

 

결과

결론은, 배포는 성공하였다.

배포는 성공

그러나, 뉴스 데이터를 가져오는 API 들은 무료로 사용할 경우, 로컬 환경에서는 사용이 가능하나, 'Production' 상태 즉, 배포할 경우에는 API로 데이터를 가져올 수 없기 때문에 배포 환경에서는 뉴스 데이터를 출력할 수 없게 됐다.

그렇지만, 많은 문제를 겪었고, 그리고 해결했고 결국에는 배포까지 성공해서 많은 배움을 얻었고 좋은 경험을 했다.