...

понедельник, 17 февраля 2014 г.

Definer.js — простая модульная система

Пока JavaScript не обзавёлся настоящими модулями мы продолжаем импровизировать.

Так появилась на свет ещё одна реализация модулей — definer.

Главная идея этой модульной системы в отсутствии модульной системы. Исходные коды приложения удобно раскладываются по модулям с указанием зависимостей между собой, а затем собираются в один самодостаточный файл, который ничего про модули не знает.


Для хорошего понимания идеи, под катом примеры от простого к сложному.


Возьмём абстрактную страницу товаров интернет-магазина, index.html:



<html>
<head>
<meta charset="utf-8"/>
<title>Каталог интернет-магазина</title>
<script src="jquery.js"></script>
<script src="http://ift.tt/1gJFADj"></script>
<script src="modules/cart.js"></script>
<script src="modules/list.js"></script>
</head>
<body>
<ul class="list">
<li class="item">
<span class="name">Компьютер</span>, <span class="price">250</span>
</li>
<li class="item">
<span class="name">Телевизор</span>, <span class="price">100</span>
</li>
<li class="item">
<span class="name">Холодильник</span>, <span class="price">300</span>
</li>
</ul>
</body>
</html>


Будем использовать jQuery для работы с DOM и definer для модулей.


Модуль Cart, реализующий корзину интернет-магазина с возможностью добавить товар и получить суммарную стоимость добавленных товаров:



definer('Cart', function() {

function Cart() {
this.list = [];
}

Cart.prototype = {
add: function(target) {
var item = $(target);
this.list.push({
name: item.find('.name').text(),
price: +item.find('.price').text()
});
},
sum: function() {
return this.list.reduce(function(sum, item) {
return sum + item.price;
}, 0);
}
};

return Cart;

});


Модуль list, зависящий от Cart и реализующий взаимодействие посетителя с каталогом:



definer('list', function(Cart) {

var iCart = new Cart();

$(function() {
$('.item').on('click', function(e) {
iCart.add(e.currentTarget);
console.log(iCart.sum());
});
});

});


Получилась страница, где можно кликнуть по товару и в консоли увидеть суммарную стоимость добавленных товаров. Но, при этом, мы разделили функциональность на два самостоятельных модуля.


В данном примере, у нас осталась глобальная переменная, которую тоже можно вынести в модуль, это jQuery.


Подключим файл modules/clean.js перед существующими модулями:



definer.clean('$');


Теперь переменной $ нет в глобальном контексте:



console.log($); // undefined


Чтобы продолжать использовать jQuery в модулях, добавим зависимость:



definer('Cart', function($) { ... });
definer('list', function($, Cart) { ... });


Сборка




Теперь всё готово и можно собрать исходники в единый файл.

Устанавливаем сборщик модулей:



npm install definer


Собираем все модули из директории modules в файл index.js:



./node_modules/.bin/definer -d modules/ index.js


Теперь в index.html достаточно подключить только jQuery и собранный файл:



<script src="jquery.js"></script>
<script src="index.js"></script>


Сборка с помощью grunt-definer




Для удобства разработки есть grunt-плагин. Можно установить мониторинг на изменение файлов модулей и автоматически запускать сборку.

Устанавливаем всё, необходимое для гранта:



npm install grunt grunt-cli grunt-contrib-watch grunt-definer


Добавим в корень проекта файл Gruntfile.js:



module.exports = function(grunt) {

grunt.initConfig({
watch: {
scripts: {
files: ['modules/*.js'],
tasks: ['definer:all']
},
},
definer: {
all: {
target: 'index.js',
directory: 'modules/'
}
}
});

grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-definer');

};


И запустим мониторинг:



./node_modules/.bin/grunt watch


Теперь сборка будет выполняться автоматически в фоне, а мы можем изменять файлы модулей и обновлять страницу в браузере, чтобы увидеть результат.


Сборка сторонних файлов




Сейчас к странице подключается два файла — jQuery и собранные модули. Можно добавить jQuery в сборку и подключать к странице всего один файл.

Для этого достаточно добавить опцию clean в grunt-цель:



definer: {
all: {
target: 'index.js',
directory: 'modules/',
clean: {
$: 'jquery.js'
}
}
}


Теперь в index.html достаточно подключить только один собранный файл:



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


JSDoc




Возможно формирование JSDoc, содержащего информацию о собранном файле.

Для этого добавим опцию jsdoc в grunt-цель:



jsdoc: {
"file": "Добавление товаров в корзину интернет-магазина",
"copyright": "2014 Artem Kurbatov, tenorok.ru",
"license": "MIT license",
"version": "package.json",
"date": true
}


Возможно указание относительного пути до JSON-файла, из которого сборщик получит значение одноимённого поля.


Положим в корень проекта файл package.json:



{
"version": "0.1.0"
}


Перед модулями в собранном файле появится такой JSDoc:



/*!
* @file Добавление товаров в корзину интернет-магазина
* @copyright 2014 Artem Kurbatov, tenorok.ru
* @license MIT license
* @version 0.1.0
* @date 17 February 2014
*/


Итого


Definer помогает:



  • разбить всё приложение на модули по зависимостям

  • избавиться от глобальных переменных

  • собирать все скрипты в один файл с помощью grunt-плагина


Документацию по definer и grunt-definer можно найти на гитхабе.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий