Так появилась на свет ещё одна реализация модулей — definer.
Главная идея этой модульной системы в отсутствии модульной системы. Исходные коды приложения удобно раскладываются по модулям с указанием зависимостей между собой, а затем собираются в один самодостаточный файл, который ничего про модули не знает.
Для хорошего понимания идеи, под катом примеры от простого к сложному.
Возьмём абстрактную страницу товаров интернет-магазина, index.html:
<html> <head> <meta charset="utf-8"/> <title>Каталог интернет-магазина</title> <script src="jquery.js"></script> <script src="https://rawgithub.com/tenorok/definer/master/definer.js"></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 можно найти на гитхабе.
ссылка на оригинал статьи http://habrahabr.ru/post/212817/
Добавить комментарий