본문 바로가기
Javascript

웹팩(Webpack) 이란, 웹팩 간단 정리 및 리액트(React) 기본 개발환경 세팅. [1]

by 램쥐뱅 2017. 6. 20.

Front-End 단 개발에서 React.js , Vue.js .. 등을 사용할 때 Node.js, Webpack 을 설치하라느니 뭔가 복잡해 보이는데 사실 뭐 없다.



웹팩이란 ?


최근 몇 년동안 웹 개발은 매우 작은 리소스들과 약간의 자바스크립트가 포함된 웹페이지를 시작으로, 복잡한 자바스크립트와 대규모 의존성 트리를 가지고 있는 다양한 기능을 갖춘 웹 애플리케이션으로 발전했다.

이러한 복잡성에 대응하기 위해 아래와 같은 방법을 고안했다.


한 프로그램으로 작동하는 하나의 파일을 여러 파일로 분할하고 구성할 수 있는 자바스크립트 모듈


향후 자바스크립트에서 제공될 기능을 미리 이용할 수 있게 해주는 자바스크립트 전처리기(pre-processor)와 자바스크립트로 컴파일되는 언어 (ex. CoffeeScript, TypeScript)


이러한 방법은 아주 유용하지만 파일을 브라우저가 이해할 수 있도록 번들로 묶고 변환(트랜스파일 및 컴파일)하는 이전에는 없던 추가 단계를 거쳐야 이용이 가능하다.


이 때문에 웹팩과 같은 도구가 필요해졌다.


웹팩은 프로젝트의 구조를 분석하고 자바스크립트 모듈을 비롯한 관련 리소스들을 찾은 다음 이를 브라우저에서 이용할 수 있는 번들로 묶고 패킹하는 모듈 번들러(Module bundler)다.




그런트나 걸프와 같은 빌드 도구와의 차이점


웹팩은 빌드 툴이 아니므로 그런트(Grunt)나 걸프(Gulp) 등의 태스크 러너나 빌드 시스템과는 다르지만, 이러한 툴을 대체하면서 장점을 제공할 수 있다.


그런트나 걸프 같은 빌드 툴은 정의한 경로에서 구성과 일치하는 파일을 찾는다. 따라서 구성 파일에서 이러한 파일을 변환, 조합 및 축소 하는 작업이나 단계를 지정해야 한다.



이와 달리 웹팩은 프로젝트 전체를 한 단위로 분석한다. 즉, 지정한 메인 파일에서 시작해 자바스크립트의 require(webpack commonJS 모듈 지원)과 import(ES6)문을 참고해 프로젝트의 모든 의존성을 조사하고 로더를 이용해 처리한 후 번들로 묶은 자바스크립트 파일을 생성한다.



웹팩의 방식이 더 빠르고 직관적이다. 또한 웹팩은 js이외 다른 파일 형식까지 번들로 묶을 수 있는 방법을 제공한다.




시작하기


웹팩은 Node.js 가 설치된 환경에서 실행된다.

웹팩은 npm (Node Package Manager) 로 설치할 수 있다.


npm은 Node.js를 설치하면 사용할수 있는 말그대로 사용가능한 패키지들을 다운받고 편리하게 사용할수 있게 관리해주는 프로그램이다.

공식 사이트에 아주 잘 나와있다.




Node.js 를 간단하게 설명 하자면. 역시 공식 사이트에 잘 설명이 되어있다.



간단히 말하면 JavaScript 를 확장해서 뭔가 서버로 사용할수 있게 만들어 놓은 JavaScript Server 이다.

Node.js의 패키지 생태계안에 포함되어 있는 npm을 이용해 잘 만들어 져 있는 Webpack 모듈 번들러를 내려받으면 된다. 


npm install -g webpack : 전역에서 webpack을 사용할 때

npm install --save-dev webpack : 특정 의존성으로 설치할 때 




예제 프로젝트


에제 프로젝트를 시작해볼 비어 있는 폴더 위치에서 package.json 파일을 먼저 만들어준다.

