RequireJS?
Java나 Python 같은 잘 정립된 언어에서는 객체의 모듈화를 언어 자체에서 잘 지원하지만 JavaScript는 그렇지 않다.RequireJS는 JavaScript 파일과 모듈 로더이다.RequireJS는 브라우저에 최적화되어 있지만 Rhino나 NodeJS등의 환경에서도 사용할 수 있다. RequireJS같은 모듈 로더를 사용하면 당신의 코드의 성능과 품질이 좋아질 것이다
Java나 Python 같은 잘 정립된 언어에서는 객체의 모듈화를 언어 자체에서 잘 지원하지만 JavaScript는 그렇지 않다.RequireJS는 JavaScript 파일과 모듈 로더이다.RequireJS는 브라우저에 최적화되어 있지만 Rhino나 NodeJS등의 환경에서도 사용할 수 있다. RequireJS같은 모듈 로더를 사용하면 당신의 코드의 성능과 품질이 좋아질 것이다
(function(exports) { "use strict"; // private 변수 var name = "I'am a module"; // 외부에 공개할 public 객체 var pub = {}; pub.getName() { return name; } // 외부 공개 exports.aModule = pub; })(exports || global); (exports || global).aModule.getName(); // I'm a module이러한 구현은 변수를 private 화 할 수 있으며 그로 인한 캡슐화로 모듈 사용이 쉬운 장점이 있지만, 여러개의 모듈을 선언하면서 exports 객체에 프로퍼티가 겹칠 경우 앞서 선언된 공개 속성은 덮어써지는 문제가 있고, 모듈간 의존성이 있을때 의존성을 정의하기가 매우 어렵다.
<script type="text/javascript" data-main="main" src="/js/lib/requirejs.js"></script>위 태그를 주의깊게 보면 data-main 이라는 속성에 main 이라는 값이 할당되어 있는데, 이 속성은 옵션으로 이 속성을 주게 되면 requirejs가 전부 로딩되면 저 경로의 속성 이름에 해당하는 파일을 자동으로 로딩한 뒤 실행한다.
// 일반적인 RequireJS 모듈 정의 define(function() { "use strict"; var exports = { version: "1.0" }; var private1 = "private1"; var private2 = "private2"; exports.doSomething = function() { /* ... do something ... */ }; exports.stopSomething = function() { /* ... stop something ... */ }; return exports; });모듈의 정의에는 define 이라는 글로벌 함수를 사용하며 인자로 함수 하나를 받는데 그 함수에서 반환하는 객체가 모듈이 된다.
// 의존성이 없는 모듈의 정의 define([팩토리 함수]);그런데 잊은게 있다.
// 의존성이 있는 모듈 정의 define([의존 모듈 이름 배열], [팩토리 함수]);한번 실제 모듈 코드를 만들어 보자. 일단 파일 구조는 다음과 같다고 가정한다.
// @file Logger.js define(function() { "use strict"; var console = global.console || window.console; var exports = { version: "0.1.0", author: "javarouka" }; exports.log = function() { var args = Array.prototype.unshift.call(arguments, new Date().toLocaleString()); console.log.apply(console, arguments); }; return exports; })로그 모듈로 일반적인 로그에 앞에 로그가 찍히는 현재 날자를 추가해준다.
// @file MainController.js // @dependency Logger.js define(["sub/Logger"], function(logger) { "use strict"; var exports = { type: "controller", name: "Main" }; var bindEvent = function() { logger.log("bind event...") // do something }; var view = function() { logger.log("render ui"); // do something }; exports.execute = function(routeParameters) { logger.log(exports.name + " controller execute..."); // do something } return exports; });일단 팩토리 함수 앞에 인자로 의존성 모듈의 이름 배열을 주는데 상대 경로일 경우 .js 확장자를 생략해야 한다. "sub/Logger" 라고 주면 된다.
// @file ApplicationContext.js // @dependency sub/MainController.js define(["sub/MainController"], function(main) { "use strict"; // do something... });App.js 는 MainController.js에 의존성이 있다. App.js 가 로딩되려면 의존성에 따라
// @file main.js // @dependency App.js, sub/Logger.js require([ "App", "sub/Logger" ], function(app, logger) { "use strict"; app.start(); logger.log("Application start"); }, function(err) { // ERROR handling });모듈 정의가 아닌 단순히 코드를 실행할 때는 require 함수를 사용한다.
// 이 코드를 RequireJS가 로딩된 뒤 기타 모듈을 로딩하기 전에 둔다. require.config({ baseUrl: "/js/some/path", // 모듈을 로딩할 기본 패스를 지정한다. // 모듈의 기본 패스를 지정한다 // 모듈의 이름과 실제 경로를 매핑할 수 있어 별칭(alias) 기능도 할 수 있다 paths: { "javarouka": "modules/javarouka", // 이 모듈은 /js/some/path/module/javarouka.js 경로. // 모듈 패스를 배열로 주게 되면 먼저 앞의 URL로 로딩해보고 안되면 다음 경로에서 로딩한다. // CDN 등을 사용할 때 좋다. "YIHanghee": [ "https://cdn.example.com/YIHanghee", "modules/YIHanghee" ] }, waitSeconds: 15 // 모듈의 로딩 시간을 지정한다. 이 시간을 초과하면 Timeout Error 가 throw 된다 });이러한 설정 파일은 다음과 같이 별도의 분리된 파일로 나눌 수 있다
<script type="text/javascript"> var require = { // 설정 내용 }; </script> <script type="text/javascript" src="/js/requirejs.js"></script>다음에는 RequireJS 형식으로 작성되지 않은 다른 코드를 RequireJS에 포함시켜 사용하며 코드간 의존성을 주는 방법을 알아보겠다.
requirejs.config({ paths: { // jquery 로딩 시 필요한 경로를 지정한다. 'jquery': [ '/js/jquery', '//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min' ], // underscore 도 마찬가지. 'underscore': [ '/js/underscore.min', '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min' ], // backbone 'backbone': [ 'js/backbone.min', '//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min' ] }, shim: { // underscore에 대한 shim 속성을 정의한다. 'underscore': { // 반환될 객체는 exports속성으로 정의한다. // underscore는 아래와 같은 _ 이름으로 공개되는 것이 사용이 직관적이다. exports: function() { return _; } }, // shim 속성의 키로 모듈 이름을 지정하고 내부 속성을 나열한다. // backbone은 underscore와 jquery 에 의존성이 있다. 'backbone': { // 백본이 의존하는 underscore와 jquery를 deps 속성에 정의 // 이름은 위에 이미 지정한 별칭(키 이름)으로 해도 된다. deps: ['underscore', 'jquery'], // 반환될 객체를 정의한다. // 문자열로 줄 경우, // 글로벌 객체에서 저 속성을 키로 하는 객체가 모듈이 된다. // 함수를 줄 경우, // 함수의 실행 결과로 리턴되는 객체가 모듈이 된다. exports: 'Backbone' } } });먼저 모듈이 로딩될 경로를 paths 속성의 키로 정의한 뒤 shim 속성에서 정의한 코드에 대한 의존성을 정의한다.
"jquery": { exports: function() { var jQuery = jQuery.noConflict(); return jQuery; } }, "prototype": { deps: [ "jquery" ], exports: "$" }과 같은 방식을 적용할 수 있겠다. 두 모듈이 안전하게 로딩될 것이다.
http://blog.javarouka.me/2013/04/requirejs-javascript.html
javascript library(라이브러리) 모음 (0) | 2016.05.18 |
---|---|
배열안의 데이터 삭제에 대해 (0) | 2015.04.03 |