본문 바로가기

React/실험실

[React] Webpack - 심화

1. 나무 흔들기 

나무 흔들기(tree shaking)는 불필요한 코드를 제거해 주는 기능이다. 

웹팩은 기본적으로 나무 흔들기 기능을 제공한다.  단, 웹팩에서 제대로 동작하지 않는 경우가 있다. 

나무 흔들기를 잘 이해하고 있어야 번들 크기를 최소로 유지할 수 있다. 

npm install webpack webpack-cli
// src/util_esm.js

export const func1 = () => {
  console.log("func1_esm");
};
export const func2 = () => {
  console.log("func2_esm");
};

ESM(ECMAScript Modules) 문법을 사용하는 코드다. ESM에서는 import, export 등의 키워드를 사용한다. 

 

// src/util_commonjs.js

const func1 = () => {
  console.log("func1");
};
const func2 = () => {
  console.log("func2");
};

module.exports = { func1, func2 };

commonJS는 module.exports, require 등의 키워드를 사용한다. Node.js에서 많이 사용한다. 

 

// src/index.js

import { func1 } from "./util_esm";
import { func2 } from "./util_commonjs";

func1();
func2();
(() => {
  var o = {                                      -- commonJS
      580: (o) => {
        o.exports = {
          func1: () => {
            console.log("func1");
          },
          func2: () => {
            console.log("func2");
          },
        };
      },
    },
    r = {};
  function n(e) {
    var c = r[e];
    if (void 0 !== c) return c.exports;
    var s = (r[e] = { exports: {} });
    return o[e](s, s.exports, n), s.exports;
  }
  (() => {                                       -- esm
    "use strict";
    var o = n(580);
    console.log("func1_esm"), (0, o.func2)();
  })();
})();

util_esm에서 불러온 코드는 호출했던 func1() 함수에 대한 코드만 번들 파일에 들어가 있지만, 

util_commonjs에서 불러온 코드는 func1()과 func2() 둘 다 번들 파일에 들어가 있다. 

 

나무 흔들기는 다음과 같은 경우에 동작하지 않는다. 

  • 사용되는 모듈이 ESM이 아닌 경우
  • 사용하는 쪽에서 ESM이 아닌 다른 모듈 시스템을 사용하는 경우
  • 동적 임포트(dynamic import)를 사용하는 경우 

외부 패키지의 나무 흔들기

외부 패키지에 대해서도 나무 흔들기가 적용된다. 하지만 외부 패키지는 저마다 다양한 방식의 모듈 시스템을 사용하기 

때문에 나무 흔들기가 제대로 동작하지 않을 수있다. 

 

예를 들어, 로다시 패키지는 ESM으로 되어 있지 않기 때문에 나무 흔들기로 제거되지 않는다. 

import { fill } from 'lodash';

const arr = [1, 2, 3];
fill(arr, 'a');

로다시의 fill 함수만 사용하지만, 웹팩으로 만들어진 번들 파일에는 로다시의 모든 코드가 포함되어 있다. 

 

로다시는 각 함수를 별도의 파일로 만들어서 제공해 준다. 

import fill from 'lodash/fill';

// ...

다시 웹팩을 실행하면 번들 파일에 fill 함수의 코드만 포함된다. 

 

이처럼 사용하는 패키지에 적용된 모듈 시스템이 무엇인지, ESM이 아니라면 각 기능을 별도의 파일로 제공하는지 

여부를 파악해야 번들 크기를 줄일 수 있다. 

 

바벨 사용 시 주의할 점

우리가 작성한 코드를 바벨로 컴파일한 이후에도 ESM 문법으로 남아 있어야 한다. 

만약 @babel/preset-env 플러그인을 사용한다면 babel.config.js 파일에 추가로 설정해야 한다. 

const presets = [
	[
    	'@babel/preset-env',
        {
        	// ...
            modules: false,
        }
    ]
]

 

2. 코드 분할 

애플리케이션의 전체 코드를 하나의 번들 파일로 만들면 불필요한 코드까지 전송되어 사용자의 요청으로부터 페이지가 렌더링 되기까지 오랜 시간이 걸릴 수 있기 때문이다. 

많은 사람들 대상으로 하는 서비스라면 응답 시간을 최소화하기 위해 코드를 분할하는 게 좋다. 

npm install webpack webpack-cli react lodash

 

코드를 분할하는 가장 직관적인 방법은 웹팩의 entry 설정값에 페이지별로 파일을 입력하는 것이다. 

// src/index1.js

import { Component } from "react";
import { fill } from "lodash";
import { add } from "./util";

const result = fill([1, 2, 3], add(10, 20));
console.log("this is index1", { result, Component });

// src/index2.js
import { Component } from "react";
import { fill } from "lodash";
import { add } from "./util";

const result = fill([1, 2, 3], add(10, 20));
console.log("this is index2", { result, Component });

// util.js
export const add = (a, b) => {
  console.log("this is add function");
  return a + b;
};

같은 종류의 모듈을 사용하고 있는 index1과 index2가 있고 util에서는 add 함수를 export 하고 있다. 

 

const path = require("path");

module.exports = {
  entry: {
    page1: "./src/index1.js",
    page2: "./src/index2.js",
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
  },
  mode: "production",
};

각 페이지의 자바스크립트 파일을 entry에 각각 입력한다. 

이후 웹팩을 실행하면 page1.js, page2.js 두 파일이 생성된다. 하지만 같은 모듈의 내용을 포함하고 있어 비효율적이다.

 

3. 깃허브 

https://github.com/SeoJaeWan/webpack-tree-shaking

 

GitHub - SeoJaeWan/webpack-tree-shaking

Contribute to SeoJaeWan/webpack-tree-shaking development by creating an account on GitHub.

github.com

https://github.com/SeoJaeWan/webpack-split

 

GitHub - SeoJaeWan/webpack-split

Contribute to SeoJaeWan/webpack-split development by creating an account on GitHub.

github.com

 

반응형

'React > 실험실' 카테고리의 다른 글

[React] 실시간 채팅 만들기  (2) 2022.06.25
[React] MobX - 비동기화  (0) 2022.05.30
[React] Webpack - Plugin 사용  (0) 2022.04.18
[React] Webpack  (1) 2022.04.12
[React] Babel과 Polyfill  (0) 2022.04.06