블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 3. 16. 16:17 Backbone.js

모듈 프로그래밍은 큰사이즈의 애플리케이션을 작은 단위의 관리가능한 블록으로 만드는데 유용하다. 모듈기반 코딩은 유지보수 노력을 줄여주고 재사용을 높여준다. 그러나 모듈간의 의존관계를 관리하는 부분은 어려운 점들이 있다. 이런 의존 관계상의 문제를 해결하기 위하여 RequireJS 프레임워크가 나오게 되었다. 



1) Old Style Loading JavaScript 파일들

  - 큰사이즈 애플리케이션들은 여러 자바스크립트 파일을 <script> 태그로 로딩한다

  - 이때 각 자바스크립트 파일은 어떻게 로딩을 처리하는지 예제로 보자


purchase.js

function purchaseProduct(){

  console.log("Function : purchaseProduct");

  var credits = getCredits();

  if(credits > 0){

    reserveProduct();

    return true;

  }

  return false;

}


products.js

function reserveProduct(){

  console.log("Function : reserveProduct");

  return true;

}


credits.js

function getCredits(){

  console.log("Function : getCredits");

  var credits = "100";

  return credits;

}


  - 만일 main.js에서 이렇게 코딩을 하면 var result = purchaseProduct(); 

  - purchase.js는 credits.jsproducts.js 파일 의존관계가 된다. 따라서 이들은 purchaseProduct()이 호출되지 전에 먼저 로딩되어 져야 한다. 

  - 만약 다음 순서라면 에러가 발생할 것이다. (credits.js 가 먼저 로딩되어야 하는데 맨 뒤에 있으므로)

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

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

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

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


  

2) RequireJS 소개

  - http://requirejs.org/docs/download.html 에서 모듈을 다운로드하자 

  - 모든 자바스크립트 파일과 함께 require.js 파일을 같은 디렉토리에 둔다

    

  - index.html 안에 하기와 같이 script를 넣는다 

<script data-main="scripts/main" src="scripts/require.js"></script>


  - 코드안에 RequireJS를 사용하여 require code를 넣는다.

  - data-main 어트리뷰트 애플리케이션 최기화 시점으로 이때 RequireJS가 다른 스크립트 파일과 의존관계를 찾기위하여 scripts 디렉토리 밑에 있는 main.js를 사용하고 require.js를 src 값으로 지정한다. main.js가 해당 예에서는 같은 폴더에 모든 파일이 위치하지만 원하는 어느 폴더에 놓아도 무방하다. 


  - main.js 코드를 보자 

require(["purchase"],function(purchase){

  purchase.purchaseProduct();

});


  -  RequireJS는 require() 또는 define() 펑션으로 모든 코드를 감싼다. 펑션의 첫번째 파라미터로 의존관계에 있는 파일명을 넣으면 되고, .js는 생략가능하다. 두번째 파라미터는 무명함수(anonymous function)로 의존파일안의 함수를 호출한다. 

  - 다중의존관계 호출은 다음과 같다

require(["a","b","c"],function(a,b,c){

});



3) Define으로 모듈 생성하기

  - main.js 에서 사용될 모듈들을 define() 펑션을 이용하여 만든다

  - 모듈생성이 펑션널 프로그래밍 단위 즉 Task 단위로 생성이 되는 것이다. 

  - main.js 에서 필요한 모듈 즉 Task 를 로딩하여 사용하게 된다 

  - purchase.js를 바꾸어 보자

define(["credits","products"], function(credits,products) {

  console.log("Function : purchaseProduct");

  return {

    purchaseProduct: function() {

      var credit = credits.getCredits();

      if(credit > 0){

        products.reserveProduct();

        return true;

      }

      return false;

    }

  }

});


  - products.js 도 바꾸어 보자

define(function(products) {

  return {

    reserveProduct: function() {

      console.log("Function : reserveProduct");

      return true;

    }

  }

});


  - credits.js 도 바꾸어 보자 

define(function() {

  console.log("Function : getCredits");

  return {

    getCredits: function() {

      var credits = "100";

      return credits;

    }

  }

});



4) define()으로 모듈 만들고 require()로 필요한 모듈 사용하기 

  - require() : 모듈을 로딩하여 즉시 함수를 수행하는데 사용한다

  - define() : 모듈을 정의하는데 사용한다

  - purchaseProduct() 은 main.js 파일에서 함수를 즉시 실행한 것이다. 그러나 다른 파일은 재사용을 위하여 모듈화 하기 위하여 define()을 사용했다. 



5) 왜 RequireJS가 중요한가?

  - RequireJS는 펑션이 수행되기전에 모든 의존관계 파일이 로딩될 때까지 기다린다. 즉, 하나의 호출에 관여된 의존관계 파일을 로딩한 후에 펑션을 호출해 준다. 필요한 시점에 로딩하여 주고 Asynchronous Module Loading 이다. 

 


6) 의존관계 파일의 우선순위 관리 방법

  - RequireJS는 파일을 로딩할 때 Asynchronous Module Definition(AMD)을 사용한다.

  - Asynch로 로딩되기 때문에 순서적인 로딩을 보장받고 싶다면 shim 환경파일을 작성할 수 있다. 

  - 환경 shim 예

requirejs.config({

  shim: {

    'source1': ['dependency1','dependency2'],

    'source2': ['source1']

  }

});


  - RequireJS에서 제공하는 config() 펑션을 통해 shim 이라 불리우는 파라미터를 정의한다.

  - configuration 가이드는 http://requirejs.org/docs/api.html#config 를 참조한다. (Advanced User로 갈려면 꼭 익히자!)

    + jQuery config

    + Node config

    + Dojo config


  - 예로 하기와 같이 정의하지만 로딩 순서 지정을 위와 같이 shim으로 할 수 있는 것이다. 

define(["dependency1","dependency2","source1","source2"], function() {

);

  

  - source2는 source1을 의존한다. source1의 로딩이 끝나면 source2는 모든 의존파일이 로딩되었다 여긴다. 그러나 dependency1과 dependency2 는 여전히 로딩되고 있을지도 모른다. shim config를 사용하면 이러한 복잡성을 제거하여 로딩 순서를 지정하여 줄 수 있다. 


  - Backbone.js Boilerplate 블로깅의 index.html 파일을 파악해 보자



<참조>

  - 원문 : Understanding RequireJS for Effective JavaScript Module Loading

  - RequireJS 홈페이지

posted by 윤영식