webpack 이 뭐에요?

 

webpack은 최신 자바스크립트 애플리케이션을 위한 정적 모듈 번들러입니다. (webpack 공식 정의)

정의는 역시 잘 와닿지 않죠.

 

그럼 모듈은 뭐고 번들은 뭘까?

 

모듈은 기능을 가진 (작은) 코드 단위이다. 대규모 애플리케이션에서 모듈화는 관리와 유지보수를 쉽게 해주고, 코드의 재사용성을 높이고 협업에 도움을 준다. 

// 작게는 아래 함수부터
function sum(a, b) {
  return a + b;
}

// 일반적으로 많이 사용하는 node_modules 에서 불러오는 것들 (패키지 기반 모듈)
import path from 'path'; 경로를 쉽게 설정할 수 있게 해주는 path 모듈

// 또는 HTML, CSS, Js, Images 파일들 하나하나도 모듈이다 (파일 기반 모듈)
index.html
main.css
main.js
image.jpg

 

모듈은 관리하기 위한 시스템이 존재하는데 대표적으로는 CommonJS, ES6 모듈 시스템이 있다.

CommonJS) require module.exports 를 사용해 모듈을 가져오고 내보낸다.

ES6) import export 로 모듈을 가져오고 내보낸다.

 

번들은 관련 파일들을 하나로 묶어주는 것인데 (연필 12개를 한다스로 묶듯이)

모듈 번들러는 웹 애플리케이션을 구성하는 여러 모듈(파일 등)을 하나의 파일로 묶고 압축해주는 것을 모듈 번들링이라고 한다. (흔히 빌드한다고 하는데 번들링과 같은 말임)

webpcak docs 중 발췌

 

webpack 어디다 쓰나요?

 

웹팩은

1. 자바스크립트 모듈(파일)들의 관리와 

2. 웹 애플리케이션 빠른 로딩 속도와 성능

등의 이점이 있다.

 

1. 자바스크립트 모듈(파일)들의 관리

react, next.js는 자동으로 webpack 설정을 해줘서 종종 잊지만 한번씩 html, css, js 파일로 작은 애플리케이션을 만들다 보면 webpack 설정은 필요하다.

 

아래 번들링 없이 전역 변수를 사용하는 예시를 보자.

hello.js, world.js 파일을 불러와 innerHTML에 파싱한다

// index.html
<html>
    <body>
      <h1>hello, webpack!</h1>
      <div id="root"></div>
        <script src="./src/hello.js"></script>
        <script src="./src/world.js"></script>
        <script>
          document.getElementById('root').innerHTML = v; // world 만 출력 
        </script>
    </body>
</html>

// hello.js
var v = "Hello";

// world.js
var v = "world";

 

결과는 늦게 가져온 world.js 값만 파싱되었다 (덮어 씌워짐)

변수의 유효 범위 때문에 전역 변수의 예상치 못한 충돌이 발생한다.

 

-> ES6 모듈 시스템을 사용해 이름 충돌을 피할 수 있다. 

<script type="module">
  import v_hello from './src/hello.js';
  import v_world from './src/world.js';
  document.getElementById('root').innerHTML = v_hello + " " + v_world; // hello world 출력
</script>

위와 같이 ES6 모듈만 사용해도 전역 변수 충돌 해결된다.

하지만 webpack을 사용하면 더 깔끔하게 관리 가능하다.

 

index.js 파일에 위 코드를 작성하고 

// index.js
import v_hello from './hello.js';
import v_world from './world.js';

document.getElementById('root').innerHTML = v_hello + " " + v_world;

 

webpack으로 번들링해보자.

그리고 index.html 의 script 파일 경로를 번들링된 js로 변경

// index.html

<body>
  <h1>hello, webpack!</h1>
  <div id="root"></div>
  <script src="./build/main.js"></script> // bundle 된 js 파일 경로
</body>

이렇게 하면 위의 기능과 동일하게 root 안에 hello world 가 출력된다.