package.json 파일은 내가 만들 프로젝트 설정과 사용하는 패키지들 등의 다향한 정보를 포함하는 표준 npm 매니페스트이며, 개발자가 패키지 의존성을 지정하고 사용자가 실행할수 있는 스크립트 태스크들을 정의할 수 있게 해준다.

package.json 파일을 생성하려면 터미널에서 다음 명령을 실행 한다.


npm init


init 명령은 만들 프로젝트에 대해 여러 질문들을 표시할 것이다. 입력하거나 default를 사용하면 된다.


package.json 파일을 생성한 후 다음과 같이 웹팩을 프로젝트 의존성으로 추가하고 설치할수 있다.

--save 파라미터가 사용되면 설치하는 패키지의 의존성이 package.json에 자동으로 추가 되어 향후에 바로 설치할 수 있다.


npm install --save-dev webpack


모든 과정을 마친후에는 프로젝트 구조를 만들 차례이다.

예제 프로젝트는 자바스크립트 모듈이 들어있는 "app" 폴더와 브라우저에서 사용할 준지가 끝난 파일 (index.html, 번들 자바스크립트 파일)이 들어있는 "public"폴더로 구성할 것이다.


webpack sample project

                 ⌞  node_modules

  ⌞  app

    ⌞  Greeter.js

    ⌞  main.js

      public

  index.html

  ⌞  package.json

  


index.html에는 번들 자바스크립트 페이지를 로드하는 역할을 하는 아주 기본적인 HTML 페이지가 들어있다.


index.html

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8"/>

<title>Webpack Sample Project</title>

</head>

<body>

<div id="root"></div>

<script src="./bundle.js"></script>

</body>

</html>


main.js

var greeter = require('./Greeter.js'); //웹팩은 commonJS 모듈 require을 기본적으로 지원한다

document.getElementById('root').appendChild(greeter());


Greeter.js

module.exports = function() {

var greet = document.createElement('div');

greet.innerHTML = "Hi there and greetings !";

return greet;

}




첫 번째 빌드 실행


웹 팩의 기본 명령줄 입력 구문은 "webpack {엔트리 파일} {번들 파일의 대상}" 이다. 

엔트리 파일은 하나만 지정해야 하며, 웹팩이 지정한 엔트리를 시작으로 모든 프로젝트 의존성을 자동으로 파악한다.


웹팩을 전역으로 설치하지 않은경우 다음처럼 실행하면된다.


node_modules/.bin/webpack app/main.js public/bundle.js



웹팩이 main.js 와 Greeter.js JS 모듈 파일들을 bundle.js로 묶었다. 이제 브라우저에서 index.html 파일을 열어보면 다음과 같은 결과를 확인할수 있다.





구성 파일 정의


웹팩은 다양한 고급 옵션을 제공하며, 로드한 모듈들에 로더와 플러그인을 이용해 변환을 적용할 수 있게 해준다.

위에서 해봤듯이 명령줄에서 모든 옵션을 지정하고 웹팩을 실행하는 것도 가능하지만, 작업하기 불편하고 매번 수동으로 입력하면 잘못된 입력의 가능성이 높아진다. 때문에 빌드와 관련된 모든 정보를 넣을 수 있는 간단한 자바스크립트 모듈인 구성 파일을 따로 정의하는 것이 좋다.


계속해서 예제 프로젝트의 구성 파일로 사용할 webpack.config.js 파일을 만들어 본다.

웹팩 구성 파일은 최소한 아래 처럼 엔트리 파일과 번들로 묶일 파일의 대상을 지정해야 한다.


최소한의 webpack.config.js

module.exports = {

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

}

}


//__dirname은 현재 실행 중인 스크립트가 있는 디덱터리 이름을 포함하는 node.js 전역변수다.


이제부터는 터미널에서 간단하게 별다른 매개변수 없이 'webpack'을 실행할 수 있다. webpack.config.js 파일이 있으므로 웹펙은 이 파일에 있는 구성을 바탕으로 애플리케이션을 빌드한다.





태스크 실행 스크립트 추가


전역으로 설치하지 않았다면 node_modules/.bin/webpack 과 같은 긴 명령은 입력하기 번거롭고 잘못 입력할 가능성도 있다.

npm을 태스크 러너로 사용해 긴 스크립트를 npm start, npm run {지정한 이름} 과 같은 간단한 명령으로 대체할 수 있다. package.json 파일 안에 scripts 섹션을 추가하면 된다.


start 스크립트가 추가된 package.json 파일

{

"name" : "webpack-sample-project",

"version" : "1.0.0",

"description" : "Sample webpack project",

"scripts" : {

"start" : "node_modules/.bin/webpack",

"my_start" : ...

},

"author" : "C ssio Zen",

"license" : "ISC",

"devDependencies" : {

"webpack" : "^1.12.9"

}

}


start는 npm start 명령으로 실행할 수 있는 특수한 스크립트 이름이다. 다른 스크립트 이름으로 만들어도 되지만 실행할 때 npm run {지정한 이름} (npm run my_start)형식을 이용해야 한다.





소스맵 생성


웹펙을 구성하는데 몇 가지 옵션이 사용되는데, 가장 중요하고 많이 사용되는 소스맵 옵션이다.


패키지의 모든 자바스크립트 모듈을 하나 또는 여러개의 모듈들이 합쳐진 번들 파일로 만들어 브라우저에서 사용하면 많은 장점이 있지만 브라우저에서 디버깅할 때 원래 어떤 파일의 어떤 부분에서 문제가 생겼는지 찾기가 어렵다는 한 가지 분명한 단점이 있다.

이 문제를 해결하기 위해 웹팩의 소스맵(soruce map)을 이용할 수 있다.

소스맵은 번들 파일 내의 코드를 원래 소스 파일로 연결함으로써 브라우저 인스펙터에서 코드를 일고 디버그하기 쉽게 만들어 준다. 


표로 몇가지 빌드 시간이 가장 느린 것부터 빠른 것 순으로 옵션을 정렬해본다면 아래와 같다.


 devtool 옵션 

 설명 

 source-map

 모든 기능이 포함된 완전한 소스맵을 별도의 파일로 생성한다. 

 이 옵션은 최고 품질의 소스맵을 생성하지만 빌드 프로세스가 느려진다. 

 cheap-module-source-map

 별도의 파일에 컬럼 매핑을 제외한 소스 맵을 생성한다.

 컬럼 매핑을 생략하면 빌드 속도는 향상되지만 디버깅할 때는 약간의 불편함이 있다.

 브라우저 개발자 툴은 원래 소스 파일의 행만 가리킬 수 있으며,

 특정 컬럼(또는 문자)을 가리킬 수 없다.

 eval-source-map

 "eval"을 사용해 동일한 파일 안에 전체 소스맵과 소스코드 모듈을 중첩해 번들로 만든다.

 이 옵션을 사용하면 빌드 시간에 대한 부담 없이 모든 기능이 포함된 소스맵을 생성할 수 있지만

 자바스크립트를 실행할 때 성능과 보안이 저하되는 단점이 있다.

 즉, 개발 중에는 유용하지만 실무 버전을 빌드할 때는 사용하지 말아야 한다.

 cheap-module-eval-source-map

 빌드 중에 소스 맵을 생성하는 가장 빠른 방법이다. 

 생성되는 소스맵에는 번들 자바스크립트 파일이 칼럼 매핑을 제외하고 동일하게 인라인으로

 포함된다. 이전 옵션과 마찬가지로 자바스크립트 실행 시간에 부정적인 영향을 미치므로

 실무용 번들을 생성할 때는 적합하지 않다. 

표에 정리한 옵션들 이외의 옵션들은 웹팩 공식홈페이지에서 확인할 수 있다.


맨 위 옵션은 약간의 단점을 감수하고 최상을 결과를 출력하는 반면 맨 아래 옵션은 빌드 시간을 단축하기 위해 자바스크립트 실행하는 동안 단점을 감수해야 한다.


기능에 대해 알아보고 있거나 중소규모 프로젝트에 적용할 때는 "eval-source-map"이 적절한 옵션이다. 실무용 번들을 빌드하는 webpack.config.js를 별도로 가져갈 수 있으므로 개발중에만 적절하게 사용할 수 있다.


업데이트된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

}

}




