Как стать автором
Обновить

Комментарии 74

Ну, это public domain, так что, надеюсь, кому-нибудь это поможет сэкономить 749 (ну у них и цены %) баксов на сервер.
Ну вы, батенька, и маниак :) преклоняюсь :)
Спасибо, на выходных попробую попробывать это у себя в живую…

Сейчас дальше незначительной автоматизации «минифицирования» js и css с помощью .bat с yui-js-compressor я не зашел.
Кстати когда то уже в комменте писал про это, кому интересно: vant.kiev.ua/compressor.zip (1.6 Мб)
Ну, тут на самом деле ничего сложного — сложнее всего было продумать алгоритм :)

Ваш вариант тоже представляет собой вполне себе работоспособное решение, единственное что, некросплатформенное (для нас это критично), да и для работы с java-проектом сам бог велел использовать ant :)
Спасибо. Мне было полезно это узнать.
Сложная, громоздкая, берущая на себя много ответственности система. Вы представляете, каким маниаком должен быть человек, чтобы ею пользоваться? Как мне поступить, когда я вернусь к этому конфигу через месяц? Я в своих-то сырцах через две недели уже начинаю плохо ориантироваться.

Также такая сложность значительно усложняет интеграцию решения.

Описанная в этой статье теория может быть полезна в очень большом проекте без выхода библиотеки за рамки самого проекта.

Имхо.
1) Из-за того, что этот скрипт — ознакомительный, т.е. ставит перед собой цель «показать, представить пример того, как можно автоматизировать указанный процесс», он довольно громоздкий. На практике его можно очень и очень сильно упростить и сделать гибче.

2) А зачем вообще заморачиваться на автоматизацию выкладки проекта, если он маленький и над ним работает один человек? Вот у нас, к примеру, работает по 5-8 человек над проектом, и новые рабочие билды собираются teamcity с обязательной прогонкой через все тесты перед выкладыванием. И в наших условиях собирать это все руками — смерти подобно. Гораздо проще создать свод правил о том, как именовать файлы, куда их класть и все в таком духе, и потом создать скрипты для развертывания приложения для development, test и production окружения.
Если разбивать предложенный вами вариант на подсистемы, то постепенно получится фреймворк. А то, что представили вы — это как Остап бендер:
«Ослепительные перспективы развернулись перед васюкинскими любителями. Пределы комнаты расширились. Гнилые стены коннозаводского гнезда рухнули, и вместо них в голубое небо ушел стеклянный тридцатитрехэтажный дворец шахматной мысли. В каждом его зале, в каждой комнате и даже в проносящихся пулей лифтах сидели вдумчивые люди и играли в шахматы на инкрустированных малахитом досках».
Любопытно. Вы действительно считаете, что это чрезмерно связанная и усложненная система? Я написал этот скрипт (точнее, тот, что мы используем сейчас) за два часа, и никаких проблем с ним не было на всех проектах.

Я думаю, что на самом деле тут все супер-просто, и для сравнения приведу вам описание скрипта, который производит полное развертывания проекта для production окружения (в описании некоторых шагов я могу ошибаться, так как занимаюсь далеко не всем):

1. с помощью maven производится скачивания всех зависимостей (разработка ведется на j2ee).
2.с помощью того же maven'а проект собирается, все файлы кладутся туда, куда надо.
3.специально написанный скрипт прогоняет последовательно юнит, интеграционные тесты.
4.прогоняются скрипты, завязанные с базой данных — что конкретно делается, не скажу, не моя зоня ответственности, но, по логике, экспортируется нужная схема, данные, если нужно преобразуются.
5.прогоняется вышеуказанный модификация обсуждаемого скрипта, только она еще и выкладывает все ресурсы на кластер и проставляет заголовки expires.
6..оттестированное приложение располагается на application server'ах
7.application сервера с новым билдом соединяются с frontend сервером
8.все, пользователь видит новый билд

Если на каком-то шаге произошла ошибка, остается работать старый билд, а текст ошибки отправляется ответственному человеку на мыло.

