본문 바로가기
JavaScript/React

[React] 웹팩(Webpack)에 대한 이해

by junvely 2022. 11. 18.

✨웹팩(Webpack)이란 무엇인가?

웹팩(Webpack)이란 "JavaScript를 위한 정적 모듈 번들러" 이다.

그렇다면 모듈은 무엇이고, 번들러는 또 무엇일까? 이 둘의 개념부터 알아보자.

 


모듈(module)이란 ?

 

자바스크립트에서 모듈은, 어떤 특정 기능과 관련된 JavaScript 코드들(함수)로 이루어진 있는 하나의 파일을 말한다.

자바스크립트의 크기가 점차 커지고 기능도 복잡해지자 자바스크립트 커뮤니티는 특별한 라이브러리를 만들어 필요한 모듈을 언제든지 불러올 수 있게 해준다거나 코드를 모듈 단위로 구성해 주는 방법을 만드는 등 파일을 여러개로 분리하여 모듈화 하는 등의 다양한 시도를 하게 되었고, 대표적으로 AMD, CommonJs(Node.js에서 사용 - requre(), module.exports), UMD, ES6(import, export) 등의 모듈시스템이 만들어졌다.

모듈화의 대표적인 장점으로는 아래와 같다.

  • 유지보수성, 가독성 : 기능들이 모듈화가 잘 되어있다면, 의존성을 그만큼 줄일 수 있기 때문에 어떤 기능을 개선한다거나 수정할 때 훨씬 편하게 할 수 있다.
  • 네임스페이스화 : 자바스크립트에서 전역변수는 전역공간을 가지기 때문에 코드의 양이 많아질수록 겹치는 네임스페이스가 많아질 수 있다. 그러나 모듈로 분리하면 모듈만의 네임스페이스를 갖기 때문에 그 문제가 해결된다.
  • 재사용성 : 똑같은 코드를 반복하지 않고 모듈로 분리시켜서 필요할 때마다 사용할 수 있다.

 


웹팩(Webpack)에서의 모듈(module)이란 ?

 

웹팩에서의 모듈(module)은 자바스크립트에서의 모듈과는 조금 다르다. 특정 기능을 갖는 작은 코드 단위라는 점에서는 같지만, 웹팩에서의 모듈은 웹 애플리케이션을 구성하는 모든 자원(HTML, CSS, JS, Image 등등)을 의미한다. 우리가 리액트에서 이미지 하나까지도 모듈화하여 import해 재사용 및 유지보수성을 높이는 것과 같은 맥락인 것 같다.

웹팩에서의 모듈 시스템은 다음과 같다.

  • Common Js module - require() 구문
  • AMD modules - define과 require 구문
  • ES module - import, export구문
  • CSS imports - css/sass/less 파일들 안에서 사용하는 @import 구문
  • Image URLs - url(...) 또는 <img src ="..." />

등등 웹팩은 이런 여러가지 모듈들을 자바스크립트 코드로 import할 수 있도록 해준다.

 

 


번들러(Bundler)의 등장

 

인터넷의 발달로 대규모 웹서비스가 등장하면서 수백만줄의 자바스크립트 코드와 파일을 다루면서 다음과 같은 문제가 하나 둘씩 발생하게 된다. 

1. 중복된 이름으로 인한 에러

index.html

<head>
    <script src="./hello.js"></script>
    <script src="./world.js"></script>
</head>
<body>
    <h1>Hello, Webpack</h1>
    <div id="root"></div>
    <script type="module">
        document.querySelector("#root").innerHTML = word;
    </script>
</body>

hello.js

const word = "Hello";

world.js

const word = "World";

다음과 같은 파일에서 hello.js와 world.js 둘 다 word 변수를 가지고 있어 충돌이 일어난다.

사용자가 정확히 어떤 word를 사용하고 싶은지 구분하기도 어렵고, 의도치 못한 값이 출력되거나 함수나 변수가 삽입되는 등 심각한 에러가 발생할 수 있다.

대규모 프로젝트에서는 수십명의 개발자들에 의해 수백개의 코드가 작성되기 때문에 변수명을 사전에 방지하는 것은 불가능에 가깝다.

 

2. 파일 전송 문제

