
[0. 모듈화의 필요성]
자바스크립트는 script 태그를 통해 외부의 스크립트 파일을 가져올 수 있다.
하지만 파일마다 독립적인 파일 스코프를 가지지 않고 하나의 전역 객체를 공유한다.
예를 들어, 두 개의 js 파일을 스크립트 태그에 넣는다고 가정해 보자.
<!DOCTYPE html>
<html>
<head> </head>
<body>
<script src="./src/math.js"></script>
<script src="./src/app.js"></script>
</body>
</html>
자바스크립트는 가장 뒤에 있는 스크립트를 기준으로 변수명을 적용하게 된다.
// math.js
function sum(x, y) {
return x + y;
}
// app.js
sum(1, 2);
console.log(sum(1, 2)); // 3
위와 같이 코드가 작성되었을 때, 만약 app.js에서 sum이 재정의되면 어떻게 될까?
// math.js
function sum(x, y) {
return x + y;
}
// app.js
sum = 1;
sum(1, 2); // Uncaught TypeError: sum is not a function
console.log(sum(1, 2));
sum의 정의는 뒤에 불러온 app.js의 선언을 따르기 때문에 sum 함수를 사용할 수 없다.
이렇게 각 파일을 개별적으로 불러오더라도 같은 스코프로 판단되어 변수명 중복이 일어나는 문제를 해결하기 위한 많은 시도가 있었다.
[1. CommonJS]
CommonJS는 Javascript를 브라우저 뿐 아니라 서버사이드 애플리케이션 혹은 데스크탑 애플리케이션에서도 사용하기 위해 조직한 자발적 워킹 그룹이다.
Javascript를 브라우저 외에서 사용할 수 있게 하려면 다음과 같은 문제들의 해결이 필요했다.
- 서로 호환되는 표준 라이브러리의 부재
- 데이터베이스에 연결할 수 있는 표준 인터페이스의 부재
- 다른 모듈을 삽입하는 표준적인 방법의 부재
- 코드를 패키징하고, 배포하고, 설치하는 방법의 부재
- 의존성 문제를 해결하는 공통 패키지 모듈의 부재
위 문제점들을 모두 해결하는 방법은 코드를 모듈화하고, 그 방식을 표준화하는 것이었기 때문에 자연스럽게 JS의 모듈화에 관심이 쏠리게 된다.
CommonJS는 각 파일을 모듈화하고 'exports'로 정의한 후 필요한 곳에서 'require' 키워드를 사용해 불러옴으로서 변수명이 겹치는 문제를 해결했다.
아래는 여러 모듈을 합쳐 활용하는 예시이다.
// hello.js
module.exports = 'Hello';
// world.js
module.exports = 'World';
//greetings.js
var greeting = require('./hello') + require('./world');
module.exports = greeting;
// app.js
alert(require('./greeting'));
위와 같이 여러 모듈을 합쳐 하나의 모듈에서 사용하고, 그 모듈을 다른 곳에서 불러오는 식으로 사용이 가능하다.
CommonJS 모듈은 기본적으로 Javascript를 서버사이드 애플리케이션에서 사용할 수 있도록 하기 위해 설계되었기 때문에 동기적으로 동작한다.
즉, 모듈의 내용을 모두 실행한 후 다음 코드를 실행한다.
파일 시스템 접근 및 네트워크 요청 등의 작업은 순서를 지켜 동기적으로 수행하는 것이 가장 중요하기 때문이다.
따라서 모든 파일이 로컬에 존재하는 경우(서버사이드)에서는 CommonJS 명세가 간결하다.
[2. AMD]
AMD(Asynchronous Module Definition)은 비동기 상황에서도 JavaScript 모듈을 사용하기 위해 CommonJS에서 함께 논의하다 의견의 불일치로 독립한 그룹으로 비동기 모듈에 대한 표준안을 다룬다.
AMD 명세에서는 기본 경로와 각 모듈에 해당하는 경로, 각 모듈이 동작하기 위해 필요한 모듈(의존성 모듈)을 지정해줌으로서 각 모듈의 의존성 모듈이 모두 로드되면 해당 모듈도 바로 로드될 수 있도록 한다.
CommonJS는 동기적으로 모듈을 로드하기 때문에 웹에서 네트워크 지연 등의 문제가 발생하면 속도가 현저하게 느려지게 되지만, AMD는 비동기적으로 파일을 로드하기 때문에 웹 애플리케이션의 속도 향상에 도움이 된다.
따라서 브라우저 환경에서는 AMD가 CommonJS보다 유리하다고 볼 수 있다.
[3. webpack]
webpack은 위 CommonJS와 AMD 명세를 모두 지원하는 번들러이다.
Javascript 파일을 포함해 다양한 웹 리소스(CSS 파일, 이미지 파일, JSON 파일)등을 모듈화하여 의존성을 해결하고 단일 번들 파일로 결합해 브라우저 로딩 속도를 단축시킬 수 있다.
webpack은 다음과 같은 6개의 핵심 개념이 존재한다.
- Entry(엔트리)
- Output(출력)
- Loaders(로더)
- Plugins(플러그인)
- Mode(모드)
- Browser Compatibility(브라우저 호환성)
[3-1. Entry]
// webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
webpack을 사용하기 위해서는 진입점(Entry Point) 모듈을 설정해주어야 한다.
webpack은 진입점 모듈로부터 시작하여 애플리케이션을 빌드하는 데 필요한 모든 모듈들을 의존성 그래프에 추가하여 재귀적으로 빌드한다.
이 과정에서 필요하지 않다고 판단된 코드(의존성 그래프에 포함되지 않은 코드)를 빌드에서 제외한다.
이를 트리 쉐이킹이라고 한다.
그 후 빌드된 모든 모듈들을 작은 수(보통 하나)의 번들로 묶는다.


