Немного о проекте
Собственно, делали мы интерактивную книгу одного популярного российского писателя. Книжка написана на 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/
Добавить комментарий