И приблизительно за каждым из этих шагов стоит свой скрипт. Вот это уже фреймворк, и у нас он сделан, как фреймворк. А обсуждаемый скрипт — лишь его часть.
НЛО прилетело и опубликовало эту надпись здесь
ага, а что Packer вытворяет? :)
То, что представлено на конечном сайте может быть сколь угодно уродским. Красивым и лаконичным структура проекта должна быть на девелопмент-версии. Попробуйте разобраться в JS на gmail.com
Видимо, вы невнимательно читали.
На дев-машине все остается по-прежнему.
А на продакшен все выкладывается примерно в том виде, что вы указали.
А что, вы хотите дебажить js-код прямо на продакшене? Так это неправильно, отлов багов должен происходить на машине тестера/разработчика. То, что лежит на сервере, должно быть оптимизировано для быстрой загрузки, для чего сжатие и делается.
Это был ответ не тебе, а ident )
простите? может быть, что-то с системой комментирования.
но оракл распространяет этот oraclemaps.js как javascript-библиотеку для создания карт

и порой приходится в ней рыться, много там ошибок ещё
видимо, оракл не читает хабрахабр ;)
Что вы предпочитаете… экономить свои нервы… или же делать клиентскую оптимизацию?, которую я думаю даже пользователи не заметят, а уж заказчик тем более. На дворе 21 век… гигабайты оперативной памяти… На мой взгляд нецелесообразно.
Гм.
Простите, а вы имеете представление о том, для чего делается клиентская оптимизация и какой эффект она дает?
Если вкратце, то даже начального уровня клиентская оптимизация позволяет ускорить с точки зрения пользователя работу сайта (в первую очередь — скорость появления первой «картинки») в несколько раз. Как вы, наверное, представляете, это может вылиться в серьезную экономию денег, а также помочь удержать на сайте новых пользователей и привлечь новых. Почитайте статью сколько живых денег принесет ускорение загрузки сайта.

Гигабайты ОЗУ — это здорово, но вот гигабайтные каналы далеко не у всех, и это я даже не вспоминаю всякие наладонники и GPRS.
Как вы собираетесь сократить трафик склеиванием нескольких файлов? (просто меня больше всего затронул этот фактор). Если опустить все пункты которые влияют на входящий трафик, то по сути вся остальная оптимизация должна переваливаться на плечи разработчиков браузеров.

P.S. С сегодняшним кешированием в браузерах даже несколько лишних килобайт не трагедия.

P.S.S. Да, думаю многие люди могут осуждать меня, «надо экономить, быстрая загрузка, экономия памяти», а в итоге это все лишь затрудняет дальнейшую разработку. Просто нужно все делать грамотно, не перегибая палку. В итоге, экономите на ресурсах компьютера, растрачиваете свои физические ресурсы, растрачиваете ресурсы пользователя, сокращаете время разработки. Все равно придется чем то жертвовать.
Видимо, вы где-то промахнулись в своих расчетах.
Давайте посчитаем, что дает уменьшение количества файлов:

1) Не надо посылать новый запрос, а значит, экономим на request/response header'ах, что уменьшает трафик. не смейтесь, для мелких файлов (1-2 кб) совокупный размер хедеров вполне сравним с размерами самого файла.
2) Не надо ждать загрузки файлов (а ведь она складывается из ping+request_time+ping+download_time). а это порядочный выигрыш во времени, а не в трафике. Вы еще считаете?
3) Уменьшение и сжатие файлов дает уменьшение размера страницы с ~800 KB до 140 KB. Теперь умножаем на, скажем, 100 000 уникальных посетителей в месяц, получаем неплохую экономию трафика для сервера, не так ли?

С учетом всего вышеперечисленного, на канале ~100 MB/S с использованием клиентской оптимизации сайт появляется на экране компьютера мгновенно после клика на ссылку, без нее — где-то через 5-6 секунд. Разница, по моему, громадная.
Я бы еще добавил, что не стоит забывать, сколько одновременных соединений поддерживают современные браузеры, да и сам Windows, если не серверная версия, по дефолту поддерживает 10 одновременных полуоткрытых соединений. Если его не патчить, то любые сайты с большим количество ресурсов открываются достаточно долго.
Да, справедливое уточнение.
У вас много сайтов, которые открываются (становятся доступными для чтения, прокрутки и кликанья) меньше чем за 1с с момента ввода адреса или щелчка по ссылке? Нет? Может у вас медленный интернет или слабый компьютер, а может просто много вебмастеров-чайников с таким же пождходом к разработке сайта.
(с горечью глядя на vkontakte.ru) иногда все же все решает канал…
Ну, кстати, конкретно этот случай (vkontakte.ru) не показателен.