사용자가 요청을 하면 서버는 웹 애플리케이션을 구성하는 파일들을 보낸다. 웹 애플리케이션를 구성하는 파일의 양이 많다면, 사용자의 요청에 응답하는 시간이 길어지게 된다.(서버가 파일 1개를 요청하고 응답하는데 1초가 걸린다고 가정하였을 때 100개의 파일을 응답하는 데 100초, 1000개의 파일을 응답하는 데 1000초의 시간이 걸린다.)

거기에 수많은 사용자가 웹 사이트를 이용할 경우, 응답을 제때 하지 못해 네트워크 *병목현상이 일어날 수 있다.

*병목현상 : 두 구성 요소의 최대 성능의 차이로 인해 한 구성 요소가 다른 하드웨어의 잠재 성능을 제한하는 것을 말한다.

 

이와같이 만약 파일의 양을 줄이기 위해 하나의 JS 파일에 모든 변수, 함수를 추가한다고 하면 속도 면에선 빨라져 네트워크 병목 현상을 피할 수 있을 것이다. 하지만 개발자의 입장에선 수 천, 수 만줄의 코드를 유지보수 하는 것은 가독성에서 최악이다.

이처럼 가독성, 유지 보수를 위해 파일을 분리하면 네트워크 병목현상이 일어날 것이고, 응답 시간을 위해 파일 수를 줄이면 가독성, 유지 보수가 힘들어지는 딜레마에 빠지게 된다. 

 

이와같은 문제들로 인해 여러개의 파일을 하나의 파일로 묶어주는 번들러가 등장한다.

 

 


번들러(Bundler)란?

 

JS, CSS, 이미지 등의 파일을 묶어주는 작업을 '번들링(Bundling)'이라고 하고, 최소한의 작업의 결과물을 '번들(Bundle)'이라고 한다.

즉 번들링이란, 웹 애플리케이션을 구성하는 몇백개의 모든 모듈들 = 자원(HTML,CSS,JS,Image등등)들의 의존성 관계를 파악하여 그룹화하는 작업, 최소한의 파일 묶음(번들)로 병합 및 압축해주는 것을 말한다.

또한 자바스크립트 파일을 외부에서 알아 보기 힘들게 코드를 변환하는 작업(Uglyfy)을 한다거나, 바벨(babel) 등의 다양한 로더를 활용하여 모던 자바스크립트(ES6 > ES5변환)나 SASS 등을 사용할 수 있게 돕는다.

번들링 과정이 끝나면 기존 스크립트에서 import/export가 사라지기 때문에 type="module"이 필요 없어진다. 따라서 번들링 과정을 거친 스크립트는 일반 스크립트처럼 취급한다.

번들러는 웹팩 외에도 Rollup, Parcel 등이 있다.

 


🔥지금까지 정리 

웹팩에서 모듈이란, 웹 애플리케이션을 구성하는 모든 자원(HTML, CSS, JS, Image 등등)을 의미하고,

모듈화의 장점은 다음과 같다.

  • 유지보수성, 가독성 : 기능들이 모듈화가 잘 되어있다면, 의존성을 그만큼 줄일 수 있기 때문에 어떤 기능을 개선한다거나 수정할 때 훨씬 편하게 할 수 있다.
  • 네임스페이스화 : 자바스크립트에서 전역변수는 전역공간을 가지기 때문에 코드의 양이 많아질수록 겹치는 네임스페이스가 많아질 수 있다. 그러나 모듈로 분리하면 모듈만의 네임스페이스를 갖기 때문에 그 문제가 해결된다.
  • 재사용성 : 똑같은 코드를 반복하지 않고 모듈로 분리시켜서 필요할 때마다 사용할 수 있다.

웹팩에서의 모듈의 장점은 자바스크립트 외의 리소스 포맷의 모듈도 사용할 수 있게 해 준다는 것이다. CSS든, 이미지든 사용하려는 곳에 해당 리소스를 import 해주기만 하면 웹팩이 알아서 빌드(번들링)해준다

 

번들링이란, 웹 어플리케이션의 모든 모듈들의 의존성 관계를 파악하여 그룹화하는 작업, 최소한의 파일 묶음(번들)로 병합 및 압축해주는 것을 말한다.

번들러는 다음과 같은 문제들을 해결하였다.

  • 변수명의 중복 방지
  • 파일 전송 문제로 인한 병목현상(속도), 크기, 가독성, 유지보수 문제 해결 등

 


 

이제부터 다시 웹팩(Webpack)에 대해 알아보자.

 


웹팩(Webpack)란?

웹팩(Webpack)이란 "JavaScript를 위한 정적 모듈 번들러" 이다.

 

웹팩을 사용해야 하는 이유는 무엇일까?

위에서 언급한 번들러의 장점도 있지만,

  • 편리한 모듈 의존성 관리
  • 빠른 컴파일 속도 : 웹팩은 여러 개의 파일을 하나로 번들링하기 때문에 HTTP 요청 횟수를 줄일 수 있다. 이는 빠른 서비스 제공에 도움이 된다.
  • 자동 빌드 : 자바스크립트 외의 리소스 포맷의 모듈도 사용할 수 있게 해 준다. CSS든, 이미지든 사용하려는 곳에 해당 리소스를 import 해주기만 하면 웹팩이 알아서 빌드해준다. Webpack 같은 번들러는 자동으로 빌드하고, import나 export 항목을 기반으로 디펜던시 그래프를 추론한다. 이 덕에 코드를 수정했을 때 다시 빌드하고 새로고침 하지 않아도 바로바로 빌드 결과를 확인할 수 있다.
  • 자바스크립트 파일을 외부에서 알아 보기 힘들게 코드를 변환하는 작업(Uglyfy)을 한다.
  • 바벨(babel) 등의 다양한 로더를 활용하여 모던 자바스크립트(ES6 > ES5변환)나 SASS 등 다양한 리소스를 사용할 수 있도록 지원한다.
  • 꾸준한 성장과 문서화

 

웹팩의 환경적 특징

  • Webpack은 브라우저 외부 환경의 서버나 컴퓨터에서 사용할 수 있는 JavaScript 런타임인 Node.js에서 동작한다. 웹팩은 AMD, *Common JS(Node.js에서 사용)를 지원한다.
