webpack-1

GI JUNG·2023년 3월 18일
3

web

목록 보기
1/1

🍀 webpack이란?

웹팩은 간단하게 모듈 번들러이다. 여기서 모듈은 웹을 구성하는 모든 자원( html, css, javascript, image, font etc... )이며, 웹팩에서의 번들러는 모듈로 취급된 자원들을 하나의 결과물로 묶어준다. 그리고 하나의 결과물로 묶어주는 행위를 bundling(번들링) 이라 할 수 있다. 웹 개발을 하면서 모듈이라 하면 하나의 javascript file로만 생각하였는데 Webpack에서는 모두 모듈로 취급한다.


<의존성 있는 파일들을 하나의 파일로 번들링한다>

🍀 webpack이 필요한 이유

webpack이 필요한 이유는 여러가지가 있다.

  • 기본적으로 자바스크립트는 변수의 유효 범위가 전역범위를 갖는데 이로 인해 발생할 수 있는 전역오염(global namespace pollution) 을 예방할 수 있다.
  • 많은 script를 head또는 body안에 위치시켰지만, script tag가 너무 많아지면 개발자가 개발에만 집중할 수 없고 script간의 순서와 의존성 관리해야 하는데 webpack이 알아서 처리해준다. 실제로 bundling된 파일을 봤을 때 IIFE로 관리함을 찾아볼 수 있었다.
  • Lazy Loading(모듈이 필요할 때마다 요청하여 모듈을 로딩함)을 통해서 웹 애플리케이션의 빠른 로딩 속도를 보장한다.
  • 반복되는 작업들을 자동화 해준다.

위와 같은 이유도 있지만 또 다른 이유는 module system이 있다. 현재 웹 개발에서 ES Module system인 import/export 를 사용하부터 javascript에 모듈을 지원하기 시작할 때를 생각할 수 있다. import/export 를 웹팩을 이용하여 할 수 있게 된 것이다. 이와 관련하여 아래 예시를 보자.

<!-- index.html -->
<html>
    <script src="./src/printer.js" defer></script>
    <script src="./src/index.js" defer></script>
    <title>Document</title>
</html>

// printer.js
function printPretty(arr) {
  let result = "";
  arr.forEach((n) => (result += `${n} `));
  result.trim();

  console.log(result);
}
// index.js
printPretty([1, 2, 3, 4, 5]);

브라우저에서 아래와 같은 출력을 확인할 수 있다.

index.js와 printer.js는 전역 스코프를 공유하고 있기 때문에 window.printPretty 를 통해서 함수에 접근할 수 있으며 전역 오염(global namspace pollution) 이 일어날 수도 있다. 또한 위치상 printer.js가 index.js보다 뒤에 온다면, printPretty 라는 함수는 index.js가 파싱되고 실행되는 동안 printPretty라는 함수의 존재를 알 수 없다.

👇 전역 공간에서 printPretty 함수 확인

만약 의도치 않게 함수에 접근하여 값을 바꾼다고 해 보자. 이렇게 되면 지정한 함수의 의도와 맞지 않게 변경되어 전역 오염이 발생한다.

👇 전역 오염 예시

위의 전역 오염을 IIFE(Immeditaely Invoked Function Expression을 이용하여 전역 스코프와 독립적인 스코프에 printer함수를 선언하여 전역 스코프에서 참조하지 못 하도록 할 수 있다.

// index.js
printer.printPretty([1, 2, 3, 4, 5]);
// printer.js
const printer = {};

// 👇 IIFE를 이용하여 전역 scope와 분리된 독립적인 scope에 함수 정의
(function () { 
  function printPretty(arr) {
    let result = "";
    arr.forEach((n) => (result += `${n} `));
    result.trim();

    console.log(result);
  }

  printer.printPretty = printPretty;
})();

이렇게 IIFE를 이용하여 유하하게 독립된 모듈처럼 구현할 수 있으나 아래와 같이 ES Module import/export를 이용하면 파일간의 의존성과 독립된 모듈 스코프를 가지므로 개발하기 편하다.

<!-- index.html -->
<html>
    <script type="module" src="./src/index.js" defer></script>
    <title>Document</title>
</html>

script tag에 type="module"을 지정해 주어야한다.

// index.js
import { printPretty } from "./printPretty.js";
printer.printPretty([1, 2, 3, 4, 5]);
// printer.js
export function printPretty(arr) {
  let result = "";
  arr.forEach((n) => (result += `${n} `));
  result.trim();

  console.log(result);
}

하지만, 브라우저에서 기본적으로 ES Module을 지원하지 않는 브라우저도 있기 때문에 어떤 브라우저에서든 ES Module이 사용가능하게끔 이해할 수 있는 형식으로 트랜스파일링 하는 것이 필요한데 이를 webpack이 해준다.

🍀 webpack 사용해보기

webpack을 사용하기 위해서 webpack, webpack-cli를 설치 해주어야 한다. 여기서 webpack-cli는 개발자가 command line을 통해서 webpack을 다루는데 있어서 명령 및 옵션을 제공해준다.

$) npm i -D webpack webpack-cli
$) yarn add -D webpack webpack-cli