[3-2. Output]
// webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
Output 속성은 생성한 번들을 내보낼 위치와 그 파일의 위치를 지정한다.
기본 출력 파일은 ./dist/main.js, 기타 파일의 경우에는 ./dist 폴더에 저장된다.
[3-3. Loaders]
webpack은 기본적으로 Javascript와 JSON 파일만 이해한다.
따라서 로더를 설정해 webpack이 다른 유형의 파일을 처리해 애플리케이션에서 사용하게 하거나, 모듈로 변환해 의존성 그래프에 추가한다.

// webpack.config.js
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
위 예시 코드의 rules 속성은 다음을 의미한다.
require() 또는 import문 내에서 .txt 파일을 발견하면 번들링하기 전에 raw-loader를 사용해 변환
[3-4. Plugins]
로더는 특정 파일을 관리하는 데 사용한다면, 플러그인은 번들 최적화, 에셋 관리, 환경 변수 주입 등 광범위한 작업을 수행하는 데 사용한다.
여기에서 기본 지원 플러그인 목록을 확인할 수 있다.
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 내장 plugin에 접근하는 데 사용
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
위 설정에서 HtmlWebpackPlugin은 생성된 모든 번들을 자동으로 삽입하여 애플리케이션용 HTML 파일을 생성한다.
[3-5. Mode]
mode 파라미터는 development, production, none 세 가지로 설정 가능하며, 각 설정별로 webpack에 내장된 환경 별 최적화를 활성화한다. 기본값은 production이다.
// webpack.config.js
module.exports = {
mode: 'production',
};
// 각 모드에 대해 어느 부분이 달라지는지는 추가 공부 필요
development | DefinePlugin의 process.env.NODE_ENV를 development로 설정합니다. 모듈과 청크에 유용한 이름을 사용할 수 있습니다. |
production | DefinePlugin의 process.env.NODE_ENV를 production으로 설정합니다. 모듈과 청크, FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, TerserPlugin 등에 대해 결정적 망글이름(mangled name)을 사용할 수 있습니다. |
none | 기본 최적화 옵션에서 제외 |
[3-6. Browser Compatibility]
webpack은 ES5가 호환되는 모든 브라우저를 지원한다.
- Chrome
- IE (9.0 이상)
- Edge
- FireFox
- Safari
- Opera

