[⚓️개발환경] 웹팩이란 무엇인가

2024. 7. 8. 13:13·⚓️ 개발환경

1. 배경

문법 수준에서 모듈을 지원하기 시작한 것은 ES2015부터입니다.

import / export 구문이 없던 모듈 이전 상황을 살펴보면 웹팩의 등장 배경을 이해하는데 수월할 것입니다.

// math.js
function sum(a,b){
	return a + b;
}

// app.js
sum(1, 2);
  • 위 코드는 모두 하나의 HTML 파일 안에서 로딩해야만 실행됩니다.
  • math.js가 로딩되면 app.js는 이름 공간에서 ‘sum’을 찾은 뒤 이 함수를 실행합니다.
  • 문제는 ‘sum’이 전역 공간에 노출된다는 것입니다. 즉, 다른 파일에서도 ‘sum’이란 이름을 사용한다면 충돌이 일어납니다.

1.1 IIFE 방식의 모듈

  • 이러한 문제를 예방하기 위해 스코프를 사용합니다.
  • 함수 스코프를 만들어 외부에서 안으로 접근하지 못하도록 공간을 격리하는 것입니다.
var math = math || {} //math의 네임스페이스

(function(){
	function sum(a, b){
		return a + b;	
	}
	math.sum = sum
})()
  • 코드를 즉시 실행함수로 감쌌기 때문에 다른 파일에서 이 안으로 접근할 수 없으며, 동일한 파일일지라도 접근 불가합니다.
  • 이는 자바스크립트의 함수 스코프의 특징입니다. ‘sum’이란 이름은 즉시실행함수 안에 감추어졌기 때문에 외부에서는 같은 이름을 사용해도 괜찮습니다.
  • 전역에 등록한 ‘math’라는 이름 공간만 잘 활용하면 됩니다.

 

1.2 다양한 모듈 스펙

  • 이러한 방식으로 자바스크립트 모듈을 구현한 대표적 명세가 AMD와 CommonJS입니다.

1.2.1 CommonJS

  • CommonJS는 자바스크립트를 사용하는 모든 환경에서 모듈을 사용하는 것이 목표입니다.
  • exports 키워드로 모듈을 만들고 require() 함수로 불러들이는 방식입니다.
  • 대표적으로 Node.js에서 이를 사용합니다.
// math.js 
exports function sum(a, b) { return a + b; } 

// app.js 
const math = require('./math.js'); 
math.sum(1, 2); // 3

1.2.2 AMD

  • AMD(Asynchronous Module Definition)은 비동기로 로딩되는 환경에서 모듈을 사용하는 것이 목표이다.

1.2.2 UMD

  • UMD(Universal Module Definition)는 AMD기반으로 CommonJS 방식까지 지원하는 통합 형태입니다.

이렇게 각 커뮤니티에서 각자의 스펙을 제안하다 ES2015에서 표준 모듈 시스템을 내놓았습니다.

지금은 웹팩과 바벨을 이용해 모듈 시스템을 사용하는 것이 일반적입니다.

1.2.3 ES2015 모듈 시스템

// math.js
export function sum(a, b){
	return a + b;
}

// app.js
import * as math from './math.js'
math.sum(1, 2);
  • export 구문을 모듈로 만들고 import 구문으로 가져올 수 있습니다.

 

1.3 브라우저의 모듈 지원

  • 안타깝게도 모든 브라우저에서 모듈 시스템을 지원하진 않습니다.
  • IE를 포함한 몇 브라우저에서는 여전히 모듈을 사용하지 못합니다.
  • 가장 많이 사용하는 크롬브라우저를 보자면 type=”text/javascript” 대신 type=”module”을 사용합니다.
  • 즉, app.js는 모듈을 사용할 수 있습니다.
  • <script type="module" src="app.js"></script>
  • 그러나 위에서 이야기 했던 것처럼 IE등 몇몇 브라우저는 모듈 사용이 불가합니다.
  • 이제 웹팩이 나올 차례입니다.

 

2. 엔트리/아웃풋

  • 웹팩은 여러 개의 파일을 하나로 합쳐주는 번들러입니다.
  • 하나의 시작점 (entry point)로부터 의존적인 모듈을 전부 찾아내서 하나의 결과물을 만들어냅니다.
  • app.js부터 시작해 math.js 파일을 찾은 뒤 하나의 파일로 만드는 방식입니다.

2.1 웹팩으로 번들링 해보자

1. webpack-test 디렉터리를 만들고 그 안에서 예제를 실행하도록 하겠습니다.

$ mkdir webpack-test
$ cd webpack-test

2. HTML 파일 작성하기

  • index.html
// index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Example</title>
  </head>
  <body>
    <script type="text/javascript">
      function currentTime() {
        const date = new Date();
        const hours = date.getHours();
        const minutes = date.getMinutes();
        const seconds = date.getSeconds();
        return `${hours}:${minutes}:${seconds}`;
      }

      const div = document.createElement("div");
      document.body.appendChild(div);
      setInterval(() => (div.innerText = currentTime()), 1000);
    </script>
  </body>
