장경은
Study

[9장] 모던 리액트 개발 도구로 개발 및 배포 환경 구축하기

9.1 Next.js로 리액트 개발 환경 구축하기

  • tsconfig.json의 각 옵션 설명
  • next.config.js의 옵션 설명
  • 똑같은 설정을 매번 반복하지 않는 방법
    • 보일러플레이트 프로젝트를 만들어, 깃허브에서 Template repository 옵션을 체크해두는 것
    • create-next-app에서 한 발 더 나아가 나만의 create-***-app을 만드는 것

9.2 깃허브 100% 활용하기

  • 코드의 변화를 모으고 관리하는 코드 중앙 저장소에서, 여러 기여자가 기여한 코드를 지속적으로 빌드하고 테스트해 코드의 정합성을 확인하는 과정을 바로 CI라고 한다.
  • 깃허브 액션이란 깃허브를 둘러싼 다양한 이벤트를 기반으로 깃허브에서 제공하는 가상 환경에서 사용자가 원하는 작업을 수행할 수 있도록 도와주는 서비스다.
  • 깃허브 액션의 용어
    • 스텝들을 엮어서 잡을 만들고, 이러한 여러 개의 잡은 병렬로 실행되며, 이러한 잡을 하나 이상 모아둔 것을 액션이라고 한다. 그리고 이 액션을 실행하는 것이 러너다.
  • Lighthouse CI
    • Lighthouse CI는 구글에서 제공하는 액션으로, 9장에서 설명할 웹 성능 지표인 라이트하우스를 CI를 기반으로 실행할 수 있도록 도와주는 도구다.
  • Dependabot
    • 깃허브에서 제공하는 강력한 기능 중 하나는 Dependabot으로, 의존성에 문제가 있다면 이에 대해 문제를 알려주고 가능하다면 해결할 수 있는 풀 리퀘스트까지 열어준다.
    • Critical, High, Moderate, Low의 4단계로 분류하여 개별 취약점을 알려준다.

[참고] 유의적 버전(semantic versioning)

  • 버전은 주.부.수로 구성되어 있으며 각각의 정의는 다음과 같다.
  1. 기존 버전과 호환되지 않게 API가 바뀌면 주(主) 버전을 올린다.
  2. 기존 버전과 호환되면서 새로운 기능을 추가할 때는 부(部) 버전을 올린다.
  3. 기존 버전과 호환되면서 버그를 수정한 것이라면 수(修) 버전을 올린다.
  • (예시)

    • react@16.0.0: 버전 앞에 아무런 특수 기호가 없다면 정확히 해당 버전에 대해서만 의존하고 있다는 뜻이다.
    • react@^16.0.0: 16.0.0과 호환되는 버전을 의미한다. 호환된다는 뜻은 0보다 높은 부 버전에 대해서는 호환된다는 가정하에 상위 버전을 설치할 수 있다는 것을 뜻한다. 즉, 여기서 가능한 버전은 16.0.0부터 17.0.0 미만의 모든 버전이다. 단, 앞서 언급한 것처럼 주 버전이 0인 경우에는 부 버전이 올라가도 API에 변경이 있을 수 있으므로 수 버전까지만 수용한다.
    • react@~16.0.0: 패치 버전에 대해서만 호환되는 버전을 의미한다. 즉, 여기서 가능한 버전은 16.0.0부터 16.1.0 미만의 모든 버전이다. 기능이 추가되는 수 버전은 사용하지 않는다.
  • 유의적 버전은 어디까지나 개발자들 간의 약속일 뿐, 정말로 해당 API의 버전이 이 유의적 버전에 맞춰 구현돼 있는지는 알 수 없다.

[참고] 의존성

  • dependencies: 해당 프로젝트를 실행하는 데 꼭 필요한 패키지가 여기에 선언된다.

  • devDependencies: 해당 프로젝트를 실행하는 데는 필요하지 않지만 개발 단계에서 필요한 패키지들을 여기에 선언한다.

  • peerDependencies: 주로 서비스보다는 라이브러리와 패키지에서 자주 쓰이는 단위다. 이는 직접적으로 해당 패키지를 require하거나 import하지는 않지만 호환성으로 인해 필요한 경우를 의미한다.

  • 최근에는 애플리케이션 실행에 필요한 패키지를 구분하는 것에 의문을 제기하는 목소리도 있다.

    • 번들러의 존재로 devDependencies에 설치한 것이든 dependencies에 설피한 것이든 모두 node_modules에 동일하게 설치한다.
    • 개발 파이프라인이 복잡해짐에 따라 devDependencies에 설치된 것을 설치하지 않으면 빌드할 수 없는 경우가 많다.

