디펜던시 모듈 관리

기존의 프론트엔드 자바스크립트는 특별히 모듈화나 디펜던시관리에 대한 방법이 없어 필요한 자바스크립트 파일을 정해진 순서에 맞게 직접 스크립트 태그로 로드하고 각각 약속된 네임스페이스에 담아 공유했었다. 이런 방식은 프로젝트가 커질수록 그리고 참여 개발자가 많을수록 문제를 일으켰다.

이후 개발자들에 의해 AMD와 CommonJS 두가지 방법으로 모듈 관리 환경이 발전하게 되었는데, AMD 방식은 RequireJS가 많이 사용되고 있고 CommonJS는 Browserify가 인기가 많았다. 그리고 CommonJS는 NodeJS에서 사용하고 있는 방식이다.

//AMD style
define([
     module1,
     module2,
     module3
],
function(
     module1,
     module2,
     module3
) {
     //using modules
});
//CommonJS style
var module1 = require(module1);
var module2 = require(module2);
var module3 = require(module3);

//using modules

Webpack이란

Webpack은 Requirejs나 Browserify와 같은 자바스크립트 모듈 디펜던시를 관리하는 도구다. Requirejs을 꽤 오래전부터 사용해오다 Browserify로 변경해서 사용한 지 1년이 넘었는데, 바꾸게 된 이유는 Requirejs의 AMD방식은 모듈을 로드할때 로드할 모듈 정보를 인자에 넘기고 콜백 함수를 통해 파라메터로 모듈들을 전달받는 구조다 보니 로드하는 모듈이 많아질수록 관리가 힘든 점이 제일 컸으며 점점 NodeJS 코드를 다루는 상황이 많아지고 있어 모듈관리를 한가지 스타일로 유지하고 싶었다.

웹팩설명 다이어그램

Browserify를 문제없이 사용하던 중 Webpack 이란 도구를 알게 되었는데, Webpack은 AMD와 CommonJS를 동시에 지원할 뿐 아니라 기본적으로 부분을 캐싱하여 변경점만 번들링하는 방식이라 속도가 빠르고 Karma와 같은 테스트 런너와의 연동도 훨씬 좋았다. 무엇보다 제일 활발하게 진행되는 오픈소스 프로젝트였기에 발전 가능성이 제일 커 보였다. 결과적으로 앞으로 새로 시작하는 프로젝트는 물론 이미 Browserify로 작업된 프로젝트들도 단계적으로 Webpack을 사용할 예정이다

설치 및 간단한 사용

$ npm install webpack -g

보통의 nodejs 모듈처럼 npm을 이용해 webpack을 설치한다. global에 설치하는 것을 예제로 사용했지만 프로젝트별로 따로 설치하는 것을 추천한다.

index.js라는 엔트리 포인트를 시작으로 내부의 디펜던시가 해결되어 머징된 bundle.js라는 파일을 만들어내는 예제다.

$ webpack ./src/index.js ./dist/bundle.js

html파일에서 실제로 로드하는 자바스크립트 파일은 bundle.js가 되는것이다.

설정파일

Webpack을 실행할 때 대부분의 설정은 커맨드 라인에서 직접 파라메터로 설정이 가능하지만 매번 해줄 수 없으니 프로젝트의 설정을 파일로 만들어 간편하게 실행한다. webpack.config.js란 파일을 만들고 위의 커맨드 라인 예제와 동일한 파라메터를 설정파일로 만들어 보겠다.

module.exports = {
    entry: "./src/index.js",
    output: {
      filename: "./dist/bundle.js"
    }
};

이렇게 설정파일을 만들어두면 해당위치에서

$ webpack

파라메터 없이 실행해도 파일에 저장된 설정대로 bundle.js파일을 만들어준다.

watch 모드

watch 모드는 프로젝트의 js 소스코드가 변경될 때마다 자동으로 다시 bundle.js 파일을 만들어주는 기능을 한다. 개발중에는 주로 watch 모드를 이용하게 된다.

$ webpack -w

Webpack을 -w 파라메터를 주고 실행하거나 설정파일에 watch:true를 추가한다.

0eba1c1616fa0ed9e77075c5ce795ac7

첫 번째 실행 시점에서 Webpack이 종료되지 않고 대기하다가 코드를 수정하면(여기서는 sub.js) 해당 파일만 다시 bundle.js에 적용된다. 여기서 중요한 점은 특정 파일의 일부분을 수정해서 저장했는데 전체의 코드를 다시 훑어서 전체의 bundle.js를 다시 만드는것이 캐싱된 상태에서 변경이 일어난 자바스크립트 파일만 변경해 주는 방식이라는 것이다. 그래서 매우 빠르다. Browserify는 이렇게 하려면 추가적인 모듈과 복잡한 설정이 필요했다.그리고 보여주는 터미널 로그도 Browserify보다 이쁘고 필요한 정보를 잘 제공해 준다.

로더

Webpack은 로더라는 일종의 플러그인들을 이용해 기능을 확장할 수 있다. ES6와 ES7문법으로 작업하고 바벨 로더를 이용해 번들링 하는 과정에서 결과물을 ES5로 Transpile 할 수 있으며 Uglify 로더를 이용해 코드를 난독화도 할수 있다. 빌드하는 과정을 자동화 하는 도구로 Grunt나 Gulp가 많이 사용되는데 그런 도구들이 해주던 역할을 이 로더들을 이용해서 처리할 수 있다. 필요한 로더는 직접 만들 수 있지만 이미 많은 로더들이 구현되어 있어 바로 사용할 수가 있다. (로더목록)

장점

모듈 로드 및 디펜던시 관리도구로써의 Webpack의 장점은 아래와 같다.

  • 관련 도구중 제일 핫하다.
  • AMD & CommonJS 코드 둘다 사용 가능
  • 큰 어려움없이 RequireJS나 Browserify에서 전환이 가능하다.
  • Watch모드의 캐싱으로 개발시 변환속도가 매우 빠르다.
  • 특별한 자동화도구 없이 로더를 이용해 기능을 확장할 수 있다.
  • Karma, Babel등 최신 자바스크립트 도구들과의 연동성이 좋다.
  • 개발용 서버를 따로 구성할 필요 없이 바로 사용 가능한 webpack-dev-server가 있다.

Quick start!

디렉토리를 하나 만들고 설정파일을 만든다. (webpack.config.js)

//webpack.config.js
module.exports = {
    entry: "./index.js",
    output: {
        filename: "bundle.js"
    }
};

만들려는 자바스크립트 어플리케이션의 시작점이 되는 index.js파일을 만든다.

//index.js
var sub = require('./sub');

sub.subInit();

index.js는 sub라는 모듈이 필요하다.

//sub.js
module.exports = {
    subInit: function() {
        console.log('this is sub2');
    }
};

우리가 만들 어플리케이션은 페이지에 로드 되자마자 콘솔에 로그 한 줄을 남긴다. 이제 모든 게 통합된 번들 파일을 만든다.(컴파일이라고도 할 수 있겠지만 굳이 따지만 링킹과정에 가깝겠다.)

$ webpack

html파일을 만들어 번들파일을 불러온다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta charset="UTF-8">
    <title>TITLE HERE</title>
</head>
<body>
<script src=“./bundle.js”></script>
</body>
</html>

이제 브라우저에서 html파일을 열어 본다.

자 이제 어플리케이션에 기능을 더 추가해본다!!

보다 추가적인 자세한 사용법은 Webpack사이트에서 찾을 수 있다.