Вступление
За время существования Дневник.ру (а это более 4-х лет) скопился огромный объем JavaScript кода: часть находилась в отдельном проекте в виде подключаемых файлов, часть определялась прямо на разметке контролов, а часть собиралась прямо в code-behind при помощи StringBuilder. К этому прибавлялись:
- растущее количество HTTP запросов для получения статичного контента – так, например, на всех страницах только в теге <head> загружалось 11 JavaScript файлов;
- глобальные переменные, которые иногда перекрывали друг друга;
Решив, что с этим пора что-то делать, мы поставили себе первоочередную задачу: вынести все подключаемые по отдельности файлы из тега в один минифицированный пакет. При этом код делился на сторонний и «наш», который планировалось проверять каким-то синтаксическим анализатором.
В этой статье мы расскажем вам о том, как решили эту задачу, и, разумеется, не умолчим о проблемах, с которыми при этом столкнулись.
Что использовать?
Прежде всего нам предстояло определиться, с помощью каких средств мы будем организовывать автоматическую сборку этого пакета. Конечно, можно было бы использовать любую систему сборки, начиная от Ant заканчивая MSBuild; можно было написать и свой собственный простой скрипт – например, на Ruby или Python. В итоге мы решили не писать свои велосипеды и не забивать гвозди трактором, а использовать Grunt. Для тех, кто не знает: Grunt – это JavaScript task runner, работает он на node.js, а распространяется под свободной лицензией MIT. Несмотря на относительную «молодость» данного решения, оно уже успело зарекомендовать себя как прекрасный инструмент – именно его используют для сборки jQuery и QUnit, Tweetdeck в Twitter и Brackets в Adobe. Помимо этих рекомендаций у нас были и собственные причины, по которым мы выбрали именно Grunt:
- Простота использования – для того чтобы начать с ним работать, необходимо всего лишь установить node.js.
- Все поставленные задачи можно решать с помощью JavaScript на node.js, для синтаксической проверки использовать JSHint, для минификации кода – UglifyJS, а если заглянуть в будущее – node.js будет незаменим для модульного тестирования, проверки и сборки стилей.
- Большой выбор плагинов для запуска различных инструментов, а также простой API для написания своих плагинов.
Кстати говоря, ни для кого уже не секрет, что наш проект работает на ASP.NET, поэтому мы рассматривали возможность использования Web Optimization Framework производного от него Bundle Transformer. Тем не менее, мы отказались от этих решений по следующим причинам:
- с помощью этих инструментов невозможно осуществлять синтаксическую проверку кода;
- контент, отдаваемый клиенту, формируется динамически при запросе, а эта операция в любом случае тяжелее, чем отдача веб-сервером статичного файла. Кто-то может сказать, что это экономия на спичках, но:
во-первых, мы с этим не согласны – в нашем проекте есть довольно тяжелые операции, которые и без того нагружают сервера;
во-вторых, сделать это чисто технически было невозможно, так как проект, в котором хранятся JavaScript файлы, не является у нас веб-приложением,
кроме того, статические файлы нам были необходимы в связи с переходом в ближайшее время на CDN.
Однако если в будущем эти инструменты поднимутся на уровень sprockets из Ruby on Rails, то я не исключаю, что мы вернемся к их рассмотрению.
Поехали!
Итак, система для сборки выбрана и пора действовать, но перед дальнейшим повествованием стоит оговориться. Так как приложение у нас написано на ASP.NET, то большинство разработчиков работает на Windows (что неудивительно), да и процесс непрерывной интеграции, который построен у нас при помощи TeamCity (об этом мы писали в одной из предыдущих статей), также происходит на Windows. Поэтому автор просит любителей Unix way простить его за то, что нижеследующее будет описываться именно в рамках экосистемы Windows, и воспринимать весь нижеизложенный опыт как challenge.
Установить node.js на Windows уже давно не представляет никаких проблем. Все, что для этого нужно – скачать бинарный файл с официального сайта, запустить его и потыкать в кнопку «Далее». Вместе с node.js установится и npm – пакетный менеджер, с помощью которого мы установим и Grunt, и все необходимое для его работы. Для начала создадим в проекте файл package.json, в который запишем название нашего проекта, его версию, зависимости и версию node.js. Выглядеть он будет примерно так:
{
"name": "Dnevnik",
"version": "0.1.0",
"private": true,
"dependencies": {
"grunt": "0.4.0",
"grunt-cli": "0.1.6",
"grunt-contrib-concat": "0.1.3",
"grunt-contrib-jshint": "0.2.0",
"grunt-contrib-uglify": "0.1.1",
"grunt-hash": "0.2.2",
"grunt-contrib-clean": "0.4.0"
},
"engines": {
"node": "0.10.0"
}
}
В зависимостях укажем Grunt и его версию, а также необходимые плагины. На начальном этапе мы использовали всего шесть плагинов:
Автор: codefo