[0. 모듈화의 필요성]
자바스크립트는 script 태그를 통해 외부의 스크립트 파일을 가져올 수 있다.
하지만 파일마다 독립적인 파일 스코프를 가지지 않고 하나의 전역 객체를 공유한다.
예를 들어, 두 개의 js 파일을 스크립트 태그에 넣는다고 가정해 보자.
<!DOCTYPE html>
<html>
<head> </head>
<body>
<script src="./src/math.js"></script>
<script src="./src/app.js"></script>
</body>
</html>
자바스크립트는 가장 뒤에 있는 스크립트를 기준으로 변수명을 적용하게 된다.
// math.js
function sum(x, y) {
return x + y;
}
// app.js
sum(1, 2);
console.log(sum(1, 2)); // 3
위와 같이 코드가 작성되었을 때, 만약 app.js에서 sum이 재정의되면 어떻게 될까?
// math.js
function sum(x, y) {
return x + y;
}
// app.js
sum = 1;
sum(1, 2); // Uncaught TypeError: sum is not a function
console.log(sum(1, 2));
sum의 정의는 뒤에 불러온 app.js의 선언을 따르기 때문에 sum 함수를 사용할 수 없다.
이렇게 각 파일을 개별적으로 불러오더라도 같은 스코프로 판단되어 변수명 중복이 일어나는 문제를 해결하기 위한 많은 시도가 있었다.
[1. CommonJS]
CommonJS는 Javascript를 브라우저 뿐 아니라 서버사이드 애플리케이션 혹은 데스크탑 애플리케이션에서도 사용하기 위해 조직한 자발적 워킹 그룹이다.
Javascript를 브라우저 외에서 사용할 수 있게 하려면 다음과 같은 문제들의 해결이 필요했다.
- 서로 호환되는 표준 라이브러리의 부재
- 데이터베이스에 연결할 수 있는 표준 인터페이스의 부재
- 다른 모듈을 삽입하는 표준적인 방법의 부재
- 코드를 패키징하고, 배포하고, 설치하는 방법의 부재
- 의존성 문제를 해결하는 공통 패키지 모듈의 부재
위 문제점들을 모두 해결하는 방법은 코드를 모듈화하고, 그 방식을 표준화하는 것이었기 때문에 자연스럽게 JS의 모듈화에 관심이 쏠리게 된다.
CommonJS는 각 파일을 모듈화하고 'exports'로 정의한 후 필요한 곳에서 'require' 키워드를 사용해 불러옴으로서 변수명이 겹치는 문제를 해결했다.
아래는 여러 모듈을 합쳐 활용하는 예시이다.
// hello.js
module.exports = 'Hello';
// world.js
module.exports = 'World';
//greetings.js
var greeting = require('./hello') + require('./world');
module.exports = greeting;
// app.js
alert(require('./greeting'));
위와 같이 여러 모듈을 합쳐 하나의 모듈에서 사용하고, 그 모듈을 다른 곳에서 불러오는 식으로 사용이 가능하다.
CommonJS 모듈은 기본적으로 Javascript를 서버사이드 애플리케이션에서 사용할 수 있도록 하기 위해 설계되었기 때문에 동기적으로 동작한다.
즉, 모듈의 내용을 모두 실행한 후 다음 코드를 실행한다.
파일 시스템 접근 및 네트워크 요청 등의 작업은 순서를 지켜 동기적으로 수행하는 것이 가장 중요하기 때문이다.
따라서 모든 파일이 로컬에 존재하는 경우(서버사이드)에서는 CommonJS 명세가 간결하다.
[2. AMD]
AMD(Asynchronous Module Definition)은 비동기 상황에서도 JavaScript 모듈을 사용하기 위해 CommonJS에서 함께 논의하다 의견의 불일치로 독립한 그룹으로 비동기 모듈에 대한 표준안을 다룬다.
AMD 명세에서는 기본 경로와 각 모듈에 해당하는 경로, 각 모듈이 동작하기 위해 필요한 모듈(의존성 모듈)을 지정해줌으로서 각 모듈의 의존성 모듈이 모두 로드되면 해당 모듈도 바로 로드될 수 있도록 한다.
CommonJS는 동기적으로 모듈을 로드하기 때문에 웹에서 네트워크 지연 등의 문제가 발생하면 속도가 현저하게 느려지게 되지만, AMD는 비동기적으로 파일을 로드하기 때문에 웹 애플리케이션의 속도 향상에 도움이 된다.
따라서 브라우저 환경에서는 AMD가 CommonJS보다 유리하다고 볼 수 있다.
[3. webpack]
webpack은 위 CommonJS와 AMD 명세를 모두 지원하는 번들러이다.
Javascript 파일을 포함해 다양한 웹 리소스(CSS 파일, 이미지 파일, JSON 파일)등을 모듈화하여 의존성을 해결하고 단일 번들 파일로 결합해 브라우저 로딩 속도를 단축시킬 수 있다.
webpack은 다음과 같은 6개의 핵심 개념이 존재한다.
- Entry(엔트리)
- Output(출력)
- Loaders(로더)
- Plugins(플러그인)
- Mode(모드)
- Browser Compatibility(브라우저 호환성)
[3-1. Entry]
// webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
webpack을 사용하기 위해서는 진입점(Entry Point) 모듈을 설정해주어야 한다.
webpack은 진입점 모듈로부터 시작하여 애플리케이션을 빌드하는 데 필요한 모든 모듈들을 의존성 그래프에 추가하여 재귀적으로 빌드한다.
이 과정에서 필요하지 않다고 판단된 코드(의존성 그래프에 포함되지 않은 코드)를 빌드에서 제외한다.
이를 트리 쉐이킹이라고 한다.
그 후 빌드된 모든 모듈들을 작은 수(보통 하나)의 번들로 묶는다.


