webpack이란?
최근 몇 년동안 웹 개발은 소수의 애셋과 약간의 자바스크립트가 포함된 페이지에서 복잡한 자바스크립트와 대규모 의존성 트리(여러 파일이 여러 다른 파일에 의존하는)가 포함된 다양한 기능을 갖춘 웹 애플리케이션으로 발전했습니다.
개발자 커뮤니티에는 이러한 복잡성에 대응하기 위해 다음과 같은 방법을 고안했습니다.
- 한 프로그램을 여러 파일로 분할하고 구성할 수 있는 자바스크립트 모듈
- 향후 자바스크립트에서 제공될 기능을 미리 이용할 수 있게 해주는 자바스크립트 전처리기와 자바스크립트로 컴파일되는 언어(예: 커피스크립트)
이러한 방법은 아주 유용하지만 파일을 브라우저가 이해할 수 있도록 번들로 묶고 변환(트랜스파일 및 컴파일)하는 이전에는 없던 추가 단계를 거쳐야 이용할 수 있습니다. 이 때문에 webpack과 같은 도구가 필요해졌습니다.
webpack 은 프로젝트의 구조를 분석하고 자바스크립트 모듈을 비롯한 애셋을 찾은 다음 이를 브라우저에서 이용할 수 있는 번들로 묶고 패킹하는 모듈 번들러입니다.
grunt나 gulp와 같은 빌드 도구와의 차이점
webpack은 빌드 툴이 아니므로 grunt나 gulp 등의 태스크 러너나 빌드 시스템과는 다르지만 이러한 툴을 대체하면서 장점을 제공할 수 있습니다.
grunt나 gulp 같은 빌드 툴은 정의한 경로에서 구성과 일치하는 파일을 찾습니다. 따라서 구성 파일에서 이러한 파일을 변환, 조합 및/또는 축소minify하는 작업이나 단계를 지정해야 합니다.
- 소스 폴드(자바스크립트 ES6)
- 폴더에서 모든 파일을 읽음
- 첫 번째 작업(플러그인)을 통해 파일을 처리
- JS(ES5)로 트랜스파일
- 파일을 저장하거나 다음 작업으로 전달
- JS 모듈을 번들로 묶음
- 파일 저장
- 번들로 묶은 자바스크립트 파일
이와 달리 webpack은 프로젝트 전체를 한 단위로 분석합니다. 즉, 지정한 메인 파일에서 시작해 자바스크립트의 require와 import 문을 참고해 프로젝트의 모든 의존성을 조사하고 로더를 이용해 처리한 후 묶은 자바스크립트 파일을 생성합니다.
webpack의 방식이 더 빠르고 직관적입니다. 또한 다른 파일 형식까지 번들로 묶을 수 있는 방법을 제공합니다.
로더
webpack의 가장 흥미로운 기능 중 하나인 로더를 이용하면 외부 스크립트와 도구를 통해 소스 파일을 전처리하고 다양한 변경과 변환을 적용할 수 있습니다. 이러한 변환은 JSON 파일을 일반 자바스크립트로 구문 분석하거나, 차세대 자바스크립트 코드를 현재 브라우저가 이해할 수 있는 일반 자바스크립트로 변환해 먼저 이용할 수 있게 하는 등 다양한 상황에서 유용합니다. 로더는 리액트의 JSX를 일반 자바스크립트로 변환하는 데도 이용할 수 있으므로 리액트 개발에도 중요합니다.
로더는 별도로 설치해야 하며, webpack.config.js의 “modules” 키에서 구성해야 합니다. 로더 구성 설정에는 다음과 같은 항목이 있습니다.
- test: 이 로더로 처리하기 위해 일치해야 하는 파일 확장자를 비교하는 정규 표현식(필수)
- loader: 로더의 이름(필수)
- include/exclude: 로더가 명시적으로 추가하거나 무시할 폴더와 파일을 수동으로 지정하는 옵션 설정
- query: 로더로 추가 옵션을 전다하는 데 이용되는 쿼리 설정
이번에는 인사말 텍스트를 별도의 JSON 구성 파일로 옮겨보겠습니다. 먼저 웹팩의 JSON 로더 모듈을 설치합니다.
npm install --save json-loader
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {...},
module: {
loaders: [
{
test: /\.json$/,
loader: "json"
}
]
},
devServer: {
contentBase: "./public",
colors: true,
historyApiFallback: true,
inline: true
}
}
마지막으로 config.json 파일을 만들고 Greeter에서 이 파일을 가져오게 합니다.
// config.json
{
"greetText": "Hi there and greetings from JSON!"
}
// greeter.js
var config = require('./config.json');
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = config.greetText;
return greet;
}
바벨
바벨은 자바스크립트 컴파일과 도구 지원을 위한 플랫폼으로서 다음과 같은 기능을 제공합니다.
- 아직 일부 브라우저에서 지원되지 않은 자바스크립트의 버전(ES6, ES6 등)을 이용할 수 있게 해줍니다.
- React의 JSX와 같은 자바스크립트 구문 확장을 이용할 수 있게 해줍니다.
바벨은 독립 실행형 도구지만 로더로 이용할 수 있으며, 웹팩과 아주 잘 어울립니다.
설치와 구성
바벨은 모듈형 구조를 띠며, 다양한 npm 모듈로 배포됩니다. 핵심 기능은 ‘babelcore’ npm 패키지로 제공되며, 웹팩과의 통합은 ‘babel-loader’ npm 패키지로 제공됩니다. 또한 코드에서 이용하려는 기능과 확장 유형마다 각기 다른 패키지를 설치해야 합니다. 많이 사용되는 패키지로는 ES6 컴파일을 위한 babel-preset-es2015와 React JSX 지원을 위한 babel-preset-react가 있습니다.
이러한 패키지를 모두 개발 의존성으로 설치하려면 다음 명령을 이용할 수 있습니다.
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
다른 웹팩 로더와 마찬가지로 바벨도 웹팩 구성 파일의 모듈 섹션에서 구성할 수 있습니다.
// webpack.config.js
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {...},
module: {
loaders: [
{
test: /\.json$/,
loader: "json"
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
},
devServer: {
contentBase: "./public",
colors: true,
historyApiFallback: true,
inline: true
}
}
이제 바벨을 이용해서 ES6모듈과 구문을 이용할 수 있으니 JSX까지 이용해서 예제 코드를 작성해 보겠습니다. 바벨을 설치 및 구성하고 React와 React-DOM을 설치합니다.
npm install --save react react-dom
// Greeter.js
import React, {Component} from 'react';
import config from './config.json';
class Greeter extends Component {
render() {
return (
<div>
{config.greetText}
</div>
);
}
}
export default Greeter
다음으로 ES6 모듈 정의를 이용하고 Greeter 리액트 컴포넌트를 렌더링하도록 main.js 파일을 업데이트합니다.
// main.js
import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';
render(<Greeter />, document.getElementById('root'));
바벨 구성 파일
바벨을 webpack.config.js에서 완전히 구성할 수도 있지만 구성 설정과 옵션, 조합이 매우 다양하기 때문에 동일한 파일 안에서 모든 구성을 처리하려면 지나치게 복잡해질 수 있습니다. 이 때문에 ‘.babelrc’라는 별도의 바벨 리소스 구성을 만드는 경우가 많습니다.
지금까지 사용한 바벨 전용 구성은 프리셋 정의뿐이므로 이 항목만 포함하는 바벨 전용 구성 파일을 따로 만드는 것이 과하게 보일 수 있습니다. 그러나 바벨 전용 구성을 만들어 놓으면 사용면에서 편리합니다. 먼저 프리셋 구성을 webpack.config.js 파일에서 분리해 기본 로더 설정만 남겨놓습니다.
// 바벨 프리셋 정의를 제거한 웹팩 구성
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {...},
module: {
loaders: [
{
test: /\.json$/,
loader: "json"
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
}
]
},
devServer: {...}
}
이어서 바벨의 프리셋 구성을 포함하는 ‘.babelrc’라는 파일을 만듭니다.
{
"presets": ["react", "es2015"]
}