3-1. 코드 스플리팅

우리가 17장에서 배웠었던 코드 스플리팅을 이 프로젝트에서도 적용해보겠습니다.

코드 스플리팅용 라우트 인덱스 만들기

우선 컴포넌트를 비동기적으로 불러 올 수 있게 해주는 함수 asyncComponent 를 lib 디렉토리에 파일을 만들어서 작성하세요.

src/lib/asyncComponent.js

import React from 'react';

export default function asyncComponent(getComponent) {
  return class AsyncComponent extends React.Component {
    static Component = null;
    state = { Component: AsyncComponent.Component };

    constructor(props) {
      super(props);
      if (AsyncComponent.Component) return;
      getComponent().then(({default: Component}) => {
        AsyncComponent.Component = Component;
        // 여기가 constructor 이긴 하지만 이 함수는 비동기적으로 작동하기에
        // 실질적으로는 컴포넌트가 마운트 되고 나서 실행되기 때문에 this.state.Component = ... 가 아닌
        // this.setState(...) 로 진행합니다.
        this.setState({ Component });
      });
    }

    render() {
      const { Component } = this.state
      if (Component) {
        return <Component {...this.props} />
      }
      return null
    }
  }
}

그 다음엔 이 함수를 사용하여 비동기 라우트 인덱스 파일인 index.async.js 파일을 만드세요.

src/pages/index.async.js

import asyncComponent from 'lib/asyncComponent';

export const ListPage = asyncComponent(() => import('./ListPage'));
export const PostPage = asyncComponent(() => import('./PostPage'));
export const EditorPage = asyncComponent(() => import('./EditorPage'));
export const NotFoundPage = asyncComponent(() => import('./NotFoundPage'));

프로덕션용 웹팩 설정 변경하기

코드 스플리팅이 제대로 이뤄지도록, webpack.config.prod.js 를 수정하세요. 일단, 자주 변경되지 않는 코드인 react, react-dom, redux, axios, codemirror 등의 라이브러리들을 entry 부분의 vendor 로 추가하세요.

config/webpack.config.prod.js - entry

  entry: {
    app: paths.appIndexJs,
    vendor: [
      require.resolve('./polyfills'),
      'react',
      'react-dom',
      'react-router-dom',
      'redux',
      'axios',
      'codemirror',
      'prismjs'
    ],
  },

그 다음엔, 설정 파일 하단의 plugins: [ 쪽으로 스크롤하여 플러그인들은 추가하겠습니다. vendor 파일이 따로 분리되고, 중복되는 코드가 다른 파일에 들어가지 않도록 CommonsChunkPlugin 을 설정하고, “pages” 를 import 하게 되면 index.js 가 아닌 index.async.js 를 불러오도록 하기 위하여 NormalModuleReplacementPlugin 을 적용하세요.

config/webpack.config.prod.js

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
    }),
    new webpack.NormalModuleReplacementPlugin(
      /^pages$/,
      'pages/index.async.js'
    ),
    ...

벌써 코드스플리팅 작업이 완료되었습니다! 우리가 이전에 리액트 라우터를 공부 할 때 한번 다뤄봤기 때문에, 금방 할 수있지요?

한번 터미널에서 yarn build 를 입력해보세요

$ yarn build
yarn build v0.27.5
$ node scripts/build.js
Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  115.69 KB  build/static/js/vendor.11f64b1b.js
  45.18 KB   build/static/js/0.dd9800e4.chunk.js
  33.96 KB   build/static/js/1.4ccb9a74.chunk.js
  33.84 KB   build/static/js/app.6055e75f.js
  23.83 KB   build/static/js/2.57664346.chunk.js
  1.03 KB    build/static/css/app.14c573c3.css
  222 B      build/static/js/3.38132d94.chunk.js

(...)

위와 같은 실행결과가 나타나나요? 우리는 컴포넌트를 스타일링 하기 위하여 CSS Module 과 Sass 를 결합하여 사용했는데요, CSS Module 을 사용 할 경우에, 코드 스플리팅 과정에서 CSS 관련 코드도 스플리팅이 되어서 메인 CSS 파일인 app._.css 파일에 저장되는 것이 아니라, 각 청크파일에 들어가게 됩니다.

프로젝트에서 build 디렉토리를 보면, 우리가 방금 만든 파일들이 있는데요, 그 중에서 0._____.chunk.js 파일을 열어보시면, 실제로 CSS 관련 코드가 자바스크립트 파일 내부에 내장되어있는 것을 볼 수 있습니다. (못찾겠다면 scss 를 검색해보세요)

서버사이드 렌더링을 하지 않는다면, 이러한 구조는 전혀 문제가 되지 않습니다. 하지만, 우리가 추후 서버사이드 렌더링을 하게 된다면 자바스크립트가 실행되기 전 부터, 페이지의 내용을 HTML 로 미리 받아보게 되는데요, 이렇게 CSS 가 각 자바스크립트 안에 내장이 되어있으면, 자바스크립트가 다 불러와질 때 까지 스타일링 되지 않은 HTML 이 렌더링 되게 됩니다. 결국, 흰 페이지에 검정색 텍스트만 나타나게 되겠죠. 물론, 파일을 다 불러오고 나면 모두 정상적으로 보여지겠지만, 그때까지는 사용자의 네트워크 속도가 느리다면 몇 초 정도를 못생긴 페이지를 보여줄지도 모르게 되는것이지요.

CSS 코드가 스플리팅되는것을 방지하는 것은 매우 간단합니다.

webpack 의 플러그인 부분에 다음과 같은 코드가 보일 텐데요:

config/webpack.config.prod.js - plugins - ExtractTextPlugin

    new ExtractTextPlugin({
      filename: cssFilename,
    }),

이것을 다음과 같이 수정해주시면 됩니다.

    new ExtractTextPlugin({
      filename: cssFilename,
      allChunks: true
    }),

위와 같이 allChunks 값을 설정해주고 나면 CSS 코드 스플리팅은 이뤄지지 않습니다. 설정파일을 저장하고 나서, 다시 yarn build 를 실행해보세요.

이번에 만들어진 파일의 사이즈를 보면 다음과 같습니다:

  115.69 KB (-2 B)      build/static/js/vendor.b8e93646.js
  34.81 KB (-10.36 KB)  build/static/js/0.ba96e82c.chunk.js
  32 KB (-1.84 KB)      build/static/js/app.fbeaaac0.js
  28.44 KB (-5.53 KB)   build/static/js/1.7e8d1912.chunk.js
  20.61 KB (-3.21 KB)   build/static/js/2.d4449d1e.chunk.js
  4.96 KB (+3.93 KB)    build/static/css/app.339db884.css
  223 B (+1 B)          build/static/js/3.672391ac.chunk.js

청크 파일들의 사이즈가 전체적으로 줄어들었고, CSS 파일의 사이즈가 조금 늘었습니다.

results matching ""

    No results matching ""