</html>

 

브라우저 화면 

  • 위 html 파일을 liveserver을 이용해 열어본다면 1초마다 화면을 업데이트해 현재 시각을 나타내 보여줍니다.


 

3. HTML / JavaScript 분리하기

  • HTML 태그와 JavaScript 코드를 하나의 파일에 섞는 것은 좋은 코드가 아닙니다.
  • 따라서 index.html 파일에서 Javascript 코드만 뽑아내어 index.js 파일을 만들고 이 둘을 script 태그를 활용해 연결합니다.
  • Index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Example</title>
  </head>
  <body>
    <script src="./index.js"></script>
  </body>
</html>
  • Index.js
function currentTime() {
  const date = new Date();
  const hours = date.getHours();
  const minutes = date.getMinutes();
  const seconds = date.getSeconds();
  return `${hours}:${minutes}:${seconds}`;
}

const div = document.createElement("div");
document.body.appendChild(div);
setInterval(() => (div.innerText = currentTime()), 1000);

 

 

 

4. 외부라이브러리 사용하기

  • Moment.js라는 라이브러리를 사용해 위 코드를 다시 작성해보겠습니다.
  • index.html 파일에는 Moment.js의 소스파일에 대한 CDN 링크를 추가했고, index.js 파일에는 currentTime() 함수 대신 Moment.js의 format() 함수를 호출하는 1줄짜리 코드로 변경했습니다.
  • index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Example</title>
    <script src="https://unpkg.com/moment@2.22.2/moment.js"></script>
  </head>
  <body>
    <script src="./index.js"></script>
  </body>
</html>
  • index.js
function currentTime() {
  return moment().format("H:m:s");
}

const div = document.createElement("div");
document.body.appendChild(div);
setInterval(() => (div.innerText = currentTime()), 1000);

 

이것이 전통적으로 웹사이트에서 외부 자바스크립트 라이브러리를 사용하는 전형적인 방법입니다.

이러한 상황에서 웹에서도 자바스크립트를 통한 자체적인 외부 모듈 import 기능이 절실해지는 시점입니다.하지만 여기는 여러 단점이 있습니다.

 

  1. Javascript 파일이 HTML파일로부터 완전히 독립할 수 없다.
  2. 여전히 HTML 파일에서 외부 자바스크립트 라이브러리에 대한 의존성이 관리되고 있기 때문에 정작 Javascript 파일은 HTML 파일 없이 정상작동이 불가합니다.
  3. 외부 자바스크립트 라이브러리에 들어있는 모든 변수, 함수, 객체들이 사용여부에 관계 없이 글로벌 네임스페이스를 오염시키게 됩니다.
  4. 외부 라이브러리를 추가적으로 사용할 때마다 HTML 파일을 수정해주어야 합니다.

 

2.2 NPM으로 외부 라이브러리 설치하기

  • 좀 더 체계적으로 예제 프로젝트의 외부라이브러리를 관리하기 위해 Node.js의 패키지 매니저인 NPM을 도입하도록 하겠습니다.
$ npm init -y