웹팩 개발 서버


웹팩은 로컬 개발을 위한 웹팩 개발 서버라는 서버를 옵션으로 제공한다.

웹팩 개발 서버는 정적 파일을 제공하며, 웹팩 구성에 따라 스크립트들을 빌드한 후 메모리에 저장했다가 개발자가 소스 파일을 수정하면 자동으로 브라우저를 새로 고치는 간단한 node.js 익스프레스 앱이다.

웹팩 개발 서버는 별도의 npm 모듈이므로 프로젝트의 의존성으로 설치해야 이용할 수 있다.


npm install --save-dev webpack-dev-server


웹팩 개발 서버는 webpack.config.js 구성 파일의 별도 "devserver" 항목으로 구성할 수 있다.



 devserver 설정

 설명

 contentBase

 기본적으로 웹팩 개발 서버는 프로첵트 루트에 있는 파일을 서비스 한다.

 다른 폴더 (ex. 예제에서 사용하는 public 폴더)의 파일을 서비스 하려면 이 설정으로 특정 contentBase를

 잡아주어야 한다.

 port

 사용할 포트를 지정하며, 생략할 경우 기본값은 "8080"이다

 inline

 "true"로 설정하면 조그만한 클라이언트 엔트리를 번들에 삽입해 페이지가 변경되면 새로 고침을 수행한다.

 colors

 서버가 터미널에 출력하는 내용에 색상을 지정한다. 

 historyApiFallback

 HTML5 히스토리 API를 이용하는 단일 페이지 애플리케이션을 개발할 때 유용한 옵션으로서 "true"로 설정하면

 기존 스크립트와 매핑되지 않는 웹팩 개발 서버에 대한 모든 요청이 곧바로 /로 (index.html 파일로) 라우팅된다.


업데이트된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


이제 webpack 명령을 실행하는 대신 webpack-dev-server를 실행해 서버를 시작할 수 있다.


node_modules/.bin/webpack-dev-server




업데이트된 package.json

{

"name" : "webpack-sample-project",

"version" : "1.0.0",

"description" : "Sample webpack project",

"scripts" : {

"start" : "node_modules/.bin/webpack-dev-server --progress"

},

"author" : "",

"license" : "ISC",

"devDependencies" : {

"webpack" : "^1.12.9",

"webpack-dev-server" : "^1.14.0"

}

}


//--progress 옵션은 명령줄에서만 사용할 수 있으며, 빌드 단계중에 터미널에 진행 표시줄을 표시한다.




로더


웹팩의 가장 흥미로운 기능 중 하나로 로더(Loader)가 있다.

로더를 이용하면 외부 스크립트와 도구를 통해 소스 파일을 전처리하고 다양한 변경과 변환을 적용할 수 있다. 이러한 변환은 JSON 파일을 빌한 자바스크립트로 구문 분석할수 있게 해주거나, 차세대 자바스크립트 (ES6, ES7) 코드를 현재 브라우저가 이해할 수 있는 일반 자바스크립트(ES5)로 변환해 먼저 이용할 수 있게 하는등 다양한 상황에 유용하게 사용된다.

또한 로더는 리액트의 JSX를 일반 자바스크립트로 변환하는 데도 이용할 수 있다. (리액트 이외에도 알맞은 해석구문의 로더만 있다면 일반 자바스크립트로 변환시킬수 있다.)


로더는 별도로 설치해야 하며, webpack.config.js의 "module" 항목에서 구성해야 한다.


 로더 구성 설정 

 설명 

 test 

 이 로더로 처리하기 위해 일치해야 하는 파일 확장자를 비교하는 정규 표현식 (필수)

 loader

 로더의 이름 (필수)

 include/exclude

 로더가 명시적으로 추가하거나 무시할 폴더와 파일을 수동으로 지정하는 옵션

 query

 로더로 추가 옵션을 전달하는 데 이용되는 쿼리 설정


JSON로더를 이용하여 예제 어플리케이션을 수정해 본다.


npm install --save json-loader //Json Loader 설치


업데이트 된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

}

]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


config.json

{

"greetText" : "Hi there and greetings from JSON!"

}


