Front-End/성능개선

[웹 성능 최적화] - bundle 파일 분석, 텍스트 압축(2/3)

딸기케잌🍓 2023. 2. 8. 12:37

bundle 파일 분석

JS 코드를 다운 받는데 용량이 너무 크다면 (990KB 사이즈를 크다고 보셨음) bundle analyzer 툴을 활용하여 JS 번들을 분석할 수 있습니다.

 

'cra bundle analyzer'를 검색하여 cra-bundle-analyzer를 설치해줍니다. 

설치를 완료한 후,

npx cra-bundle-analyzer

명렁어를 이용해서 analyzer를 실행합니다. 잠시 후 다음과 같이 창이 뜨면서 번들 파일에 어떤 파일들이 들어 있는지 보여줍니다.

node_modules에 refractor가 약 485KB로 번들에서 꽤 큰 것을 알 수 있네요.

refractor를 package-lock.json에서 살펴보니 react-syntax-highlighter에서 디펜덴시로 refractor를 쓰고 있는 것을 확인할 수 있습니다.

(package-lock.json : 사용하고 있는 모듈들의 하위 디펜던시를 보여줌)

syntax highlight 해야 하는 부분은 첫 페이지(ListPage 컴포넌트)에서는 필요가 없었기 때문에 코드 스플릿팅으로 번들을 분할해서 더욱 빨리 JS 코드를 로딩할 수 있게 해보겠습니다. 

 

동적 임포트를 통해 코드 스플릿팅을 쉽게 할 수 있습니다.

기존에는 App.js에서 다음과 같이 한번에 모두 임포트 해오고 있었는데요.

...
import ListPage from './pages/ListPage/index'
import ViewPage from './pages/ViewPage/index'

function App() {
  return (
    <div className="App">
      <Switch>
        <Route path="/" component={ListPage} exact />
        <Route path="/view/:id" component={ViewPage} exact />
      </Switch>
    </div>
  )
}

 

lazy함수를 이용하여 동적으로 임포트 할 수 있도록 변경했습니다. 이렇게 하면

각각의 컴포넌트에 매칭된 path가 호출되는 시점에 로딩이 일어납니다.

const ListPage = lazy(() => import("./pages/ListPage/index")); //lazy loading
const ViewPage = lazy(() => import("./pages/ViewPage/index")); //lazy loading
function App() {
  return (
    <div className="App">
      <Suspense fallback={<div>로딩 중</div>}>
        <Switch>
          <Route path="/" component={ListPage} exact />
          <Route path="/view/:id" component={ViewPage} exact />
        </Switch>
      </Suspense>
    </div>
  );
}

여기서 Suspense의 fallback props에는 동적 로딩이 일어나지 않았을 때  렌더링할 컴포넌트를 넘겨줍니다.

 

다시 analyzer를 호출해보면

npx cra-bundle-analyzer

 

다음과 같이 node_modules이 쪼개진 것을 확인할 수 있습니다.

 

웹에서도 lazy loading을 적용한 컴포넌트를 불러오는 동작을 실행해보면(아까 syntax highlight가 사용되는 화면으로 들어가보면, 즉 ViewPage 컴포넌트를 호출하면) 개발자 도구의 네트워크 탭에서 js 파일을 추가적으로 로드해오는 것을 볼 수 있습니다.

 

 

 

텍스트 압축으로 로딩 성능 개선하기

운영환경은 개발환경과는 다르게 Minify등의 웹펙 기능을 추가로 실행합니다.

그래서 성능을 측정할 때는 최종적으로 실제 서비스 되는 환경인 운영환경에서 해야합니다.

 

운영환경 빌드는 다음의 명령어로 합니다.

npm run build

 

빌드된 파일을 서비스 하기 위해서는 다음의 명령어를 실행합니다.

npm run serve

package.json에서 살펴보면 npm run serve는 실제로 위와 같은 명령어를 수행하게 됩니다.

빌드 환경으로 서비스를 기동해보면 개발 환경일 때보다는 조금 더 lighthouse의 점수가 높은 것을 확인할 수 있습니다.

 

 

서버에서 클라이언트로 html, css, js 파일들을 내려줄 때 압축을 했다면 아래와 같이 네트워크 탭에서 Response Header에

"Content-Encoding:gzip"

을 확인할 수 있습니다.

다른 번들파일들도 압축을 하려면 클라이언트가 아닌 서버단에서 압축을 해줘야 합니다.

 

package.json 파일의 빌드된 파일을 실행하는 명령어를 보면 -u, -s 옵션이 있습니다. 

    "serve": "npm run build && node ./node_modules/serve/bin/serve.js -u -s build",

 

 

help를 통해 옵션을 살펴보면

./node_modules/serve/bin/serve.js --help
 -u, --no-compression                Do not compress files

-u 옵션이 압축을 해제하라는 옵션이네요.

요 옵션을 제거해줍니다.

 

복잡한 시스템에서 서버가 여러대인 경우 서버가 통하는 라우터 서버에 텍스트 압축기능을 둬서 공통적으로 관리할 수도 있습니다.

 

여기서 잠깐⚠️

모든 파일들을 다 압축해서 보내주는게 효율적일까요?

서버에서 압축을 했다면 클라이언트에서는 압축을 해제해야 합니다. 모든 파일에 다 적용하면 오히려 비효율적일 수 있으므로 위의 명령어는 파일의 크기가 2KB 이상일 경우에만 압축을 해주고 있습니다.