[트러블슈팅] WebSocket connection to `'${web url}'` failed

Chaejung·2023년 12월 7일
0
post-thumbnail

개요

CRA로 만든 프로젝트를 배포한 뒤 이것저것 확인하고 있었다.
그 와중에 배포된 링크에서 다음과 같은 warning console이 떴었다.

바로 위 [API] GET /my-page/edit/user-info | Response 200은 api 호출 후 발생하는 console이기 때문에 프론트, 백 둘 다 정상 작동하는 것을 의미한다.

따라서 기능 상의 문제는 없었기에 해결을 해야하는 것인가 싶었지만,
그래도 프로덕션 단계에서 console은 깨끗하게 비워야하고,
왜 발생한 에러인지 정리하기 위해 포스트를 작성하게 되었다.

참고 설계

참고로 해당 에러가 발생한 설계는 아래 다이어그램과 같다.
React는 CRA로 초기세팅을 했고, 배포는 Azure의 PaaS 중 하나인 App Service를 이용했다.

원인

범인은 누구...?

현재 프로젝트에서 web socket을 쓰지 않고, 직접 설정한 게 없으므로 web socket 문제는 아니다.
그래서 에러 console을 그대로 복사해서 검색했더니 이런 포스팅이 있었다.

webpack? 이것도 별도로 설정한 게 없는데? webpack.config.js가 도대체 어딨지?

그것은... CRA가 숨겼습니다!

도.. 돌려줘요...!

CRA(Create React App)는 단순히 React 전용 프로젝트 초기세팅 툴 정도로만 생각하고 있었는데, 오직 기능 중심의 코드를 작성하는 데에 집중시켜주기 위해
기본 세팅을 전부 시켜주는 기능을 하고 있었다.

Create React App is an officially supported way to create single-page React applications. It offers a modern build setup with no configuration.
.
Create React App은 React SPA를 만드는데 공식적으로 지원하고 있는 방법입니다. 별도의 설정 없이 모던 빌드 셋업을 할 수 있습니다.
출처: getting-started / create-react-app.dev/docs

여러 기본 세팅 중에서는,
jsx 문법을 브라우저가 이해할 수 있는 JavaScript로 바꿔주기 위해 필요한
transpiler, bundler가 있다.

여기서 bundler에 해당하는 것이 바로 webpack인 것이다

어떤 걸 더 숨겼는지 알고 싶으면 참고: Inside create-react-app - medium

webpack?

At its core, webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph from one or more entry points and then combines every module your project needs into one or more bundles, which are static assets to serve your content from.
.
webpack은 모던 JavaScript 애플리케이션을 위한 정적 모듈 번들러입니다. webpack이 애플리케이션을 처리할 때, 내부적으로 의존성 그래프를 빌드합니다. 빌드는 하나 또는 다수의 시작점에서 프로젝트에서 필요한 모든 모듈을 결합시켜 하나 또는 다수의 번들로 만듭니다. 해당 번들은 애플리케이션 콘텐츠를 제공하는 정적 에셋입니다.
출처

그렇다. 지금껏 자세히 살펴보지 못했지만 사실 이 친구는 웹 애플리케이션을 브라우저에 띄울 때 코드베이스의 애플리케이션을 적절히 처리해서 올려주는 친구인 것이다.

webpack을 쓰지 않고 다수의 JavaScript 파일을 배포하려면, 파일 간에 얽혀있는 의존성때문에 선언되는 순서를 신경쓰면서 관리를 해야하는 어려움이 있다.

아무튼 배포를 어렵지 않게 하려고 만든 webpack에서 왜 이런 오류가 발생하는 것일까?

CRA와 webpack-dev-server

webpack의 여러 설정 중에서는 개발 단계에서 활용할 수 있는 webpack-dev-server가 있다.
간단한 웹 서버와 실시간 다시 로딩 기능을 제공하는 기능을 가지고 있다.
출처: using-webpack-dev-server - webpack.js.org/guides

개발 단계에서 브라우저에서 변경된 파일이 있는지 확인하려고 다시 로드할 때,
webpack이 web socket을 쓰며 현재 작동 중인 프론트 웹 서버를 향해 정보를 가져오게 된다.

그리고 CRA는 이러한 설정을 기본적으로 다음과 같이 가져간다.

출처: advanced-configuration / reate-react-app.dev/docs

일반적으로 webpack-dev-serverwindow.location.hostname, /ws, window.location.port로 각각 socketjs의 host name, path name, port를 지정합니다.

그래서 배포된 상태의 web url을 향해 web socket을 열어 통신하려는 것이고,
실제 배포된 애플리케이션의 환경에서 web socket에 대한 허용이 되지 않았으면 해당 에러가 발생하는 것이다.

또는 원래는 실행 환경이 development에서만 실행되어야 하는webpack-dev-server이므로
배포된 환경의 실행 환경 설정이 production인지, development가 아닌지 확인할 필요가 있다.

해결 방법

1. webpack.config를 직접 수정

CRA에서 손수 짜주고 숨겨둔 webpack 설정을 다시 끄집어 내서 직접 수정하면 된다.
webpack.config는 npm run eject를 사용해서 밖으로 드러나게 할 수 있다.
그런데 다음과 같은 이유로 npm run eject로 실행하여 하는 것은 비추천한다.

🚨 주의: npm run eject한 이후로는 이전 상태로 돌아갈 수 없다.

