Chap23. 리액트앱 배포하기

Muru·2024년 4월 18일

[React] 지식 저장소

목록 보기
28/30
post-thumbnail

23.1 : 이번 단원에서는 무엇을 배우는가

지금까지는 리액트앱을 “로컬 환경”에서만 다루었다. 이번 단원에서는 “로컬 환경”이 아니라 실제 서버에 배포하여 다른 사람들이 볼 수 있게 하는 방법을 다룬다.

  1. 애플리케이션을 로컬환경에서 실제 서버로 옮기는 방법
  2. 배포 과정에서 거쳐야할 여러 단계들
  3. 있을 수 있는 어려움과 해결방법
  4. 서버측 라우팅 vs 클라이언트측 라우팅의 비교


23.2 : 배포 과정

  1. 애플리케이션을 배포하기 전 철저히 테스트
  2. 코드에 최적화 가능한 부분이 있는가? (지연 로딩이 가능한지)
  3. 프로덕션용 앱 빌드
    => 이미 작성된 스크립트를 실행하여 이 스크립트가 우리의 코드를 통합하고 자동으로 최적화하여 가능한 작은 크기의 프로덕션 레디패키지를 만들어줄것. 이렇게 만들어진 패키지를 서버로 옮기기
    해당 작업을 통해 가능한 최소한의 크기로 유저에게 최적화된 코드 패키지를 제공할 수 있다.
  4. 서버에 업로드하기 (with 호스팅 제공자의 제품을 설정)


23.3 : 지연 로딩

지연 로딩 : 특정 컴포넌트를 추후에 불러오는 기능

23.3.1 : 지연 로딩의 필요성

지연 로딩을 사용하지 않고 배포한다고 가정해보자.
A파일이있고 B,C를 import하고 있다고 할때 이 A파일은 B,C 파일을 모두 불러오고나서 화면에 무언가를 출력할 수 있다. 이렇듯 여러 코드가 상호 연결 관계를 가져서 최종 사용자에게 전달되기 이전에 모든 코드가 불러져 와야 한다.
여기서 이론적인 문제가 발생한다. 화면에 무언가를 띄우기 전에 모든 코드 파일이 불러와져야 한다는것이다. 물론 작은 애플리케이션에서는 문제가될 여지가 현저히 적지만, 더 복잡한 애플리케이션에서는 수십개또는 수백개의 컴포넌트가 있어서 문제가 될 여지가 있다.
초기에 모든 코드를 다운로드 한 후에야 화면에 무언가가 뜨는것을 볼 수 있다. 초기 로딩이 아주 느려지고 사용자 경험에 좋지않다.

그래서 필요한게 “지연 로딩”이다. 특정 컴포넌트를 나중에 불러온다. 미리 불러오는것이 아니라 필요할때 불러온다는것이다.

23.3.2 : 지연 로딩 추가하기

해당 페이지에서 "Blog 컴포넌트“ "Blog의 게시글”들에 지연 로딩을 적용하려고 한다.
대강 하는 방법은 함수를 적용하여 지연 로딩을 적용할 수 있다.
파일을 두고 주석처리 위주로 사용하는방법을 알아보자.

App.js

import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { lazy, Suspense } from "react";

// 지연로딩을 원하는 컴포넌트페이지의 import문을 삭제한다.
// * 참고로 loader도 당연하게 지연로딩 해주어야한다.(함수형태로)
// 삭제한 import문 => import BlogPage, { loader as postsLoader } from './pages/Blog';

import HomePage from "./pages/Home";

// 각각의 게시글에도 지연로딩을 적용시키자.
// 삭제한 import문 => import PostPage, { loader as postLoader } from "./pages/Post";

import RootLayout from "./pages/Root";






// BlogPage = () => import('./pages/Blog/'); 이런형태는 적절하지않다.
// 컴포넌트를 함수로 작성할수 있지만 함수가 유효한 컴포넌트가 되려면
// JSX 코드와 같은 형태를 반환해야하는데 이 함수는 프로미스를 반환한다.
// 그래서 react제공하는 lazy를 사용하여 동적으로 import하는문을 인자로 받는다.
const BlogPage = lazy(() => import("./pages/Blog"));
// 각각의 게시글에도 지연로딩 적용시키기
const PostPage = lazy(() => import("./pages/Post"));

const router = createBrowserRouter([
  {
   path: "/",
   element: <RootLayout />,
   children: [
    {
     index: true,
     element: <HomePage />,
    },
    {
     path: "posts",
     children: [
      // loader를 지연로딩하려면 함수를 할당하자
      // 함수를 할당하여 import키워드를 사용할수있다!
      // 동적으로 필요할때 만 import하게된다.
      // * import 함수는 프로미스를 반환한다. then을 붙일 수 있다.
      // * 전체 loader 함수가 결국 마지막의 loader()함수에 의해 프로미스를 반환한다.
      // * 전체 loader 함수가 호출될때만 import 함수가 실행이된다.
      // * 전체 loader 함수는 Blog 페이지를 방문할때 트리거 된다.
      {
       index: true,
       // 콘텐츠의 로딩을 기다리는데 사용 할 수 있는 <Suspense>
       // 즉 폴백 프로퍼티를 사용 할 수 있다.
       // 폴백 프로퍼티란 로딩하는동안 어떤 컨텐츠를 보여줄것인가?
       element: (
        <Suspense fallack={<p>로딩중...</p>}>
         <BlogPage />
        </Suspense>
       ),
       loader: () =>
        import("./pages/Blog").then((module) => module.loader()),
      },
      {
       path: ":id",
       // 게시글에도 지연로딩적용하기
       element: (
        <Suspense fallback={<p>로딩중..</p>}>
         <PostPage />
        </Suspense>
       ),
       loader: (meta) =>
        import("./pages/Post").then((module) => module.loader(meta)),
      },
     ],
    },
   ],
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

이렇게 적용시키고나서 지연로딩이 작동하고 있는지 보기위해서는 개발자툴로 들어가서 Blog 컴포넌트 또는 게시글로 이동할때 스크립트파일이 로딩되는지 확인하면 된다.

Blog 컴포넌트로 이동할때 스크립트 파일이 로딩되는것을 볼 수 있고,
게시글을 하나 클릭했을때 또한 스크립트 파일 하나가 로딩되는것을 볼 수 있다.


간단한 애플리케이션은 상관없지만, 복잡한 애플리케이션에는 필요한 기술이므로 잘 알아두자.



23.4 : 리액트 앱 배포하기

코드를 최적화 한뒤 두 단계만 거치면 배포단계는 끝난다.
1. 프로덕션용 앱을 빌드하고
2. 서버에 프로덕션 코드를 업로드

23.4.1 : 프로덕션용 앱 빌드

왜 우리가 만들고 있는 애플리케이션을 업로드하면 안되는걸까?
개발에 사용하는 코드이기 때문이다. 가독성이 좋고 브라우저에서 지원하지 않는 기능도 몇가지 사용하고 있는 코드이기 때문이다. 알기 쉽게 React의 JSX코드는 브라우저에서 지원하지 않는다.
즉 서버에 업로드하기 전에 최종 사용자가 쓸 수 있는 코드로 변환해야 한다.
사실 "npm start"를 통하여 "http://localhost:3000/"에서 미리 보여지는 웹페이지도 우리의 코드를 미리 변환해서 보여주는 것이다.

일단 코드를 업로드하려면 최적화가 필요하므로 개발 서버를 종료하고($ claer) 다른 스크립트를 실행한다.

npm run build

이 과정을 통해 업로드할 준비가 완료된 아주 최적화된 변화 코드 번들이 생성된다.
build 폴더가 생성되며 이 build 폴더의 내용물을 서버에 업로드하면 된다.

23.4.2 : 서버에 프로덕션 코드를 업로드

서버에 업로드하기전 알아두어야 할점은 리액트 SPA는 정적 웹사이트이다.
HTML, CSS, 자바스크립트,이미지파일들로만 구성되고 서버에서 실행되어야 하는 코드가 없다.
모든 코드가 브라우저에서 파싱되며 방문자의 컴퓨터에서 실행되는것이다. 서버에서 코드를 실행하는 호스팅 제공자를 사용하지 않아도 된다. 단! 풀스택 리액트 애플리케이션을 만들고자 한다면 얘기는 달라진다. 서버측에서 실행해야하는 코드가 필요하다면 당연하게도 그에 맞는 제공자를 사용해야 한다. 해당 섹션에서는 정적 웹사이트를 호스팅하기위해 Firebase를 사용하였다.

  • 오류해결
    Firebase에서 소개하는 과정을 따라가는 도중에 npm install -g firebase 을 실행했더니
    “Error: EPERM: operation not permitted”라는 문구가 나온다.
    VScode를 관리자권환으로 실행했더니 해결

FireBase에 업로드하는 과정에서 이러한 문구가 있다.

“? Configure as a single-page app (rewrite all urls to /index.html)? YES"

현재 우리는 여러 라우트간의 이동이 가능하다. 이는 리액트 라우터에서 제공하여 가능한것을 이해 해야 한다. 이 리액트 라우터 패키지는 서버에서 실행되는것이 아니라 브라우저에서 실행된다.
실제로 애플리케이션을 서버에 배포하고나서 사용자가 브라우저에 URL을 입력하면 기술적으로 브라우저는 서버에 요청을 보낸다. 만약 서버가 /posts 등 기타 웹사이트의 경로를 추가해 요청을 보냈다면, 요청에 따라 해당하는 경로가 서버에 전달되고, 요청한 경로에 해당하는 응답을 찾기 위해 노력한다.

하지만 지금의 경우는 서버에서 해당하는 파일을 찾는 대신 언제나 동일한 HTML 파일과 자바스크립트 코드를 반환해 요청한 경로를 자바스크립트 코드인 리액트앱의 리액트 라우터로 처리하도록 만들어야 한다. 즉 서버에서 어떠한 파일을 찾지 않게끔해야한다.

SPA를 사용하겠냐고 물어보고 YES라고 대답한다면 어떠한 경로의 요청이 오던지 index.html이 반환되도록 환경설정이 된다. 즉 언제나 동일한 자바스크립트 파일을 요청하게된다. 서버측 라우팅 대신 클라이언트 측 라우팅을 사용하도록 설정된 결과다.

fireBase는 일단 SPA로 설정할지 물어보았지만 다른 호스팅 제공자에서는 물어보지 않을 수 있고 이런 경우 index.html을 반환하도록 직접 리디렉션 규칙을 설정해주어야 한다.

FireBase를 통한 빌드가 성공적으로 완료되었다.


이러한 “클라이언트 측 라우팅”과 “서버 측 라우팅”의 차이를 알아보면서 해당 단원을 마친다.

profile
Developer

0개의 댓글