[3-2. Output]
// webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
Output 속성은 생성한 번들을 내보낼 위치와 그 파일의 위치를 지정한다.
기본 출력 파일은 ./dist/main.js, 기타 파일의 경우에는 ./dist 폴더에 저장된다.
[3-3. Loaders]
webpack은 기본적으로 Javascript와 JSON 파일만 이해한다.
따라서 로더를 설정해 webpack이 다른 유형의 파일을 처리해 애플리케이션에서 사용하게 하거나, 모듈로 변환해 의존성 그래프에 추가한다.

// webpack.config.js
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
위 예시 코드의 rules 속성은 다음을 의미한다.
require() 또는 import문 내에서 .txt 파일을 발견하면 번들링하기 전에 raw-loader를 사용해 변환
[3-4. Plugins]
로더는 특정 파일을 관리하는 데 사용한다면, 플러그인은 번들 최적화, 에셋 관리, 환경 변수 주입 등 광범위한 작업을 수행하는 데 사용한다.
여기에서 기본 지원 플러그인 목록을 확인할 수 있다.
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 내장 plugin에 접근하는 데 사용
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
위 설정에서 HtmlWebpackPlugin은 생성된 모든 번들을 자동으로 삽입하여 애플리케이션용 HTML 파일을 생성한다.
[3-5. Mode]
mode 파라미터는 development, production, none 세 가지로 설정 가능하며, 각 설정별로 webpack에 내장된 환경 별 최적화를 활성화한다. 기본값은 production이다.
// webpack.config.js
module.exports = {
mode: 'production',
};
// 각 모드에 대해 어느 부분이 달라지는지는 추가 공부 필요
development | DefinePlugin의 process.env.NODE_ENV를 development로 설정합니다. 모듈과 청크에 유용한 이름을 사용할 수 있습니다. |
production | DefinePlugin의 process.env.NODE_ENV를 production으로 설정합니다. 모듈과 청크, FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, TerserPlugin 등에 대해 결정적 망글이름(mangled name)을 사용할 수 있습니다. |
none | 기본 최적화 옵션에서 제외 |
[3-6. Browser Compatibility]
webpack은 ES5가 호환되는 모든 브라우저를 지원한다.
- Chrome
- IE (9.0 이상)
- Edge
- FireFox
- Safari
- Opera