Опыт работы с GruntJS

от автора

Привет. Мы, наконец, закончили работу над одной интерактивной книгой, и сейчас очень хочется рассказать об одном из самых интересных инструментов, из тех, что мы использовали — о GruntJS.

Немного о проекте

Собственно, делали мы интерактивную книгу одного популярного российского писателя. Книжка написана на JS, шаблонах ECT-JS и LESS. Сборкой, конкатенацией, минификацией и деплоем занимается Grunt, книжка работает на iPad’е под Phonegap.

Технически, мы делали прототип — мы активно изучали и применяли различные технологии. С чем-то получилось круто, с чем-то не очень. Как бы то ни было, книга работает, и ее даже можно скачать в App Store.

Думаю, что этого достаточно. Теперь можно перейти к GruntJS…

Grunt Головного Мозга

— У меня есть две переменных, как мне их сложить?
— Я поставил плагин “jquery.math”, очень удобно!

Расскажу немного утрированную, но поучительную историю. Основным форматом графики в нашем проекте был PNG24 с прозрачностью. Проект занимал примерно 500Мб. Мы решили это оптимизировать. Конечно же с помощью плагина для GruntJS…

Вменяемого результата так и не было. 500Мб не лезло ни в какие рамки. С трудом сжали до 450Mб. В итоге, после нескольких дней поисков, сбросили 250Мб. Вот так:

find . -name "*.png" | xargs pngquant -f -v --ext .png --quality 0-90 

GruntJS — потрясающая штука, но вызывает привыкание. Конечно, эта история немного преувеличена, но я действительно видел, как люди делают такие вещи. Напоминает плагины к jQuery. Все-таки, порой проще обойтись однострочником на баше, или подключить проверенные временем консольные утилиты.

Вообще, можно выполнять bash скрипты и команды через grunt. Для этого есть grunt-shell.

grunt.initConfig({   shell: {     compressPNG: {       options: {         stdout: true       },       command: 'find . -name "*.png" | xargs pngquant -f -v --ext .png --quality 0-90'     }   } });  grunt.loadNpmTasks('grunt-shell'); grunt.registerTask('compress', ['shell: compressPNG']); 

Конфиг для Gruntfile.js

В нашем проекте Gruntfile.js содержал порядка 200 строк кода, где была перемешана логика и параметры. Мы решили сделать отдельный конфиг для Gruntfile. В своем проекте для этой цели я создал файл config.json, в котором я храню:

  • Директорию исходников
  • Директорию для деплоя
  • Переменные для шаблонизатора (например, название книги)
  • Игнор-лист (файлы, которые не попадают в деплой)
  • Список LESS-файлов, и целевой файл
  • Список JS-файлов и целевой файл
  • Параметры для деплоя на сервер для тестирования

Пользы от этого много. Во-первых, добавлять файлы становится значительно проще, во-вторых, небольшие изменения в конфиге может внести совершенно не знакомый с Grunt’ом человек. Ну и в третих, логика не перемешивается с параметрами.

Выглядит конфиг так:

{   "src": "_src",   "dst": "www",   "port": 8000,   "variables": { "bookname": "Чапаев и Пустота"},   "ignore": [ "**/*.ect", "**/*.md", "**/*.less"],   "less": {     "www/app/assets/css/app.min.css": ["_src/app/assets/less/main.less"],     "www/content/assets/css/content.min.css": ["_src/content/assets/less/main.less","_src/content/widgets/**/widget.less"]     }   },   "js": {     "www/app/assets/js/app.min.js": [       "_src/app/assets/js/utilities.js",       "_src/app/assets/js/modules/*.js",       "_src/app/assets/js/setups/*.js",       "_src/content/widgets/**/*.js"       "_src/app/assets/js/init.js",     ]   } } 

Пример Gruntfile

module.exports = function (grunt) {    //  Подключаем config.json   var config = grunt.file.readJSON('config.json') || grunt.fatal('config.json not found');    // Разбираемся с паттернами в игнор-листе   config.ignore = getIgnorePatterns(config);    var tasks = {     clean: {       dst: path.join(config.dst, '**/*'),       ignore: config.ignore     },     livereload: {…},     regarde: {…},     copy: {…},     ect: {…},     less: {…},     uglify: {…},     rsync: {…}   };    grunt.initConfig(tasks);   grunt.registerTask('lvrld', ['livereload-start', 'connect', 'regarde']);    grunt.registerTask('main', ['clean:dst', 'copy:main', 'clean:ignore','uglify:main', 'ect', 'less:browser']);   grunt.registerTask('browser', ['main', 'lvrld']);   grunt.registerTask('phonegap', ['clean:dst', 'copy:main', 'clean:ignore', 'uglify:main', 'less:phonegap', 'ect']);   grunt.registerTask('deploy', ['main', 'rsync:deploy']);   grunt.registerTask('default', ['browser']);    var plugins = ['grunt-rsync', 'grunt-ect-templates', 'grunt-remove-logging', 'grunt-contrib-copy', 'grunt-contrib-concat', 'grunt-contrib-clean', 'grunt-contrib-less', 'grunt-contrib-uglify', 'grunt-contrib-livereload', 'grunt-contrib-connect', 'grunt-regarde']    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);  }; 

Удобная отладка на устройствах

Отлаживать код на паре iPad’ов и MacBook’е очень неудобно. Приходиться постоянно обновлять страницу руками. Это ужасно.

Здесь Grunt может помочь. Если запустить grunt-contrib-watch, настроить livereload, и подключить все устройства по IP, то при изменении кода все гаджеты будут сами перезагружать страницу. Это потрясающе! Серьезно, если постоянно перезагружать страницу даже на трех устройствах, то уже через час я хочу разнести все в щепки.

Вообще, здесь есть проблема. В нашем проекте относительно много файлов. Примерно тысячи 2. Так вот, если покрыть livereload’ом все (с разными тасками, конечно), то nodejs начинает падать. Приходится отказываться от полного покрытия. У нас под нож пошли картинки.

Написание плагина

Вобщем-то, шаблонизатор я выбрал достаточно просто — взял первый попавшийся, с layout и partials. Первым попавшимся оказался ECTJS. Сейчас я бы взял jade, но тогда взял этот. Не найдя подходящий плагин для шаблонизатора, я решил написать свой.

Вообще, писать плагин для gruntjs достаточно просто. Практически все что может понадобиться, написано в инструкции. В целом, алгоритм такой:

1. grunt-init gruntplugin создаст структуту проекта
2. Пишем код, подключаем модули…
3. Когда нужно — подсматриваем в API GruntJS


Вобщем-то это все, чем я хотел поделиться.

ссылка на оригинал статьи http://habrahabr.ru/post/193092/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *