Posts React) JS 다운로드 시간 동안의 로딩 화면
Post
Cancel

React) JS 다운로드 시간 동안의 로딩 화면

최근 프로젝트에서 리액트 앱을 배포하였는데, 인터넷 속도가 느린 환경에서 자바스크립트를 다운로드 받는 시간이 오래 걸린다는 걸 눈치챘다.

눈치챘다는 표현이 어울리는데 왜냐하면 사실 당연한 건데 이제까지 신경쓰지 않았던 부분이기 때문이다. 리액트앱은 매우 큰 자바스크립트 파일 하나로 이루어져있고, 이를 다운로드 받는 것은 당연히 오래 걸리는 일이기 때문이다.

따라서 이 시간 동안 단순한 로딩 화면이라도 띄울수있다면 사용자 경험을 향상 시킬 수 있을 것이라 생각되어 관련된 공부를 하게 되었다.

리액트 앱이 띄워지기까지

사용자가 우리의 앱에 접근하고, 리액트가 사용자 브라우저에 띄워지기까지 다음과 같은 과정을 거친다.

  1. 사용자는 주소창으로 우리의 앱에 접근한다.

  2. 서버는 index.html을 사용자에게 보낸다.
  3. 사용자의 브라우저는 index.html을 읽고, 필요한 파일들을 파악한 후, 서버로 요청한다.
  4. 서버는 필요한 파일들을 보낸다. 이때 리액트 번들 파일도 보낸다.
  5. 다운로드 된 번들 파일을 실행하여 리액트 앱을 띄운다.

이때 우리가 로딩 처리해줄 수 있는 순간은 바로 4번뿐이다. 1 ~ 3번은 우리가 처리할 수 없고, 네트워크과 브라우저에게 맡겨야하는 부분이기 때문이다. 5번에서는 각종 초기화 작업들이 이루어 질텐데, 이미 리액트 앱은 실행된 상태이므로 앱 안에서 로딩처리하면 될 일이다.

자, 그럼 4번을 어떻게 처리해야할까? 이 주제에 관해 얘기하기 전에 먼저 정말로 처리해줘야하는지 알아보자.

다음은 크롬 개발자 도구를 사용하여 보급형 휴대전화에서 필자의 프로젝트의 다운로드 속도를 측정한 것이다.

image-20220203032433794

  1. yourlist.me (2.16초) : 서버로 접근하고, 응답을 받기까지 걸린 시간
  2. www.yourlist.me(2.15초) : index.html을 요청하고 받는데까지 걸린 시간
  3. main.~~~.js(10.47초) : 리액트 js 번들파일

위 결과를 보면 알겠지만, 보급형 휴대전화를 사용하는 사용자는 리액트 앱이 실행되기까지 15초 가량이 걸리게 된다. 만약 그 시간동안 흰화면만 띄워지고 아무런 인터랙션도 없다면, 필자라면 그냥 그 사이트를 나갈 것이다. 이는 유저이탈을 불러일으켜 서비스 운영에 악영향을 끼치게 된다. 따라서 우리는 시간동안 무엇이든 띄워야한다.

JS 다운로드 시간동안 로딩 처리 방법

방법은 간단하다.

먼저 리액트 프로젝트를 만들면 생성되는 public/index.html 파일의 초기 상태는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="ko">
    <meta charset="utf-8" />
    <link rel="icon" type="image/png" href="%PUBLIC_URL%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>

    </head>
  <body>
    <div id="root"></div>
  </body>
</html>

여기서 리액트 앱은 body 안의 “root”라는 id를 가지는 div 안에서 실행되니, 우리는 그 밖에서 무언가를 작업하면 js 파일이 다운로드 받기 전에도 무언가를 띄울 수 있다는 것을 짐작할 수 있다.

따라서 필자는 다음과 같이 index.html을 작성하여 로딩 엘리먼트를 띄웠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="ko">
    <meta charset="utf-8" />
    <link rel="icon" type="image/png" href="%PUBLIC_URL%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
     <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>

    <!--
      index.html에 적용할 css 파일 import
    -->
    <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/index.css" />
    <style>
      /* css 파일을 연동하는 시간을 아끼기 위한 내부 스타일시트 선언*/
      #loadingElement {
        animation: 1s linear infinite rotateLoadingElement;
      }
      @keyframes rotateLoadingElement {
        from {
          transform:translate(-50%,-50%) rotate(0deg);
        }
        to {
          transform:translate(-50%,-50%) rotate(360deg);
        }
      }
    </style>
    </head>
  <body>
    <div id="root"></div>

    <!--
      번들을 다운로드 받는 동안, 아래 loading화면을 띄움
      css 파일을 연동하는 시간도 아끼기 위해 inline style도 사용함
      번들 다운로드 후, 내부 api 작업을 위한 로딩은 #root 안에서 해결
    -->
    <div id="loading">
        <img id="loadingElement" src="%PUBLIC_URL%/loading.png" style="position:absolute; width:100px; top:50%; left:50%;"/>
    </div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
/* index.css */
#root:not(:empty) ~ #loading {
  display: none;
}

#loading {
  background-color: #f9f9f9;
  width: 100vw;
  height: 100vh;
}
  1. root 엘리먼트 아래에 로딩 엘리먼트를 추가하여 번들 다운로드 중에도 화면에 로딩 엘리먼트를 띄웠다.
  2. css를 사용하여, root가 비어있을때만 로딩 엘리먼트를 띄우도록 했다. 따라서 리액트 앱이 실행되면 자동으로 로딩 엘리먼트는 사라지게 된다.
  3. 인라인 스타일과 인터널 스타일시트를 사용하여, css 파일을 다운로드 받는 시간조차 아꼈다.

그 결과가 다음과 같다.

adasd

index.html이 다운로드 받아지고, js 번들파일이 다운로드 되기 전까지 로딩 엘리먼트가 제대로 띄워짐을 알 수 있다. (이후 다른 로딩엘리먼트가 띄워지는데, 이는 리액트 앱 내부에서 렌더되는 것이다.)

이로써 유저는 번들 파일이 다운받아지는 시간동안 최소한 작업이 진행되고 있다는 것을 알 수 있어 조금이라도 더 기다리게 할 수 있다.

여기에 단순 로딩엘리먼트만이 아닌, 작업 안내 페이지를 띄운다면 더욱 효과가 클 것이다.

This post is licensed under CC BY 4.0 by the author.

2631 줄세우기

데이터베이스 개요

Comments powered by Disqus.