본문으로 바로가기

RequireJS - module loader(모듈 로더)

category Web Tech/RequireJS 2016. 1. 25. 13:40


JS 모듈 관리(Javascript Modules Management)

RequireJS 는 자바스크립트 파일/모듈 로더입니다. 

브라우저 환경에서 최적화되어 있으나 Node 와 같은 다른 자바스크립트 환경에서도 사용될 수 있습니다.



그렇다면 모듈 로더는 무엇인가?!

JAVA 나 그 밖의 다른 서버사이드 언어는 파일을 include 하여 사용할 수 있으나 자바스크립트 자체로는 file01.js 파일로부터 다른 file02.js 파일을 include 할 수 있는 방법이 없습니다. 하지만 이를 해결할 수 있는 여러가지 방법이 존재하고 있으며 이러한 방법을 통해 자바스크립트 파일들 서로 간에 의존성/종속성 관리를 할 수 있습니다.

여러가지 방법 중의 하나인 RequireJS 와 같은 모듈 방식의 스크립트 로더를 사용한다면 웹 어플리케이션의 품질과 속도, 최적화를 향상 시킬 수 있습니다.


이 포스팅에서는 Javascript 관리와 성능을 향상시키기 위한 모듈 관리방법중에 RequrieJS 에 대해 알아보고자 합니다.

그리고 이 글을 읽기에 앞서 Client/Sever Side Javascript 표준화를 위한 CommonJS, AMD 에 대해 알아볼 것을 추천드립니다.



다음의 코드를 간단히 살펴보도록 하겠습니다.

html
<!DOCTYPE html>
<html>
<head lang="ko-KR">
    <meta charset="UTF-8">
    <title>Require.js 시작하기</title>
    <script src="require.js"></script>
    <script type="text/javascript">
        // jQuery 를 load 한 후 실행한다.
        require(["http://code.jquery.com/jquery-1.11.1.min.js"], function() {
            // CDN 으로부터 jQuery 가 로드된 뒤에 아래의 코드가 실행된다.
            alert($().jquery);
        });
    </script>
</head>
<body>

</body>
</html>


http://requirejs.org/docs/download.html 에서 require.js 를 다운받아 import 를 해주고 require 함수를 사용하여 무엇(여기선 jQuery)인가를 로드하면 로드를 하기 전에 또 거기에 의존성이 있는 파일, 즉 require 로 로드할 의존성 모듈들을 먼저 가져온 후에 콜백함수가 실행되는 방식입니다


물론 RequireJS 를 위와 같이 작성하지는 않습니다.


위와 같은 방식을 사용하게 되면 jQuery 가 실행될 때 전역 네임스페이스가 $ 변수로 오염되기 때문입니다. 이는 다른 라이브러리와의 충돌이나 두 개의 다른 버전의 제이쿼리를 사용할 수 없을 것입니다. 

이는 모듈 로더인 RequireJS 를 사용하려는 목적에 벗어나는 일이니까요.

일반적인 자바스크립트 패턴의 사용은 편하기는 하지만 이 편안함에 너무 의존하다보면 돌이킬 수 없는 스파게티 코드나 

중복 코드 발생이 빈번해 질 수 있기 때문에 모듈 프로그래밍이 필요합니다. 

RequireJS 는 일반적인 스크립트 패턴에서 발생할 수 있는 문제점에 대한 대안이 될 수 있으며, RequrieJS 를 사용함으로써 모듈 생성/호출 등 관리를 통해 좀 더 체계적인 프로그래밍을 가능하게 해 주며 브라우저 지원 또한 IE 6 이상을 지원하고 있습니다.

RequireJS 의 모듈 패턴은 일반적으로 스크립트를 작성하는 패턴과는 달리 전역 네임스페이스의 오염을 피할 수 있는 별도의 컨텍스트인 한정된 범위에서 객체를 선언하여 사용하는 점에서 차이점이 있습니다.

모듈은 해당 모듈의 의존(dependancy) 목록을 명시할 수 있으며 전역객체에 대한 참조없이 의존 모듈 상의 객체를 함수의 인자(args)로 받음으로써 핸들링할 수 있게 해줍니다.