Мне кажется, его успех заключается в первую очередь потому, что «Content is the King» — там контент, там удобно, там куча людей.

Ну и, во вторых, его делали очень грамотные люди — я знаком с несколькими разработчиками, и они свое дело знают туго.
Возможно немного не в тему, но раз вы занимались клиентской оптимизацией… то вдруг.
Бьюсь над проблемой отжирания памяти страницей.
Смотрел IEWatche'м, данных (страница+скрипты+стили+картинки) приходит на 200Кб. Смотрел sIEve и JS Memory leaks detector'ом — утечек нет. Искал потенциальные источники утечек — не нашёл.
Тем не менее, после загрузки отъедает +30Мб оперативки, а после выгрузки 10Мб не отдает. Т.е. пять раз на страницу зашел, 50Мб не вернутся до закрытия браузера.
Есть идеи куда копать? Может существует утилита, показывающая распределение памяти по DOM/JS-объектам?
P.S.: извините, наболело :( Уже у всех спрашиваю.
JS Memory leaks == Drip? тогда фиг знает. Но могу посмотреть
Не могу дать посмотреть, технические сложности — доступа не дадут, сохраняться не умеет. Только не надо про кривые руки :)
Поэтому ищу способ/инструмент решения проблемы.
профилирование — на каждый чих вставлять задержку и смотреть, что память отъедает и не возвращает. Более интеллектуального, к сожалению, нет.
И вот этим (а также тупым комментированием addHandler'ов) я и занимаюсь второй день. Нереально грустно.
И Drip'ом тоже смотрел.
Боюсь, что быстрого автоматического способа не знаю. Ниже sunnybear указал тот способ, что я хотел предложить.
Вот мне иногда кажется, что должна существовать утилита, показывающая число живых объектов JS и DOM. Те же sIEve и Drip умеют подсчитывать число ссылок JS-объектов на DOM-элементы.
Кажется, такую даже написать не очень сложно (в JS не так много типов, рефлексия в самом сердце).
Но вот гугл молчит. Коллега пробовал написать — не получилось (не помню почему).
Вот и я не знаю, хоть я и не гугл :)
Возможно, выходом будет переписать все навешивания addEventHandler через какой-нибудь framework вроде jQuery или YUI. И удалять элементы с помощью них же. Они гарантируют, что убирают все ссылки на dom element'ы из javascript и наоборот.
Firebug — не оно? И под IE есть
Не совсем. Можно посмотреть: какие файлы и каких размеров скачались, полазить по DOM, подебажить JS, но не палит утечки и не показывает у кого сколько ссылок. Причем, лучше занимаемый объем объектов по этим ссылкам и возможность агрегации (чтобы по всем узлам не бегать).
Либо я не умею пользоватье файрбагом, что вполне допустимо :)
Пардон за стиль изложения — с утра и до сих пор дебажу.
кстати, попробуйте вставить перед каждым удалением элемента что-нибудь вроде метода purge от Дугласа Крокфорда:

function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}


Пробовал. И даже учитывающую особенности ASP.NET Ajax функцию (которая корректно диспозит, а я корректно отписываюсь) использую. Вот здесь пример этой функции.
и перед использованием innerHTML на все уже существующие элементы внутри контейнера (которые удалятся) прогоняете?
Да. Я читал про утечки — как исконно IE-шные, так и добавленные (PDF) ASP.NET Ajax'ом, — и такие моменты тоже выискивал. Впрочем, есть повод для радости — понизили приоритет задачи :) Фффух. Буду подробнее изучать.
с мнением jslint не все согласны, кстати
Ну его можно по разному настраивать.
Ну и кроме того, всегда полезно послушать критику jslint относительно своего кода :)
Лично я тоже не следую абсолютно всем рекомендациям в strict-режиме, очень уж это накладно.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Ну, в моем случае выбор пал на ант потому, что мы программируем на java, и наши проекты собираются maven + ant. Выгоднее и для оптимизации использовать уже используемую технологию.