기본적으로 Webpack을 사용하기 위해서는 --entry, --mode, --ouput 속성들을 지정해주어야 한다.

💡 여기서 중요한 점은 output path는 절대경로를 이용해서 찾기 때문에 path.resolve를 이용하여 처리해주었다.

--entry: 모듈의 진입점(시작지점)으로서 진입점을 기반으로 연관된 모듈들을 읽어올 수 있다.
--mode: development, production, none 총 3가지가 있다.
--output-path: bundling이 끝난 최종 하나의 파일을 저장하는 경로 지정

webpack을 실행하기 전 파일은 아래와 같다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script type="module" src="./src/index.js" defer></script>
    <title>Document</title>
  </head>
  <body></body>
</html>
// printer.js
export function printPretty(arr) {
  let result = "";
  arr.forEach((n) => (result += `${n} `));
  result.trim();

  console.log(result);
}
// index.js
import { printPretty } from "./printer.js";

printPretty([1, 2, 3, 4, 5]);

아래 command를 이용하여 webpack을 실행해보자.

$) node_modules/.bin/webpack --mode development --entry ./src/index.js --output-path ./dist
js --output-path ./dist
$) npx webpack # 위의 코드를 그냥 이 명령어로 실행해도 된다.

👆 위의 명령어는 개발모드이며 src folder 밑에있는 index.js를 bundling하여 dist folder 밑에 저장해라.

번들링이 완료되어 main.js라는 하나의 파일을 얻을 수 있다.

이제 index.html에 이전에 ES Module을 사용하기 위해 type=”module”을 준 것은 webpack이 알아서 처리(index.js와 printer.js를 하나의 파일로 묶어줌)해주었기 때문에 dist/main.js file을 script로 넣어주자.

<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="./dist/main.js"></script>
    <title>Document</title>
  </head>
</html>

이렇게 하면 아까와 같이 browser에서 동일한 결과값인 1 2 3 4 5 를 확인할 수 있다.

하지만, 이렇게 일일히 webpack의 설정을 command로 한다면 골칫거리이다. 이 때 webpack에 대한 명세 파일인 webpack.config.js 를 만들어 이를 기반으로 webpack으로 번들링 할 수 있다.

// webpack.config.js
const path = require("path");

module.exports = {
  mode: "development",
	// entry: "./src/index.js", 
  entry: {
    main: "./src/index.js",
  },
  output: {
		// filename: "[name].js", => entry에서 main keyword를 그대로 넣는다.
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
		clean: true // bundling 때마다 dist안의 파일을 최신파일 상태로 만든다.
  },
};

이제 아래 command를 이용하여 webpack으로 bundling을 해보면…


"scripts": {
	"build": "webpack"
}
$) npm run build
$) yarn build

그리고 에러가 발생했다…. 하…. 또 한참 삽질하다가 여기에서 찾을 수 있었다.

오류를 해결하고 다시 에러 메세지를 자세히 읽어보니 좀만 더 자세히 봤으면 찾아보지 않고 스스로 해결할 수 있는 문제였다. 이는 webpack.config.js에서 path를 require로 불러와서 commonjs로 다루는 것이냐??? 그런데 package.json을 보니 type: “module”인 것을 보아 뭐가 맞냐??라는 의미였다. webpack.config.js를 읽는 환경은 nodejs환경인데 type="commonjs"가 아닌 type="module"이 설정되어 있으니 오류가 난 것이다.

🔥 마치며

웹팩은 그냥 번들러다 정도만 알고 넘어갔었다. 사실상 웹팩을 건드리기 엄두가 안 났다. 커리어리에서 글을 보다가 webpack을 잘 사용할 수 있으면 좋다고해서 애매하게 알 바엔 어떤 녀석인지 왜 필요한지 어떻게 사용할 수 있는지 배워보고 싶어서 시작했다. 더 공부하면서 loaderplugin에 대해서 나오는데 이는 다음 장에서 다루겠다.

📚 참고

webpack docs
webpack handbook
output option refer

profile
step by step

0개의 댓글