Сборка 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/