Ну а насчет использования xml+regex — то, что я не люблю эти технологии не означает, что я не могу ими пользоваться. Хотя вы не поверите — писал и плакал, писал и плакал :)
НЛО прилетело и опубликовало эту надпись здесь
упс :)
комментарии я навешивал уже после того, как написал скрипт, халтурил, пользовался Ctrl-V -> Ctrl-C, и вот результат :)
Штука неплохая, но обладает рядом не очень удобных (для меня, по крайней мере) особенностей:

1) Он каждый раз при отдаче файлов заново проводит всю обработку. Не верите? Вот цитата из фака, пункт первый:
With Minify you will ideally serve fewer requests, but Minify can be slower than your HTTPd serving flat files

2) Он работает под апач. У нас, к примеру, апач на последних проектах вообще не используется (раньше использовался как frontend-сервер в связки nginx+jboss+apache, сейчас перешли на nginx+jboss).

3) Он работает на php5. Проблема в том, что многие компании (и мы в том числе) вообще не используем php. И ставить его ради таких случаев — не слишком разумно.

Но вообще — большое спасибо за ссылку, думаю, я покопаюсь в исходниках и найду что-нибудь полезное для своего скрипта.
НЛО прилетело и опубликовало эту надпись здесь
1) То, что исходники потеряются — бред. Для хранения исходников предназначен репозиторий системы управлениями версий (те же subversion и git). И место для исходников — рабочее место программиста и тот же репозиторий. Ну, еще бэкап репозитория. Все. Сервер, на котором исходники могут посмотреть все желающие — бред. Сервер не для этого предназначен. А на девелоперской машине все исходники остаются в прежнем виде.

2) Моя реализация работает быстрее. Вот почему: этот скрипт один раз за билд (т.е. развертывание приложение на сервере) склеил все, сжал и заботливо положил в папочку к nginx. А тот его сжал с помощью gzip и положил рядышком два варианта — сжатый и сжатый. И когда клиент просит контент, он смотрит, поддерживает ли клиент gzip, и если да, отдает ему пожатый, если нет — отдает ему непожатый (gzip'ом). И потом это все добро еще и кеширующий прокси закешировал. Кроме того, бьюсь об заклад, что ant-скрипт отработает в разы быстрее аналогичного php-скрипта (в данном случае под словом аналогичный я понимаю «имеющий один и тот же алгоритм»).

А в вашей реализации на каждый запрос клиента будет отрабатывать php-скрипт (+compressor), а это нагрузка. Маленькая, но все же. А что, если посетителей будет очень много? Возможно, отдача flat-файлов как раз и даст ту необходимую экономию ресурсов, которая позволит серверу не захлебнуться под валом запросов.
Впрочем, простите, я слишком резко ответил.

Ваш вариант тоже вполне себе жизнеспособное и обладающее рядом плюсов (как минимум, нет столько xml-a :) решение.

Видимо, мне очень дорого свое детище, аж на людей начал кидаться :)
Есть ещё такая полезная штука js-builder. Склеивает файлы в нужном порядке. Проект хранится в xml-ке. Есть консольный и гуёвый вариант.
Легко прикручивается к проектам на пару с яха копрессором.
Да, мне js-builder тоже понравился. Он как-раз делает все, что нужно.
К сожалению, он обладает одним, но очень существенным недостатком. Он только под win-платформу.
А у нас в команде половина разработчиков сидит под *nix, сервер (где это развертывание должно происходить) под *nix, я вообще белая ворона — у меня мак.
Там исходники открыты, может быть попробуйте собрать под Mac и nix используя mono-project?
В принципе, можно попробовать. Посмотрю, поверчу.
Сливаем все css-файлы, за исключением тех, имя которых начинается с ie_ в один файл с уникальным именем (имя такое же, как и в предыдущем пункте, только расширение сменится на `css`). Порядок следования в данном случае не важен.