따라서 미리 사용자화하여 설정한 webpack이 있으면 해당 설정 파일에서 코드를 수정하면 되고,
그게 아니라면 다음과 같은 절차를 따라 수정하면 된다.

짜란!

여기서 직접 수정할 파일은 webpack.config.js가 아니라 webpackDevServer.config.js다.

  • as is

  • to be

참고 및 추가 자료: Create-React-App의 Webpack 기본 설정 살펴보기 - 김맥스 블로그
참고: react Websocket connection failed (webpack) 문제해결 - MinHye_laura.log

그런데 아무래도 npm run eject는 권장되는 스크립트도 아니거니와 코드 폴더에 무언가가 많아진 게 마음에 들지 않는다.

그래서 밤새 이것저것 찾아보고 다른 방법은 없는지 확인해보았는데 그 방법은 다음과 같다.

2. .env 설정

webpack-dev-server를 찾아보면서 어떤 의문점이 커져갔다.

분명히 개발 단계에서만 실행되는 기능인데, 왜 배포된 링크의 console에서 해당 오류가 찍히는 걸까?
그리고 내가 임의로 설정한 api console 또한 실행 환경이 development에서만 작동하도록 되어있는데 왜 찍히는 걸까?

그것은 배포 시 어떤 스크립트가 실행되고, 실행 환경이 어떻게 정해지는지 알았다면
너무나 당연한 사실이었다.

There is also a built-in environment variable called NODE_ENV. You can read it from process.env.NODE_ENV. When you run npm start, it is always equal to 'development', when you run npm test it is always equal to 'test', and when you run npm run build to make a production bundle, it is always equal to 'production'. You cannot override NODE_ENV manually. This prevents developers from accidentally deploying a slow development build to production.
.
process.env.NODE_ENV로 읽을 수 있는 빌트인 환경 변수 NODE_ENV가 있습니다. 해당 환경 변수는 npm start를 하면 development로, npm test를 하면 test로, npm run build를 하면 production으로 설정됩니다. 느린 개발 빌드를 실수로 프로덕션에 배포하는 것을 방지하기 위해 수동으로 NODE_ENV를 재정의할 수 없습니다.
출처: Adding Custom Environment Variables - create-react-app.dev/docs

이런...!
현재 App Service는 npm start로 동작하고 있기에
그래서 현재 NODE_ENVdevelopment으로 적용이 되고 있었던 것이다.

App Service + CRA + npm run bulid

내가 몇 일 밤을 샌 원인...

아직도 확실한 원인은 파악하지 못했으나 시작 명령으로 npm run build를 할 수 없기에 우회하는 방법이 필요했다.

CRA에서 쓸 수 있는 환경 변수 중에서 webpack-dev-server과 관련된 것을 위의 방법에서 설정한 것처럼 적용하면 될 것 같았다.

.env에 다음을 추가해보았다.

// .env
WDS_SOCKET_HOST = 0.0.0.0
WDS_SOCKET_PATH = /ws
WDS_SOCKET_PORT = 443

✅ 된다!

3. 시작 명령어 설정

지금 여기서 적용한 방법은 아니지만 만약 할 수 있다면 이런 방법으로도 해결이 가능할 것이다.

배포 시작 명령어를 npm start가 아닌 npm run build로 설정

이렇게 되면 React에서 NODE_ENVproduction이 될 것이고,
production에서는 webpack-dev-server가 작동하지 않을 것이니
해결할 수 있을 것이다.

느낀 점

Azure App Service의 장단점

현재 Azure App Service에 프론트, 백 애플리케이션을 배포하고 있는데,
너무 오래 걸린다. (클라우드 컴퓨팅은 빠른 게 장점이라매!)
언제는 배포때문에 이것저것 테스트하느라고 오전 5시에 잔 적도 있다.

github action을 통해서 CI/CD도 구축했지만 build error나 deploy error가 뜨기 일쑤다.

그래서 VSCode의 extension으로 직접 배포하고 있다.
이건 좀 편한 것 같다. 배포된 File도 직접 확인할 수 있다.

그런데 그것말고는 장점은 모르겠다.
가격도 비교하자면 AWS의 Amplify에 비해서 더 많이 나오는 것 같다.
Application Error가 나는 경우는 배포가 안되는 원인도 파악하기 정말 어려웠다.

시간이 되면 이번 프로젝트 마무리 이후 가격을 비교해보면 좋을 것 같다.

공부할 게 산더미

그리고 난 아직 아는 게 없다...!
다음에는 babel 설정을 직접 해보거나 webpack의 다른 설정에 관해서 좀 더 공부하고 싶다.
단순히 동작만 하면 되는 것을 넘어서서 동작 원리를 파악하는 게 중요하다.

공식문서 정독

사실 이 글이 완성되기 전 NODE_ENV를 환경 변수로 추가하는 방법을 시도하고 있었는데,
만약 CRA의 문서를 제대로 읽었더라면 애초에 시도조차 하지 않았을 바보같은 행동이었다.

그래서 부랴부랴 공개해놨던 것을 비공개로 돌려 수정하고 다시 포스팅한다.

왜를 파고들어 결국 끝에 닿는 것은 공식문서였다.

지금 쓸 줄 안다고 생각하는 기술들도 공식문서를 파헤쳐보는 시간이 필요하다.

profile
프론트엔드 기술 학습 및 공유를 활발하게 하기 위해 노력합니다.

0개의 댓글

관련 채용 정보