업데이트 된 Greeter.js

var config = require('./config.json');    //Json Loader 로 인해 webpack이 json형식의 파일도 모듈로 가져올수 있게 됬음.


module.exports = function() {

var greet = document.createElement('div');

greet.innerHTML = config.greetText;

return greet;

}




바벨


바벨은 자바스크립트 컴파일 도구 지원을 위한 플랫폼으로서 다음과 같은 기능을 제공하는 강력한 도구다.


1. 아직 일부 브라우저에서 지원되지 않은 자바스크립트의 다음 버전(ES6, ES7 등)을 이용할 수 있게 해준다.


2. 리액트의 JSX와 같은 자바스크립트 구문 확장을 이용할 수 있게 해준다. 


바벨은 독립 실행형 도구이다.

하지만 로더로도 이용할 수 있으며, 웹팩과 아주 아주 잘 어울린다.




바벨의 설치와 구성


바벨은 모듈형 구조를 띠며, 다양한 npm 모듈로 배포된다.

핵심 기능은 "babelcore" npm 패키지로 제공되며, 웹팩과의 통합은 "babel-loader" npm 패키지로 제공된다.

또한 코드에서 이용하려는 기능과 확장 유형마다 각기 다른 패키지를 설치해야 한다.

많이 사용되는 패키지로는 ES6 컴파일을 위한 "babel-preset-es2015"리액트의 JSX 지원을 위한 "babel-preset-react" 가 있다.


이러한 패키지를 모두 개발 의존성으로 설치한다.


npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react


다른 웹팩 로더와 마찬가지로 바벨도 웹팩 구성 파일의 "module" 섹션에서 구성할 수 있다.


업데이트 된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader",

query : {

presets : ['es2015','react']

}

}


]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


이제 리액트의 JSX 자바스크립트 확장 구문은 물론 ES6 모듈과 구문을 이용할 수 있다.

이러한 기능을 모두 이용하도록 예제 프로젝트를 리팩터링 해본다.


리액트를 이용하기 위해 ReactReact-DOM을 설치한다. (react Loader 와 헷갈리면 안된다)


npm install --save react react-dom


업데이트 된 Greeter.js

import React, {Component} from 'react';  // 설치한 react

import config from './config.json';


class Greeter extends Component{

render() {

return (

<div>

{config.greetText}

</div>

);

}

}

export default Greeter

//ES6 모듈 정의를 이용하고 리액트 컴포넌트를 반환하도록 구성



업데이트 된 main.js

import React from 'react';

import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter />, document.getElementById('root'));

//ES6모듈 정의를 이용하고 리액트 컴포넌트를 렌더링 하도록 구성




바벨 구성 파일


바벨을 webpack.config.js에서 완전히 구성할 수도 있지만, 바벨은 구성 설정과 옵션, 조합이 매우 다양하기 때문에 동일한 파일 안에서 모든 구성을 처리하려면 지나치게 복잡해질 수 있다.

이 때문에 ".babelrc"라는 별도의 바벨 리소스 구성을 만드는 경우가 많다.


지금까지 사용한 바벨 전용 구성은 프리셋 정의뿐이므로 이 항목만 포함 하는 바벨 전용 구성 파일을 따로 만드는 것이 과하게 보일 수 있지만 이후 계속해서 추가 적으로 웹팩과 바벨 기능을 사용할 것이므로 미리 따로 만들어 놓는다.



업데이트 된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

}


]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


.babelrc 파일 생성 (webpack 이 .babelrc 파일을 자동으로 인지한다)

{

"presets" : ["react", "es2015"]

}


이번 장에서는 기본적인 웹팩 개발 환경 구성을 다루었다.

이후 다음 정리에서는 자바스크립트 파일 이외 CSS 그리고 여러 플러그인들을 사용하여 계속해서 연습 프로젝트를 이용하여 추가 구성을 세팅 할 것이다. 내용이 많은관계로 나눠서..


웹팩(Webpack) 이란, 웹팩 간단 정리 및 리액트(React) 기본 개발환경 세팅. [2]














참고.


프로 리액트 - React.js를 이용한 모던 프런트엔드 구축.

댓글