Как это порядок не важен? А если, например, один и тот же класс (правило и т.д.) переопределяется или дополняется по-ходу проета?

Простите, но если по ходу проекта один и тот же класс переопределяется, то после сливания останется только последний вариант. При чем в данном случае неважно, какой именно вариант затерся, а какой нет — в любом случае на клиенте получится кака.

Такие css файлы просто напросто нельзя сливать. И получается только два варианта:
1) не переопределять классы по ходу проекта.
2) не сливать эти файлы.
Наверно, и я, и вы просто не правильно выразились, отсюда и непонимание.
Я имел ввиду следующее: что будет если в результирующем файле поменять местами код reset.css и того файла, в котором эти стили переопределяются, после сброса?
Да, вы абсолютно правы, css тоже надо сливать с соблюдением порядка. Я версткой редко занимаюсь и по мелочи, поэтому сразу не представил такой вариант :)

Это легко реализовать, по аналогии с js-файлами. Сейчас я занят, но как освобожусь, доработаю пример.
НЛО прилетело и опубликовало эту надпись здесь
Ага, уверен. Мы все-все сливаем в один файл.
У нас на последнем проекте вес исходников js-кода порядка 1 мегабайта (правда, та же jQuery не сжатая, и плагины к нему тоже не сжатые, да и код у нас хорошо задокументирован).
После склеивания и сжатия получается один файл размером в 98 KB. По моему, нормально. Грузится очень быстро, и функционал для всех страничек готов.
А если бить js на core-файл и кучку специализированных для каждой странички файликов, то будет все медленнее в итоге грузиться, уже не из-за трафика и размеров файлов, а из-за того, что запросы-то все равно проходят, и специализированный файл будет грузиться как минимум (ping + request_process_time + ping + download_time). Я подробнее уже вот тут отвечал.

Итого — выгоднее клеить все. Правда, есть еще одно правило:
1) Если объем сжатого js-кода больше 100 KB, то правильнее бить его на части, чтобы браузер мог грузить его в два потока. Или больше частей.
2) Если объем сжатого js-кода больше 500 KB, то надо его переписывать, т.к. такое количество js-кода просто убъет интерпретатор javascript (т.е. вкладка начнет тормозить сразу после загрузки кода, а через минуту работы подвесит весь браузер) во всех браузерах, кроме chrome.
НЛО прилетело и опубликовало эту надпись здесь
1) По поводу работы скрипта на слабой машине: все ок. Наши скрипты написаны следующим образом: есть объект manager, который следит за тем, в на каком этапе бизнес-процесса находится пользователь (грубо говоря, на какой страничке). И есть куча других объектов, которые умеют что-то делать. И на каждой странице сначала инициализируется менеджер, и вызывает initialize у тех объектов, которые нужны пользователю на этой странице. А у всех остальных объектов вызывается метод shutdown, который их удаляет из памяти. Таким образом, расход памяти минимален для каждой страницы.

2) Нет, никакой задержки незаметно.

Вся фишка в специфике работы алгоритмов сжатия. Специфический для каждой страницы скрипт, будучи прибавлен к результирующему файлу и вместе с ним сжатый, увеличивает размер получающегося файла на несколько сотен байт максимум. А если бы он gzip-пился и жался отдельно, то его размер был бы 2-3 KB.

Так что в итоге выгоднее все грузить одним файлом.

НЛО прилетело и опубликовало эту надпись здесь
засекалось, отчего же.
на 1Гб машине Pentium 3 533 (меньше не достали :) win XP sp2 на ie6 отрабатывает за 120 мс.
НЛО прилетело и опубликовало эту надпись здесь
Как же писали выше, склеивание всех файлов в папке — неправильный подход по двум причинам:
1. Придётся явно указывать порядок склейки и в будущем не забывать его обновлять.
2. Невозможно выделить большой функционал, использующийся на одной странице, в один файл и грузить его только для этой страницы.