정리

  • 의존성, 즉 dependencies와 node_modules의 크기가 커질수록 위협에 노출될 확률 또한 높아진다. 가능한 한 내재화할 수 있는 모듈은 내재화하고, 의존성을 최소한으로 유지하는 것이 좋다.
  • 아무리 사용자가 많다 하더라도 유지보수하는 주체가 없다면 점차 의존성 문제에 당면할 가능성이 크다. 패키지를 선택할 때는 얼마나 많은 사용자가 존재하고 얼마나 활발하게 유지보수되는지 살펴봐야 한다.

9.3 리액트 어플리케이션 배포하기

  • Netlify
  • Vercel
  • DigitalOcean
  • 만약 배포할 서비스가 개인적으로 운영하는 블로그이거나, 사용자가 크게 많지 않아 트래픽이 제한적인 서비스, 혹은 빠르게 배포해서 확인하고 싶은 MVP(Minimum Viable Product) 서비스라면 이러한 클라우드 서비스를 활용해서 배포하는 것을 추천한다.

9.4 리액트 애플리케이션 도커라이즈하기

  • 애플리케이션을 도커 이미지로 만드는 과정을 도커라이즈라고 한다.
  • 도커란 개발자가 모던 애플리케이션을 구축, 공유, 실행하는 것을 도와줄 수 있도록 설계된 플랫폼이다. 도커는 지루한 설정 과정을 대신해 주므로 코드를 작성하는 일에만 집중할 수 있다.
  • 도커 용어
    • 이미지: 도커에서 이미지란 컨테이너를 만드는 데 사용되는 템플릿을 의미한다. 이 이미지를 만들기 위해서는 Dockerfile이 필요하며, 이 파일을 빌드하면 이미지를 만들 수 있다.
    • 컨테이너: 도커의 이미지를 실행한 상태를 컨테이너라고 한다. 이 컨테이너가 바로 독립된 공간이며, 이미지가 목표하는 운영체제, 파일 시스템, 각종 자원 및 네트워크 등이 할당되어 실행될 수 있는 독립된 공간이 생성된다.
    • Dockerfile: 어떤 이미지 파일을 만들지 정의하는 파일이다. 이 파일을 빌드하면 이미지를 만들 수 있으며, 흔히 도커 이미지화한다(dockerize)라고 할 때 가장 먼저 하는 것이 바로 이 Dockerfile을 만드는 것이다.
    • 태그: 이미지를 식별할 수 있는 레이블 값을 의미한다. 일반적으로 이름:태그명 형태로 구성돼 있다. 대표적인 이미지인 ubuntu:latest를 예로 들면 ubuntu는 이미지 이름이고 latest는 태그명이다. 즉, ubuntu:latest는 ubuntu의 latest인 이미지를 의미한다.
    • 리포지터리: 이미지를 모아두는 저장소로, 앞서 언급했던 이름에 다양한 태그로 지정된 이미지가 모여있는 저장소다.
    • 레지스트리: 리포지터리에 접근할 수 있게 해주는 서비스를 의미한다. 대표적인 레지스트리로는 도커 허브(Docker Hub)가 있다. 이 레지스트리에는 다양한 리포지터리가 있으며, 이 리포지터리에서 사용자는 자신이 원하는 이미지를 내려받아 사용할 수 있다.

[참고]

  • next의 빌드 시 next/dist/server/next-server에서 NextServer를 꺼내온 다음, http.createServer로 만든 서버에 NextServer를 연동한다.
  • 이러한 점을 응용한다면 Koa나 Express 같은 웹 프레임워크에 Next.js를 올려 두고 실행해 별도의 Node.js 기반 서버를 운영하면서 동시에 Next.js도 서비스할 수 있을 것이다.