그냥 웃겨서..

 

vite + yarn berry + react 프로젝트를 aws amplify로 배포하는 과정에서 일어난 몇몇 슬플 뻔한 사건을 기록해보려고 한다. 몇 시간동안 고생했는데 미래의 나는 덜 고생하길 바라면서..

아 그 전에 amplify 이용 후기부터 적어보자면, 이번에 처음 써봤는데 ec2에 비해서 훠어얼씬 간단하고 배포 자동화도 디폴트로 지원해줘서 너무 편리했다. 편리한만큼 ec2로 배포하는 것보다 자유도가 떨어진다고 하는데 지금 프로젝트에선 amplify에서 제공해주는 기능들로도 충분해서 딱히 답답하진 않았다.

배포할 때 참고했던 블로그: React AWS amplify에 배포 
 

React AWS amplify에 배포

React로 만들어진 프로젝트를 AWS amplify를 통해서 배포해보겠습니다.이해를 돕기위해서 사진을 많이 첨부했지만 3분안에 기본셋팅이 가능합니다.(프로젝트빌드, 및 도메인 / SSL 연결 시간 제외)사

velog.io

*참고로 빌드 설정 구성에서 artifacts의 baseDirectory 값으로 dist를 써줬다. vite 기본 설정(vite.config.ts)에서 outDir 값이랑 동일한 값을 써주면 된다.

 

이렇게 해서 배포는 정상적으로 됐는데, 다음과 같이 배포 이후에 문제가 되는 부분들이 좀 있었다.

 

404 에러

증상

사이트의 메인 페이지가 아닌 다른 페이지(예: /mypage)에서 새로고침을 할 경우, 콘솔창에 해당 페이지를 찾을 수 없다는 404 에러가 떠있음. 하지만 페이지는 불러와서 보여지기는 함.

원인

스택오버플로우에서 본 글의 코멘트에 따르면, :

React App에는 SPA(Single Page App) 자체 라우팅이 있으며 AWS 측에서는 기본 경로를 제외한 다른 모든 경로가 서버 측에 없기 때문에 404를 반환합니다. amplify에서 index.html로 리다이렉트 설정을 해두면, react router가 라우팅을 처리합니다.

 

라고 한다.

해결 방법

  • aws amplify 콘솔에서, 좌측 메뉴 중 '다시 쓰기 및 리디렉션(Rewrites and redirects)' 클릭

  • '편집' 클릭
  • '규칙 추가' 클릭 후, 새로 추가된 행에 아래 이미지에서 빨간 네모 친 부분과 같이 입력하기
    • '소스 주소' 칸에는 다음 값 복사 후 붙여넣기: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

 

TS2307: Cannot find module

증상

특정 컴포넌트에 대해서만 Cannot find module 에러가 발생하며 빌드 실패함.

원인

처음에 단순히 path alias 때문인가 싶었는데 다른 컴포넌트에선 문제가 없고 이쪽에서만 문제가 발생하는 걸 보면 그건 아닌 거 같았음. export/import를 잘못했나 해서 다른 방식으로 해봤는데도 동일; 도무지 뭐가 문제인지 못찾겠어서 한참 구글링하다가 마침내 답을 발견....

갓Leon님 ㄷㄷ