А какой же подход правильный? Ответ: импорты и инклюды.
1. В html подключается файл project.css, который импортирует стили проекта в нужном порядке. После него подключается файл project.ie.css, импортирующий версии стилей для IE.
2. Подключается файл project.js, который инклюдит скрипты проекта в нужном порядке. (Написание функции include() оставляю в качестве домашнего задания.)
3. При выкладывании вёрстки на продакшн скрипт-сборщик проходится по файлам project.css, project.ie.css и project.js, рекурсивно заменяет строчки @import и include() на содержимое указанных файлов, сжимает получившиеся файлы компрессором и сохраняет под исходными именами, добив в начало знак подчёркивания.

Если для некой страницы выгодно выделить большой функционал в отдельный файл, то заводится page.css/page.js, содержащий необходимые импорты/инклюды, и также скармливается сборщику. Итоговый файл подключается только на данной странице, не увеличивая размер проектного файла.

Подсказка: если в начало project.ie.css добавить импорт файла project.css и проставить правильные условные комментарии для IE, то он будет грузить один файл вместо двух.
Спасибо за интересный комментарий.

1) Чем именно хранение порядка склейки файлов в скрипте (и который, к слову, можно вынести как в файл пропертис, так и вообще включить в шаблон, как описано в пункте TODO) отличается от хранения порядка склейки в файле project.js/css? Я думаю, только тем, что вам нравится один вариант, и не нравится другой. Что так в одном файле все лежит, и надо не забывать обновлять список, что эдак.

2) JavaScript. Очень и очень редко нужно указывать пофайловый порядок для склейки, чаще всего нужно указать только, какой файл (обычно — javascript framework) должен идти первым, и какой файл (какой-нибудь файл, в котором все инициализируется) должен идти последним. Порядок включения остальных файлов совершенно не важен и не сделает новых ошибок. Короче говоря, я считаю, что тот синтакс, что описан в TODO, гораздо лучше, чем ваш или мой способ.

3) CSS. В принципе, для css верно все, что сказано выше, хочется только уточнить один момент, насчет объединения файлов стилей в один. Пожалуйста, покажите пример сжатого какой-нибудь утилитой объединенного css-файла, в котором есть как обычные data:URL'ы, так и специализированные для использования в ie mtm'ы. Я уверен, что вы не предоставите, потому что после сжатия YUI Compressor'ом (или другой утилитой) картинки не будут отображаться в ie. Именно в этом причина того, что для ie заводится отдельный файл, который не обрабатывается сжималкой (и не включается из-за своего веса в общий css), а не в том, что условные комментарии представляют какую-нибудь сложность для освоения.

4) Отдельные файлы для отдельных страниц — если использовать тот синтакс, что описан в TODO, то составит отдельный файл для отдельной страницы — раз плюнуть.
1) Мы не затронули вопрос подключения файлов в разработке. При описанном мной способе достаточно подключить файлы project.*, которые сами нативно подключат все необходимые файлы. При этом они будут непожаты, чтобы сильно облегчит дебаггинг. Как подключаете файлы вы? Пересобираете при каждом изменении?

2) Согласен, порядок подключения скриптов редко важен. Однако сам механизм исключения по маске менее универсален, нежели механизм явного включения по имени. Если вы при явном указании списка файлов забудете подключить какой-либо скрипт, то сразу это заметите, получив ошибку. Если же при методе исключений вы забудете удалить неактуальный файл из папки, то он продолжит участвовать в сборке, понапрасну увеличивая итоговый размер.

3) При использовании указанных технологий (я не использую) файл лучше не сжимать, в этом вы правы.
1) Не могу не признать вашу правоту — действительно, для большинства платформ мой способ не слишком хорош в этом плане — мы действительно автоматически генерируем из шаблонов velocity и css и javascript, но нам удобно это делать просто потому, что проект так или иначе собирается с помощью ant, так что на общее время ожидания и сборки это никак не влияет.

2) Ну, ничто не мешает слегка переписать скрипт с тем, чтобы он понимал имена файлов, а не маску.

В целом — позвольте сказать вам спасибо за важные замечания, надеюсь, они помогут всем, кого интересует тема оптимизации.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации