Intro
FE 개발시 소스 수정, 빌드, 브라우저 새로 고침의 작업은
별 것 아니지만 겁나 짜증나는 일이기도 합니다.리액트 개발환경에서는
webpack-dev-server
가
코드 변경을 감지(watch
)해서 webpack 재실행으로
트랜파일되고 브라우저가 자동으로 갱신됩니다.
(create-react-app을 기반으로 만들어도 들어가 있습니다.)
당시 상황
오피스텔에 인터넷이 없어서 건물에서 무료로 제공하는 와이파이에 기생중이었습니다.
그러다보니 너무 속도가 느려서 npm install 할때마다 짜증이 났었습니다.
(Acronis 트루이미지로 자주 복원을 하다보니 .. 자주 하게 되더군요)그런데 특이하게도 구글 드라이브와 도커허브 다운로드속도는 매우 빨랐습니다!
그래서 도커를 이용하기로 결심합니다~
구상
1 | FROM node:alpine |
- 처음에는 여기서 node_modules를 뺀 부분을
/usr/src/app
에 바인당하면 될거라고 생각했습니다.
어떻게?
- 그렇습니다. app 밑에 node_modules가 있지요.
- 이것은 두가지 방법이 있었습니다
-v /usr/src/app/node_modules
옵션- 일반적으로
-v <호스트 디렉터리>:<컨테이너 디렉터리>
형식으로 사용됩니다. - 위처럼 그냥 사용하면 컨테이너의 해당 디렉터리는
/var/lib/docker/vfs/dir/xxxx
로 매핑됩니다컨테이너 해당 디렉터리를 정확하기 위해서는 다음과 같이 하면 알 수 있습니다. 1
sudo docker inspect -f "{{ .Volumes }}" <컨테이너 name>
/usr/src/app
바인딩 전에 먼저 하면
node_modules 바인딩을 피할 수 있습니다
- 일반적으로
- .dockerignore
- .gitignore와 비슷한 역할을 하는 파일로 생각하시면 됩니다
- 여기에
node_modules/*
를 집어 넣으면
해당 폴더는 도커의 COPY에서 제외됩니다
나는 바보
- 이때 옆에서 보고 있던 한 사람이 말을 합니다
- “….왜그러고 있어..COPY를 안하면 되잖아??”
- 그렇습니다. 여러분은 바보 하나를 보고 계십니다.
1 | FROM node:alpine |
현재 폴더 바인딩
- sh이 되는 mac이나 리눅스에선
$(pwd)
로 현재 폴더값을 자동으로 넣을 수 있습니다. - 윈도우 환경에선
%CD%
환경변수로 바인딩이 가능합니다.
핫로딩이 안될때의 간단 해결법
멋지게 실행해 봅니다
멋지게..멋지게.. 1
docker run --rm -it -p 3000:3000 -v /usr/src/app/node_modules -v %cd%:/usr/src/app rkaehdaos/react1:latest
정상적으로 리액트 앱이 보입니다.
문제는 로컬에서 소스를 고쳐도 반응이 없습니다. 핫로딩이 안되요 !!
브라우저를 새로 고침해도 마찬가지입니다.핫로딩이 안되다니.. 혹시나 bind가 잘못되었나 하고
컨테이너에 exec로 들어가서 확인해도 제대로 된게 맞네요이떄 희망이 되는 글을 발견하게 됩니다.
Finally, -e CHOKIDAR_USEPOLLING=true enables a polling mechanism via chokidar (which wraps fs.watch, fs.watchFile, and fsevents) so that hot-reloading will work.
chokidar 모듈은
WebPack
과Babel
이 파일들을 모니터링을 하기 위해 사용하는 모듈로
create-react-app에도 포함되어있는 모듈입니다.도커에서 해당 모듈의 polling을 사용하기 위해
CHOKIDAR_USEPOLLING=true
설정을 해주어야합니다.run 하면서
-e CHOKIDAR_USEPOLLING=true
를 하거나
Dockerfile
안에ENV
로 환경변수로 세팅하는 것도 가능합니다.이렇게 하면 핫로딩이 훌륭하게 잘 작동하는 것을 알 수 있습니다.
쓸데없는 디테일하게 들어가기
chokidar?
A neat wrapper around Node.js fs.watch / fs.watchFile / FSEvents.
VSCODE, gulp, webpack등 많은 곳에서 사용 되고 있습니다.
MacOS상에서 Darwin FSEvents API 확장 구현체가 사용되며,
매우 효율적인 watch 효율을 보여준다고 합니다.MacOS 외의 플랫폼에서는 fs.watch 기반 구현체가 기본값인데,
polling을 최대한 피해서 cpu 부하를 낮추는 구현을 갖추고 있습니다.그래서
usePolling
기본값이 MacOS에선 true이고, 나머지는 false입니다.
[참조 레퍼런스]네트워크를 통한 파일 watch를 성공하기 위해선 이 값이 true여야 합니다
도커에서 돌렸는데 네트워크라고??
linux와 달리 Mac/Win 환경의 도커는 무조건 VM위에서 돌아갑니다(WSL등을 쓰던 말던)
일반적인 가상머신과 마찬가지로, 도커 호스트가 돌아가는 VM의
Shared Folder
를 통해
호스트의 디렉토리를 접근하고bind mount
하는 것입니다.이러한 구조
[Mac/Win OS => Docker Host VM => Docker Container]
안에서의
파일 시스템 변경 감지는 사실상 네트워크 위의 파일 watch입니다.따라서 위에서 말한
usePolling
값이 true여야하며 기본값을 overriding하기 위해CHOKIDAR_USEPOLLING
환경변수를 set하는 것입니다.Mac/Win OS가 아닌 linux Native OS에서의 도커 환경에서는
네트워크를 통한 bind가 아니기 때문에 polling이 없어도
위와 같은 문제가 위 문제가 발생하지 않습니다.Reference
https://daten-und-bass.io/blog/enabling-hot-reloading-with-vuejs-and-vue-cli-in-docker
https://create-react-app.dev/docs/troubleshooting/#npm-start-doesn-t-detect-changes