{
  "devDependencies": {
    "webpack": "^5.92.1",
    "webpack-cli": "^5.1.4"
  },
  "name": "webpack_test",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": { /*중략*/  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}
  • 그리고 NPM을 활용해 Moment.js 패키지를 설치하도록 하겠습니다.
$ npm i -S moment
+ moment@2.22.2
added 1 package in 6.833s



2.3 ES6 Import/Export

  • ES6는 다른 프로그래밍 언어처럼 하나의 자바스크립트 모듈에서 다른 자바스크립트 모듈을 사용할 수 있도록 import와 export 키워드를 제공합니다.

 

1. 우선 index.html의 CDN 링크를 제거합니다.

<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Example</title>
  </head>
  <body>
    <script src="./index.js"></script>
  </body>
</html>

 

 

2. index.js 파일의 맨 위에 Moment.js 패키지를 임포트 해줍니다.

import moment from "moment";

function currentTime() {
  return moment().format("H:m:s");
}

const div = document.createElement("div");
document.body.appendChild(div);
setInterval(() => (div.innerText = currentTime()), 1000);

 

3. 크롬 브라우저에서 index.html을 실행시킵니다. 

그럼 아래처럼 에러가 뜹니다.

  • 이를 통해 일반 브라우저는 ES6의 import 키워드를 해석할 수 없다는 것을 알게되었습니다.
  • 이를 웹팩을 통해 해결할 수 있습니다.

 

2.4 Webpack과 Webpack CLI 패키지 설치

  • webpack은 웹팩의 핵심 패키지이며, webpack-cli는 터미널에서 webpack 커맨드를 실행할 수 있게 해주는 커맨드라인 도구입니다.
  • 두 패키지 모두 개발환경에서만 필요한 것이기에 -D 옵션을 사용해 설치해줍니다.
$ npm install -D webpack webpack-cli

 

2.5 Webpack Bundle 만들기

  • 프로젝트 디렉터리 안에 소스 디렉터리 (src)와 배포 디렉터리(dist)를 생성합니다.
  • 그리고 index.js를 src 폴더 내로 이동시킵니다.
$ mkdir src dist 
$ mv index.js src/
  • 이후 npx webpack 커맨트를 실행시키면, 웹팩이 소스 디렉터리 안의 index.js 파일과 그 안의 import 되어있던 Moment.js 패키지까지 읽어들여 하나의 번들로 묶은 후 배포 디렉터리 안에 main.js 파일로 떨궈줍니다.
  • 이 과정을 우리는 번들링이라 이야기 합니다.

 

  • 실제로 dist/main.js 파일을 열어보면 웹팩이 소스코드를 최적화 해놓음을 알 수 있습니다.
  • 브라우저가 해석해야 코드의 크기를 줄여주기 때문에 웹 애플리케이션의 성능이 좋아지며, 사람이 읽기 어렴기 때문에 약간의 보안적 이점도 있습니다.

 

2.6 Webpack Bundle 참조하기

  • 이제 index.html 파일이 우리가 작성한 소스코드가 아닌 웹팩이 번들링해준 번들 파일을 참조하도록 수정합니다.
  • index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Webpack Example</title>
  </head>
  <body>
    <script src="./dist/main.js"></script>
  </body>
</html>

3. Javascript 모듈화하기

  • 이제 ES6 모듈 키워드 (import, export)를 사용할 수 있으니 비단 외부 모듈을 사용할 때 뿐만 아니라 프로젝트를 모듈화할 때에도 웹팩을 활용할 수 있을 것입니다.
  • 큰 규모의 프로젝트를 진행할 경우 자바스크립트 코드를 모듈화하면 재활용성, 테스트성, 유지보수성이 향상됩니다.
  • 이렇듯 currentTime 함수를 time.js 파일에 넣고, index.js 파일에서는 currentTime 함수를 Import 하는 방식으로 수정하게 된다면, index.js를 제외한 다른 파일에서도 currentTime 함수를 가져와 사용하는 등 재사용성이 높아집니다.
// time.js
import moment from "moment";

export function currentTime() {
  return moment().format("H:m:s");
}

-------------------------------------------------------
// index.js
import moment from "moment";
import { currentTime } from "./time.js";

const div = document.createElement("div");
document.body.appendChild(div);
setInterval(() => (div.innerText = currentTime()), 1000);

 

  • 소스코드의 모듈 간의 의존성을 정리하면 다음과 같습니다.따라서 HTML 파일은 이 최종 번들파일만 참조할 수 있으며, 이것이 웹팩이 우리에게 가져다 주는 힘입니다.
  • index.js -> time.js -> moment.js
  • 웹팩은 이러한 모듈간의 의존관계를 트리로 구성하며, 하나의 번들 파일로 제공하게 됩니다.

 

저작자표시 (새창열림)

'⚓️ 개발환경' 카테고리의 다른 글

[⚓️Webpack] CRA 없이 웹팩 프로젝트 만들기 | 웹팩의 시대는 끝났나 ? | 웹팩 커스터마이징  (0) 2025.03.11
[개발환경] npm, pnpm, yarn let’s go  (0) 2024.09.02
[⚓️개발환경] 바벨이란 무엇인가?  (2) 2024.08.12
[⚓️개발환경] 프론트엔드 개발에 Node.js가 필요한 이유  (8) 2024.06.25
[⚓️개발환경] Package.json vs Package-lock.json 그리고 Caret, Tilde 등등..  (4) 2024.06.25
'⚓️ 개발환경' 카테고리의 다른 글
  • [개발환경] npm, pnpm, yarn let’s go
  • [⚓️개발환경] 바벨이란 무엇인가?
  • [⚓️개발환경] 프론트엔드 개발에 Node.js가 필요한 이유
  • [⚓️개발환경] Package.json vs Package-lock.json 그리고 Caret, Tilde 등등..
이효린
이효린
  • 이효린
    나는 이효린
    이효린
  • 전체
    오늘
    어제
    • 분류 전체보기 (40)
      • 🩵 React (14)
      • 💛 Javascript (3)
      • ⚓️ 개발환경 (9)
      • ⛓️‍💥 알고리즘 (0)
      • 🤍 ReactNative (1)
      • 🔥 취준일기 (2)
      • 🗂️ 자료구조&알고리즘 (2)
      • 기타 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    React
    -
    MSW
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
이효린
[⚓️개발환경] 웹팩이란 무엇인가
상단으로

티스토리툴바