Сборка backbone+requirejs проекта с помощью grunt
Моей основной задачей в последнее время является создание одностраничных javascript приложений. В основном я использую фреймворк Backbone и requirejs. Обычно публикация приложения была простым действием «svn update» но из-за этого возникала куча проблем, начиная с несжатых файлов стилей, огромного количества js файлов и заканчивая кэшированием файлов браузером.
Поэтому я решил озадачится и воспользоваться сборщиком проектов, который должен был решить все возможные проблемы с публикацией проектов. Выбор пал на Grunt. Почему именно он? Возможно потому что для него сейчас уже существует огромное количество плагинов и им легко пользоваться.
Не буду вдаваться в описание этого сборщика, в Интернете есть достаточное количество уже информации. Расскажу о том, как он помогает решать непосредственно мои задачи.
Сразу расскажу, что я использую при разработке приложений. В качестве IDE — WebStorm с установленным плагином компиляции less файлов. Сейчас уже не представляю как я раньше писал css без less. Это очень удобная штука.
В качестве основного фреймворка JS используется Backbone и загрузчик require.js. Само собой jQuery, underscore и все возможно сторонние библиотеки.
Вот так выглядит структура директорий в рабочем проекте.
В папке js находится рабочий js проект. В css — файлы стилей и less файлы. В data — все остальные необходимые данные для проекта. img — хранит изображения.
config.txt хранит конфигурацию приложения в json формате. Думаю, что даже лучше будет назвать его config.json, но тут главное настроить веб-сервер, что бы он понимал такой формат файлов и мог отдавать их верно.
config.dist.txt хранит настройки по умолчанию для проекта.
package.json хранит информацию о проекте и об используемых модулях
Gruntfile.js хранит конфигурацию для grunt. О нем я и буду рассказывать.
Все остальные директории создаются автоматически node.js или grunt при билде проекта.
Первое, что вам необходимо сделать для использования Grunt — это его установить. Информацию по его установке можно найти на этой странице http://gruntjs.com/getting-started. Я устанавливаю его с помощью npm. Поэтому, если у вас нет node.js, то его необходимо сначала скачать и установить. Если у вас уже установлен он, то желательно обновить на новую версию, если она доступна.
Теперь мы переходи в директорию с проектом в консоли. (Не забудьте создать файл package.json. WebStrom умеет их создавать автоматически. Там обязательны только 2 параметра название проекта и версия).
Выполняем следующие команды:
npm install -g grunt-cli
После этой команды grunt будет доступен через консоль.
npm install grunt --save-dev
После этой файл package.json будет обновлен и в файл запишется зависимость использования grunt.
Вот так будет выглядеть файл теперь:
{ "name": "test-project", "version": "0.0.1", "devDependencies": { "grunt": "^0.4.5" } }
Теперь необходимо создать файл Gruntfile.js и вносить в него компоненты и методы для сборки вашего проекта. Я приведу сразу пример своего файла.
/** * Created by VVolkov on 19.05.14. */ // Обязательная обёртка module.exports = function (grunt) { grunt.initConfig({ clean: ["build"], requirejs: { compile: { options: { baseUrl: ".", removeCombined: true, mainConfigFile: "./js/main.js", findNestedDependencies: true, fileExclusionRegExp: /^\./, out: "build/js/app.build.js", name: 'js/main' } } }, copy: { main: { files: [ { expand: true, src: [ 'data/*', 'js/vendor/*', 'config.txt', 'favicon.ico', 'index.html' ], dest: 'build/' } ] } }, imagemin: { dynamic: { files: [{ expand: true, cwd: 'img/', src: ['**/*.{png,jpg,gif}'], dest: 'build/img' }] } }, useminPrepare: { html: ['build/index.html'], options: { root: '.', dest: 'build' } }, usemin: { html: ['build/index.html'], options: { root: '.', dest: 'build' } }, replace: { appbuild: { src: ['build/index.html'], overwrite: true, replacements: [{ from: 'js/main', to: "js/app.build" }] }, cssversion: { src: ['build/index.html'], overwrite: true, replacements: [{ from: '__VERSION__', to: "<%= grunt.template.today('yyyymmddHHss') %>" }] }, csscombinedversion: { src: ['build/index.html'], overwrite: true, replacements: [{ from: '.combined.min.css', to: ".combined.min.css?v=<%= grunt.template.today('yyyymmddHHss') %>" }] }, requirejsversion: { src: ['build/index.html'], overwrite: true, replacements: [{ from: '"bust="+Math.random()', to: '"bust=<%= grunt.template.today(\'yyyymmddHHss\') %>"' }] } }, htmlmin: { dist: { options: { removeComments: true, collapseWhitespace: true }, files: { 'build/index.html': 'build/index.html' } } } }); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-requirejs'); grunt.loadNpmTasks('grunt-contrib-imagemin'); grunt.loadNpmTasks('grunt-contrib-htmlmin'); grunt.loadNpmTasks('grunt-text-replace'); grunt.loadNpmTasks('grunt-usemin'); grunt.registerTask('default', ['clean', 'requirejs', 'copy', 'imagemin', 'useminPrepare', 'concat', 'cssmin', 'usemin', 'replace', 'htmlmin']); };
Давайте разберем теперь все по шагам. У меня установлены модули которые вызываются через grunt.loadNpmTasks. Вы можете скопировать любой их них и найти в интернете. Все они лежат на гитхабе и имеют достаточное описание.
Устанавливать любой модуль надо через консоль в директории с проектом. Зависимость сразу же попадет в package.json.
Вот небольшой пример
npm install grunt-contrib-clean --save-dev
Теперь расскажу, что делает каждый модуль.
grunt-contrib-clean — очищает директорию для билда проекта.
grunt-contrib-requirejs — билдит проект через require.js оптимизатор. На выходе получаем 1 файлик. Очень удобно и просто. Код сразу обфусцирован и минифицирован.
grunt-contrib-copy — копирует файлы с которыми ничего делать не надо. Простой перенос.
grunt-contrib-imagemin — Оптимизирует ваши изображения. Хочу сказать, что очень даже хорошо получается. Есть существенная экономия на трафике.
grunt-usemin — Минифицирует ваши файлы и объединяет их. Этому плагину необходимы зависимости grunt-contrib-cssmin и grunt-contrib-concat. Расскажу подробнее об этом модуле. Например в dev проекте у вас есть ссылки на многие css файлы из разных библиотек или ваши собственные файлы. Плагин их объединяет в один используя комментарии html. Например:
<!-- build:css /css/libs.combined.min.css --> <link href="/css/normalize.min.css" rel="stylesheet"> <link href="/css/bootstrap.css" rel="stylesheet"> <link href="/css/bootstrap-responsive.css" rel="stylesheet"> <link href="/css/idangerous.swiper.scrollbar.css" rel="stylesheet"> <!-- endbuild --> <!-- build:css /css/style.combined.min.css --> <link href="/css/style.css" rel="stylesheet"> <!-- endbuild -->
Из этого примера будет создано 2 файла libs.combined.min.css (объединяющий ваши стили библиотек) и style.combined.min.css (объединяющий ваши собственные стили). Само собой файлы будут минифицированы.
grunt-text-replace — Делает замены в ваших файлах. Я это используя для установки версии css файлов или для парметров require.js. Например, на тестовом сервере для require.js я использую такой параметр конфигурации
<script> require.config({ urlArgs: "bust="+Math.random() }); </script>
Который необходим что бы файлы js не кэшировались при разработки. При билде проекта я меняю этот параметр на дату и время билда проекта. Также меняю путь к файлы проекта requirejs с «js/main» на «js/app.build». app.build — это собранный проект через оптимизатор require.js.
Ну и в последнюю очередь я использую плагин
grunt-contrib-htmlmin — Этот плагин минифицирует html файл.
Вот на этом собственно и все. Это далеко не полный список всевозможных плагинов. Это только несколько которые использую я. Под себя вы можете настроить grunt как вам угодно и удобно.
Соотвественно последовательность задач устанавливается через
grunt.registerTask('default', ['clean', 'requirejs', 'copy', 'imagemin', 'useminPrepare', 'concat', 'cssmin', 'usemin', 'replace', 'htmlmin']);
На этом все. Остается с помощью консоли в директории с проектом запустить команду grunt и ваш проект будет собран. Хороших билдов вашим проектов!
Что почитать еще?
- Делаем жизнь проще, GruntJS — http://habrahabr.ru/post/177395/
- Grunt, инструмент для сборки javascript проектов — http://habrahabr.ru/post/148274/
- Опыт работы с GruntJS — http://habrahabr.ru/post/193092/