Usage RequireJS (기본적인 사용법)


RequireJS 다운로드 및 설치


RequireJS 홈페이지에서 다운로드를 하거나 아래와 같이 npm 을 이용하여 다운로드 받습니다.


$ npm install requirejs


다음 index.html 파일을 아래와 같이 구성합니다.


index.html 파일

html
<!DOCTYPE html>
<html>
<head lang="ko-KR">
    <meta charset="UTF-8">
    <title>Require.js 시작하기</title>
    <script>
        // Require.js 환경설정(Configuration)
        // http://requirejs.org/docs/api.html#config
        var require = {
            // index.html 기준, 기본 위치 지정
            baseUrl: "www/js/"
        };
        // 이와 같이 head 에 인클루드 하지 않고 main.js 에서 환경설정들을 해주는 것이 적당하다.
    </script>
    <!-- 
          data-main 속성에 설정된 JS 파일은 비동기 호출됩니다.
          (※ 파일 경로는 Require.js가 위치한 baseUrl 기준: http://requirejs.org/docs/api.html#jsfiles)
     -->
    <script src="js/libs/require.js" data-main="js/main"></script>
    <!-- main 속성을 설정하여 RequirJS 가 로드된 후 바로 로드해서 실행해줄 자바스크립트 파일을 지정해줍니다. -->

</head>
<body>
<p>main.js 가 DOMContentedLoaded, Load 된 이후에 호출되고 있다.</p>

</body>

</html>


위와 같이 RequrieJS 의 명세서를 따라서 data-main 속성을 설정해 주어 require.js 가 로드된 후 바로 로드(호출)될  스크립트 파일을 지정해 주는 방식입니다.

위의 코드에서는 requrie.js 파일이 로드된 후에 바로 main.js 파일을 호출해서 실행하게 됩니다.


data-main 의 값은 ".js" 가 생략 가능하며, data-main 의 main 은 require 형식의 문법(약속·규약)입니다.


그리고 main.js 파일은 아래와 같이 작성할 수 있습니다.( main.js 는 custom)


main.js 파일



javascript
/**
 * --------------------------------
 * RequireJS 환경 설정 (기본 설정)
 * --------------------------------
 */

requirejs.config({
    /**
     * [ baseUrl 설정 ]
     * JavaScript 파일이 있는 기본 경로를 설정한다.
     * 만약 data-main 속성이 사용되었다면, 그 경로가 baseUrl 이 된다.
     * 환경설정해 주기 위한 main.js 가 위치한 기준 디렉터리의 루트를 설정해 줍니다.
     */
    baseUrl : 'js', // 이 곳 환경설정에서는 'js' 라는 폴더를 기본 폴더로 설정합니다.

    /**
     * [ paths 설정 ]
     * path 는 baseUrl 아래에서 직접적으로 찾을 수 없는 모듈명들을 위해 경로를 매핑해주는 속성입니다.
     * "/"로 시작하거나 "http" 등으로 시작하지 않으면, 기본적으로는 baseUrl 에 상대적으로 설정하게 됩니다.
     * 그리고 아래 exam, jQ 와 같이 별칭(alias)을 설정하여 사용하고  또한 스크립트 파일(모듈)의 .js 확장자는 붙여주지 않습니다.
     * 위와 같은 형태로 설정한 뒤에, define 에서 "exam/module" 로 불러오게 되면,
     * 스크립트 태그에서는 실제로는 src="aaaa/bbbb/module.js" 로 설정되게 됩니다.
     * path 는 또한 아래와 같이 특정 라이브러리 경로 선언을 위해 사용될 수 있는데,
     * path 매핑 코드는 자동적으로 .js 확장자를 붙여서 모듈명으로 매핑됩니다.
     * 정리 : 모듈의 별칭(Alias)을 설정하고 모듈의 단축 경로를 지정합니다.
     */
    paths : {
        "exam": "aaaa/bbbb",
        // 뒤에 js 확장자는 생략한다.
        'jquery': 'libs/jquery-1.11.3.min',
        'angular': 'libs/angular/angular-1.0.4'
    },

    /**
     * AMD 를 지원하지 않는 JS 라이브러리 AMD 호환 설정
     * shim 설정 (두 사물사이를 연결해주는 끼움쇠) html5Shim 과 같은 것입니다.
     * @type {Object}

     * [ shim 설정 ]
     * AMD 방식을 지원하지 않는 라이브러리의 경우 아래와 같이 shim 을 사용해서 모듈로 불러올 수 있습니다.
     * 참고 : http://gregfranko.com/blog/require-dot-js-2-dot-0-shim-configuration/
     */
    shim:{
        'angular':{
            deps: ['jquery'], // angular 가 로드되기 전에 jquery 가 로드되는 것을 의미합니다
                              // 만약에 angular 가 jQuery 가 필요한 라이브러리라면 의존모듈을 설정해 주는 것입니다.
            exports:'angular' // 로드된 angular 라이브러리는 angular 라는 이름의 객체로 사용할 수 있도록 해줍니다.
        },
        'modernizr' : {
            exports : 'Modernizr' // 모더나이저의 클래스가 Moderizr 이므로 Modernizr 를 등록합니다..
        },

        'detectizr' : {
            exports : 'Detectizr', // 디텍타이저의 클래스는 Detectizr 입니다.

            // deps(dependencies 의 약어) 의존 모듈을 등록합니다.
            // Detectizr 는 Modernizr 의 플러그인으로써 Modernizr 에 의존하는 모듈인 셈입니다.
            // paths에 등록된 별칭을 등록합니다.
            deps : ['modernizr']
        }
    }
});

/**
 * ----------------------------------------------
 * requireJS 를 활용하여 모듈을 호출,로드하는 방법
 * ----------------------------------------------
 */
requirejs( [
        /**
         * 디펜던시(의존 모듈)를 콜렉션 타입으로 설정하고,
         * 이 의존 모듈들이 먼저 로드 된 뒤에 아래 콜백함수가 수행됩니다.
         */
            'jquery',   // config 에 미리 선언해둔 path 의 별칭(alias),
                        // jQuery 는 AMD 방식을 지원하기 때문에 이렇게 로드해도 jQuery 또는 $ 로 호출할 수 있습니다.
            'angular'   // config 에 미리 선언해둔 path,

        ],

        /**
         * dependency 로드 뒤 콜백함수를 설정
         * 로드 된 디펜던시(의존 모듈)들은 콜백함수의 인자로 넣어줄 수 있습니다.
         */
        function ($, angular) {

            // 이 콜백 함수는 위에 명시된 모든 의존 모듈들이 모두 로드 된 후에 호출되게 됩니다.
            // 주의해야할 점은, 디펜던시 로드 완료 시점이 페이지가 완전히 로드되기 전 일 수도 있다는 점입니다.
            // 이 콜백함수는 생략할 수 있습니다.

            // 페이지가 완전히 로드 된 뒤에 실행
            console.log($ === jQuery); // true 가 출력된다.
            $('body')
                    .addClass('assign-jquery')
                    .height(window.innerHeight)
                    .attr('data-body', 'root');
        }
);

/**
 * 의존 모듈을 불러오지 않을 경우의 사용 방법
 * DOMScript Code
 */
require([], function() { // 의존 모듈이 없으므로 콜렉션(배열)을 empty 로 설정

    var body = document.body;
    body.classList.add('no-assign-jquery');
    body.style.height = window.innerHeight + 'px';
    body.setAttribute('data-body', 'root');

});


main.js 에서 require.config 를 통해 requireJS 의 환경 설정을 셋팅할 수 있습니다.


위와 같은 설정 이 외에도 다양한 옵션들이 존재하는데, 아래의 requireJS 사이트를 참고하면 해당 옵션들에 대한 자세한 내용을 살펴볼 수 있습니다.


http://requirejs.org/docs/api.html


모듈 호출방법에 대해서 다음 포스팅에서 좀 더 살펴보도록 하겠습니다.



Jaehee's WebClub