* CommonJS(http://www.commonjs.org/)는 서버사이드에서 자바스크립트를 사용하고자 하는 사람들이 만든 모듈 스펙이다.
JavaScript를 브라우저에서뿐만 아니라, 서버사이드 애플리케이션이나 데스크톱 애플리케이션에서도 사용하려고 조직한 자발적 워킹 그룹이다.
CommonJS의 ‘Common’은 JavaScript를 브라우저에서만 사용하는 언어가 아닌 일반적인 범용 언어로 사용할 수 있도록 하겠다는 의지를 나타내고 있는 것이라고 이해할 수 있다.
CommonJS가 꼭 서버사이드에만 사용하는 것은 아니지만 CommonJS를 만든 목적이 서버사이드에서 JavaScript를 사용하는 것이었기 때문에 서버사이드 용으로 사용할 때에 장점이 많다.
  • require를 도입한 CommonJS가 출시되었는데 이는 현재 파일에서 모듈을 불러오고 사용할 수 있다. 이것은 javascript를 브라우저 뿐만 아니라 필요한 곳에 모듈을 가져와 별도의 구성 없이 바로 사용할 수 있도록 하여 유효범위 문제를 해결했다.

 

 


웹팩(Webpack)의 사용방법

 

1. 웹팩 설치

npm init -y // npm 초기화
npm install webpack webpack-cli webpack-dev-server -D // 또는
npm i -D webpack webpack-cli webpack-dev-server
devDependencies를 설치할 경우 npm i -D 또는 npm install ~ -D 를 붙여줘야 한다.
코드를 수정했을 때 다시 빌드하고 새로고침 하지 않아도 바로바로 빌드 결과를 확인할 수 있는 webpack-dev-server를 추가 설치
 
 
 
 
 

2. package.json 의 script부분 dev로 수정

참고 : CRA 없이 리액트 개발환경 셋팅하기 : https://junvelee.tistory.com/31  

  "scripts": {
    "dev": "webpack serve --mode development --open --hot",
    "build": "webpack --mode production"
 
  },
필요에 따라 --mode 옵션을 줄 수 있다. 'development(개발모드)', 'production(배포모드)', 'none' 세 가지 값을 정할 수 있다. 
 
환경변수에 있는 DefinePlugin을 'development' 또는 'production'으로 바꾸고 웹팩이 각 모드에 따라 최적화를 할 수 있도록 한다. 'none'으로 지정하면 최적화를 허용하지 않는다. 
 
dev는 개발의 생산성을 높이기 위한 설정. production은 생산성은 고려하지 않고 실제 서비스 될 때 필요한 최적화 설정이 포함됨. 가장 큰 차이점은 bundle 빌드시 production에서 treeshaking이 가능하고 development는 불가능하다.
 
 
 
 
 

3. entry 설정

webpack은 번들링 과정에서 '디펜던시 그래프(dependency graph)'를 그린다. 특정 지점에서 출발해서, 애플리케이션에 필요한 모든 모듈을 포함하는 그래프를 재귀적으로 완성해 나간다. 한 파일이 다른 파일을 필요로 하면 이를 '디펜던시(dependency)'가 있다고 해석하는데, 그래프를 모두 그리고 나면 이 모든 모듈을 소수의 번들로 묶어서 (보통 하나의 번들로 묶는다) 브라우저에 로드될 준비를 마친다.

이때 우리는 webpack이 어디를 출발지점으로 해서 그려나가면 좋을지 알려주어야 한다. config파일에서 entry 속성을 설정해서 웹팩이 어떤 모듈로부터 시작해서 디펜던시 그래프를 그려나갈지 명시해줄 수 있다. 'entry' 속성의 기본값은 './src/index.js'이지만 다른 Entry Point를 지정할 수도 있다. (여러 개도 지정 가능)

module.exports = {
  mode: process.env.mode,
  entry: "./src/index.js", //여기서부터 시작

엔트리 포인트를 분리하는 경우는 싱글 페이지 애플리케이션이 아닌 특정 페이지로 진입했을 때 서버에서 해당 정보를 내려주는 형태의 멀티 페이지 애플리케이션에 적합하다.

entry: {
  login: './src/LoginView.js',
  main: './src/MainView.js'
}

 

 

4. output 설정

  • 웹팩을 돌리고 난 결과물의 파일 경로로 객체 형태로 옵션들을 추가해야 한다.

output 은 웹팩이 번들을 꾸리고 나서 결과물을 어디로 내보낼지 지정하는 속성이다. 기본값으로 메인 결과물인 main.js 파일은 ./dist/main.js에, 그 외 파일은 ./dist 폴더에 내보내 진다.  output.filename과 output.path 속성을 사용하여 webpack에 번들의 이름과 내보낼 위치를 알려주었다. 파일 이름(filename), 경로(path)를 별도로 지정할 수 있고, clean을 true로 설정하면 지정한 결과물이 내보내지는 디렉토리(본 예제에서는 dist)안에 사용하지 않는 파일을 알아서 정리해준다. 이외에도 수많은 커스텀 옵션을 설정할 수 있다. https://webpack.js.org/configuration/output/

 output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[hash].js",
    publicPath: "/",
  },

 

 

5. resolve 설정

확장자를 확장자 별칭에 매핑하는 객체이다. 이 옵션은 모듈을 해석하는 방식을 변경 할 수 있다. webpack은 알맞은 기본값을 제공하지만, 상세하게 해석 방식을 변경할 수 있다. 

  resolve: {
    // path.resove 형태로 사용할 수도 있다.
    // 그러면 node의 기본 모듈 'path'를 불러와야 한다.
    extensions: [".js", ".jsx", ".css"],
  },

 

6.  module = loader

  • 웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원(HTML, CSS, Images, 폰트 등)들을 변환할 수 있도록 도와주는 속성
  • 엔트리나 아웃풋 속성과는 다르게 module라는 이름을 사용
  • 로더를 여러개 사용할 경우 rules 배열에 옵션을 추가
  • 여러 개의 로더를 사용하는 경우 오른쪽에서 왼쪽 순으로 적용
module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: "/node_modules/",
        loader: "babel-loader",
      },
      {
        // test: 로더를 적용할 파일 유형 (일반적으로 정규 표현식 사용)
        // use: 해당 파일에 적용할 로더의 이름
        test: /\.css$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
        ],
      },
    ],
  },

 

 

7. plugins

  • 웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성.
  • 로더는 파일을 해석하고 변환하는 과정에 관여하는 반면, 플러그인은 해당 결과물의 형태를 바꾸는 역할.
  • 플러그인의 배열에는 생성자 함수로 생성한 객체 인스턴스만 추가될 수 있다.
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],

 

< 참고 >

https://baeharam.netlify.app/posts/javascript/module

https://365kim.tistory.com/35