Module이란 여러 기능들에 관한 코드가 모여있는 하나의 파일이다.
애플리케이션의 규모가 커짐에 따라 JS코드를 여러 파일과 폴더에 나누어 작성하고 서로를 효율적으로 불러올 수 있도록 하는 시스템이 필요했고 이를 해결하기 위해 ES6부터 JS는 모듈 기능을 사용할 수 있게 되었다.
- 유지 보수성
- 코드를 다시 작성하지 않고도 쉽게 의존성을 변경할 수 있다.
- 애플리케이션을 유지 보수할 때 관련 있는 모듈만 업데이트 하면 된다.
- 네임 스페이스
- JS는 파일 스코프가 존재하지 않는다. 변수는 모두 전역변수를 사용하기 때문에 애플리케이션이 커질 수록 변수명이 겹치는 경우가 많아질 수 있다.
- Module은 Module만의 네임 스페이스를 갖고 있기 때문에 위와 같은 문제를 해결할 수 있다.
- 재 사용성
- Module로 분리 시켜 필요할 때마다 다시 재 사용할 수 있다.
-
브라우저별 HTTP 요청 숫자의 제약
- TCP 스펙에 따라 브라우저에서 한 번에 서버로 보낼 수 있는 HTTP 요청 숫자는 제약되어 있다.
- HTTP 요청 숫자를 줄이는 것이 웹 애플리케이션의 성능을 높여줄 뿐만 아니라 사용자가 사이트를 조작하는 시간을 당길 수 있다.
- **프로젝트 규모가 커지면서 많은 모듈을 사용하게 되었고 수 많은 모듈을 일일이 요청하는 것을 피하기 위해 번들러의 필요성이 대두되었다. **
-
트리 쉐이킹, 코드 스플릿, 소스맵, 코드 최적화 필요성 대두 (추후 서술)
애플리케이션을 구성하는 수 많은 자원들을 하나의 파일로 병합 및 압축해주는 동작을 Module Budling이라고 한다.
번들링은 웹 애플리케이션을 동작시키기 위한 자원 (HTML, CSS, JS, Images 등)들을 각각의 모듈로 보고 하나로 묶고 조합해서 하나의 정적인 결과물을 만든다.
- 많은 자원들의 연관관계를 파악한 후, 묶고 조합한다.
- 하나로 묶여있지 않으면, 그만큼 서버에 필요한 자원을 여러번 요청해야 하다.
- 하나로 묶어서 경량화 시켜주면 그만큼 서버에 가하는 부하도 적어지고 로딩시간도 높일 수 있어 성능적으로 유리하다.
또한, 앱에 많은 기능이 필요해질수록 모듈 종속성의 올바른 순서를 추적하고 로드하는 번거로움이 더 커지게 된다.
- 코드 베이스를 모듈로 분할 관리하고 묶어 주어야 한다.
번들러는 애플리케이션에 필요한 모든 모듈을 알아서 매핑하며 매핑된 결과를 가지고 하나 이상의 번들을 생성한다.
{: .prompt-tip }
- 트리 쉐이킹 (Tree Shaking)
- 트리쉐이킹은 최종 번들에서 사용되지 않을 코드를 제거한다.
- 애플리케이션에서 사용되지 않는 코드가 번들에 포함될 수도 있다. 사용되지 않는 코드 조각은 번들 크기를 불필요하게 키우므로 번들 과정에서 제거해야 한다. 이런 과정이 마치 나무 흔들기와 비슷해서 TreeShaking이라고 부른다.
- JS 번들 크기를 줄여 앱의 실행 속도를 향상시킬 수 있다.
- 코드 분할 (Code Spliting)
- 코드 분할은 런타임 중에 나뉘어진 chunk 파일을 동적으로 불러오는 것을 말한다.
- 즉, 사용자가 애플리케이션을 모듈이 필요해지면 번들러가 필요한 하위 번들을 처리한다. (Dinamic Loading, Lazy Loading)
- 앱이 커지면 결국 번들 또한 사이즈가 커진다. 특히 3rd-party 라이브러리를 추가할 때 앱이 더욱 커져서 로드 시간이 길어질 수 있다.
- 번들이 거대해지는 것을 방지하기 위해 좋은 방법은 코드를 나누는 것이다.
- 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여준다.
- 코드 최적화, 소스맵 (Code Optimization, SourceMap)
- 수많은 모듈을 번들하는 동안 수행해야 하는 코드 최적화(코드 압축)를 할 수 있다.
- 번들 파일이 생성되면 브라우저에서 이를 해석하여 처리 하는데, 코드 최적화를 위해 주석, 공백 또는 긴 변수, 함수 이름 등을 모두 축소 또는 제거하여 파일의 크기를 크게 줄일 수 있다. 하지만, 이 코드는 압축되었기에 사람이 읽기 매우 어렵다.
- 사람이 읽기 어려운 코드는 디버깅도 쉽지 않아 코드를 추적 가능한 소스맵을 제공하는 기능이 필요하다.
- 즉, 소스맵은 배포할 때 성능최적화를 위해 압축한 코드를 원본 파일과 연결시켜준다.
웹팩은 가장 많이 사용되는 모듈 번들러이다.
$ npm install webpack webpack-cli -D
$ npm install lodash
<!-- index.html -->
<html>
<head>
<title>Webpack Demo</title>
</head>
<body>
<script src="./dist/main.js"></script>
</body>
</html>
// src/index.js
import _ from "lodash";
function component() {
var element = document.createElement("div");
/* lodash is required for the next line to work */
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
}
document.body.appendChild(component());
// package.json
{
"name": "npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 커스텀 명령어 설정
"build": "webpack --mode=none"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"dependencies": {
"lodash": "^4.17.21"
},
// false 로 설정하면 사용하지 않는 export는 제거해도 괜찮다는 것을 webpack에게 알릴 수 있다.
// TreeShaking
"sideeffects": false
}
- script속성에 build 명령어를 설정한다.
- 만약 build 명령어에
--mode=none
이 설정하지 않고 명령어를 사용하면 다음과 같은 에러 메시지가 뜬다.
# mode를 설정하지 않으면 결과물이 난독화 되어있음.
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
# 스크립트에서 정의한 빌드 명령어
$ npm run build
- build하면 dist 폴더가 생성된다.
- 결과 파일은 dist 폴더 밑의 main.js로 생성되어 있다.
결과물의 파일 경로나 웹 자원의 대상을 지정하고 싶으면 다음과 같이 package.json의 script속성을 수정할 수 있다.
"scripts": {
"build": "webpack --mode=none --entry=src/index.js --output=dist/main.js"
},
그런데 이는 일일이 작성하기 불편하기 때문에 웹팩 설정 파일webpack.config.js
을 사용할 수 있다.
// webpack.config.js
var path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
filename: 'main.js',
// __dirname: 현재 실행 중인 폴더 경로를 의미한다.
path: path.resolve(__dirname, 'dist')
}
};
- path 라이브러리
- output: entry에 있는 파일을 대상으로 webpack을 돌려서 결과물을 만드는 경로를 지정할 수 있다.
- webpack으로 변환한 결과 파일이 저장되는 경로
// package.json의 script 수정
"scripts": {
"build": "webpack"
},
변환 전
변환 후
요청 수가 줄어든 것을 확인할 수 있다. 현재는 라이브러리를 1개만 설치해서 큰 효과가 없지만 프로젝트 규모가 커질 수록 효과는 클 것이다.