(출처: https://stackoverflow.com/questions/71598801/amplify-react-build-fail-with-module-not-found-error-cant-resolve-compone)

이 분이 달아주신 답변과 정확히 동일한 상황이었다. 원래 components/layout/Nav 디렉토리가 있었는데 작업하면서 Nav를 소문자로 쓰는 게 더 적합한 것 같아 components/layout/nav로 바꿨다. 그.런.데 깃에는 이게 변경사항으로 안 잡혔나보다. 이 글 보고 혹시나 해서 origin 레포 가서 디렉토리명을 확인해보니 소름돋게도 아직까지 components/layout/Nav였던 것.. 디렉토리명 대소문자를 구분 안 하는 것 같다; 로컬에는 nav로 잘 변경되어있는 상태였어서 왜 amplify에서 저렇게 에러가 나는지 알 수 없었던 것이다 ㅠ

마음 같아선 답변 작성자 Leon님에게 추천 200개 드리고 싶은..

해결 방법

origin 레포의 components/layout/Nav를 로컬과 동일하게 components/layout/nav로 수정하기 위해 다음과 같이 진행:

1. 로컬에서 components/layout/nav를 임시로 components/layout/temp로 변경 후 git add, commit, push

2. components/layout/temp를 다시 components/layout/nav로 변경한 뒤 git add, commit, push

(관련 커밋)

 

duplicate dependencies issues

증상

다이얼로그 컴포넌트를 띄우려고 할 때 다음과 같은 에러 발생(개발 환경이나 로컬에서 빌드 후 빌드 파일 실행할 때는 발생X)

  • Material UI Dialog 컴포넌트 사용했을 때: TypeError: Cannot read properties of null (reading 'useContext')

  • 다이얼로그 패키지를 react-responsive-modal로 변경했을 때: TypeError: Cannot read properties of null (reading 'useState')

원인

일단 패키지 매니저랑 관련이 있을 것 같다는 킹리적 갓심이 들었다. 다이얼로그 라이브러리 자체의 의존성이랑 우리 프로젝트의 의존성이랑 버전이 맞지 않아서 발생하는 문제인 것 같았는데, 로컬에서는 dev server 및 빌드 파일 실행할 때 모두 이 에러가 발생하지 않는 걸로 봐서 아무래도 yarn 버전이랑 관련이 있는 것 같았다. yarn berry 쓰면서 3.4.1 버전으로 프로젝트 내의 패키지를 관리하고 있는데, amplify는 다음과 같이 yarn v1.22.0로 패키지를 설치하고 있었다.

그래서 빌드 설정에서 preBuild 쪽 명령어도 다음과 같이 추가해주고,

빌드 이미지 설정(Build image settings)에서도 다음과 같이 yarn 버전을 지정해줬는데..

그래도 amplify는 계속 고집스럽게 yarn v1.22.0를 사용했다 ㅠ yarn 버전 설정하는 방법이 따로 있나? 모르겠는데 아무튼 이렇게 yarn 버전 맞춰주는 방법은 포기했다. 그리고 원인도 확실하지는 않아서 좀 더 서치를 해봤다.

React 버전이 여러 개일 경우에 발생할 수 있다고 하는 글을 찾았다. 여기서 힌트를 얻고 관련된 해결 방법을 찾아보다가, 또 다른 스택오버플로우 질문에 달린 댓글을 통해 짐작가는 원인을 찾았다. 프로젝트에서 사용하는 패키지(다이얼로그 관련 패키지인 MUI Dialog, react-responsive-modal 쪽에서 문제가 발생하는 듯 하다.)가 프로젝트와 동일한 React 인스턴스를 쓰는 게 아니라 자기자신의 의존성 목록에 있는 React 인스턴스를 써버려서 그렇다고 한다. (참고: How to fix NPM link duplicate dependencies issues)

 

해결 방법

문제를 일으키는 패키지가 프로젝트와 동일한 React 인스턴스를 사용하도록 하려면 다음과 같이 vite resolve.alias 설정을 추가해줘야 한다. 이렇게 함으로써 React 버전이 여러 개일 경우에 대한 문제도 해결할 수 있다고 한다.

// vite.config.ts

return {
    plugins: [
      tsconfigPaths(),
      react({
        jsxImportSource: "@emotion/react",
        babel: {
          plugins: [ "@emotion/babel-plugin" ],
        },
      }),
      mkcert(),
    ],
    optimizeDeps: {
      disabled: false,
    },

    base: "/",
    publicDir: "./public",

    server: serverOptions,
    build: buildOptions,
    preview: {
      port: 3000,
    },

    // 🙋🏻‍♀️ 이 부분!
    resolve: {
      alias: {
        react: path.resolve("./node_modules/react"),
      },
    },
};

 

복사했습니다!