-> webpack을 통해 2개의 js파일을 하나로 관리하고 import export 로 전역 변수 충돌문제를 해결하는 es6 모듈 시스템을 더욱 잘 관리할 수 있게됐다. 

 

물론 요새는 var 사용 안하기도 하고 예시가 잘 와닿지 않을 수 있지만 위와 같은 번들링이 없던 시절엔 점점 규모가 커지면서 위의 전역변수 충돌, 모듈 관리의 문제점이 있었고 이를 방지하기 위해 여러 방법 중에 하나인 웹팩이 등장했다고한다.

 

+ react에 설정된 자동 번들러없이 js 파일 만들때 아래 에러 한번씩은 만나봤을겁니다..


Uncaught TypeError: Failed to resolve module specifier "lodash". Relative references must start with either "/", "./", or "../". 

// hello.js

import _ from "lodash"; // react에서 처럼 그냥 이렇게 node_modules 에서 가져오면 에러남

var v = _.join(["Hello", " ", "world"], ""); // Hello world

 

위와 같이 상대 경로로 가져오라는 에러가 나는데 웹 브라우저는 기본적으로 상대 경로로 시작하는 경로만 지원하고

빌드없이 해당 모듈을 불러오려면 import _ from "../node_modules/lodash/lodash.js" 요런식으로 해야되는 번거로움이 발생한다. (빌드 후에는 최종 파일에 lodash 와 같은 import 한 모듈이 포함되어 있어 바로 접근 가능한것)

이와같이 개발 과정에서 빌드 도구를 사용하면 모듈 관리를 편하게 할수있다.

 

2. 웹 애플리케이션 빠른 로딩 속도와 성능

많은 js 파일을 하나의 js 파일로 묶어서 압축해주기 때문에 용량이 작아져 웹 브라우저가 빨리 읽을수 있고 

여러 HTTP 통신을 줄여줘 웹 애플리케이션 성능을 높여줌. 

 

간단한 예제

webpack 과 webpack-cli 설치

webpack-cli 를 통해 npx webpack, npx webpack server 등의 명령어를 사용할 수 있다

npm init
npm install webpack webpack-cli --save-dev

 

// package.json

// script는 취향에 따라 커스텀해준다
"scripts": {
  "build": "npx webpack --watch" // 해당 명령어는 바라보는 js 파일이 변하면 다시 build 해줌
}
// webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js', // 해당 경로 index.js을 build 해서
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'), // 해당 경로에 main.js 로 output 해준다
  },
};

// entry 와 output 은 위 설정이 default 지만 여러 프로젝트마다 폴더구조도 다르고하니 알아두자

 

css 번들 

css도 js 파일로 함께 말수있다. 

 

css 관련 모듈 설치

npm install --save-dev css-loader
npm install --save-dev style-loader
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/i, // 파일 확장자가 .css로 끝나는 모든 파일을 build 한다
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

loader는 파일을 전처리 시켜준다. loader를 통해 js 파일만이 아닌 자산(css, image, json 파일 등등)을 번들링 할 수 있다.

(css -> js, image -> base64 로 변환)

 

html도 함께 번들링해야 배포하기 편함

const HtmlPlugins = require("html-webpack-plugin");

module.exports = {
  plugins: [ // css와 다르게 plugins에서 인스턴스를 실행한다
    new HtmlPlugins({
      filename: "index.html", // output 시 파일명
      template: "./src/index.html", // input html 경로
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

로더는 특정 유형의 모듈(css, image)을 변환하고, 플러그인은 번들을 최적화하거나, 에셋 관리, 환경 변수 주입 등의 다양한 작업을 할 수 있다. (HTML 파일 생성, 코드 압축, .env 파일의 환경 변수 주입 등)

'Webpack' 카테고리의 다른 글

Webpack 개념에서 실무활용까지 -2  (0) 2024.08.21

+ Recent posts