Главная > AJAX, ExtJS Framework, Open Source > Создаем собственную оптимизированную сборку фреймворка ExtJS

Создаем собственную оптимизированную сборку фреймворка ExtJS

9 ноября 2007

Если вы используете в своих проектах фреймворк ExtJS, то наверное заметили, что, несмотря на все преимущества и мощность, библиотека все же обладает достаточно большим размером, что сказывается на производительности приложений. Да и даже в минимальной версии нам нужно подгружать несколько файлов (в основном, два JS файла и два стилевых, не считая изображений), а это секунды времени ожидания, для медленных же соединений вообще проблема, часто такая система будет намного медленнее чем даже обычный сайт без AJAX-а.

Конечно, в правильно спроектированном приложении страниц, где подключаются все библиотеки, не так и много, и самым верным подходом является применение прелоадера (ну, например, выводить экран загрузки и активировать страницу только когда все загрузится). Но есть еще несколько путей, чтобы сэкономить самое ценно - время пользователя (и повысить скорость работы приложения).

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

Конструктор выполнен в виде простого двухшагового мастера, а одной из его самых важных особенностей является разрешение зависимостей (автоматическое), что позволит не задумываться какие конкретно файлы и компоненты требуются, а просто выбирать заранее указанные группы компонентов и указывать дополнительные опции, а конструктор сам определит, какие файлы включить в библиотеку. Давайте разберем его подробнее.

Сначала предстоит выбрать базовую библиотеку, которая буде подключаться. ExtJS имеет как свою основную библиотеку, так и может подключать через адаптеры другие популярные библиотеки - jQuery, Yahoo UI! и Prototype. В принципе, если вы не будете использовать какие-то особенности этих библиотек, например сторонние скрипты, требующие их функционала, то можно взять за основу и сам ExtJS (что и выбрано по умолчанию).

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

В ExtJS входят следующие модули:

  • Ext Core - самые базовые возможности, включая работу с DOM, событиями, основные эффекты, основной класс элемента, функциональность UpdateManager-а и базовые возможности AJAX. Он всегда включается в библиотеку.
  • Core - Utilites - расширение базовой функциональности, добавляющие работу о стилями, JSON данными, клавиатурой и другие обьекты. Используется довольно часто, поэтому рекомендуем включить.
  • Core - Date parsing and formatting - включает компонент работы с датами и временем. В принципе, если вы не сипользуете визуальные компоненты календаря, то можно не включать этот компонент.
  • Core - Layers - работа со слоями, основной компонент для реализации элементов интерфейса, он же поддерживает тени и основную функциональность компонентной модели виджетов, поэтому подключайте его обязательно.
  • Core - Drag and Drop - отвечает за реализацию функций перетаскивания элементов, а также расширяет функциональность элементов прокрутки. Полезен для реализации сложных интерфейсов, поэтому исходите из своих задач, возможно для простых интерфейсов он также буде лишним, но в больших проектах обязателен.
  • Core - State Manager - базовый класс для реализации менеджера состояний, честно говоря, не нашел ему применения так что решайте сами, нужно или нет.
  • Resizable - поддержка визуального изменения размера оконных элементов. Если вы, к примеру, используете только фиксированные диалоги или разметку страницы, то можно сэкономить и не отключить поддержку этого компонента.
  • QuickTips - элемент, реализующий динамическую подсказку в виде всплывающего окошка. Если вы проектируете интерфейс, то этот элемент очень вам пригодится, смело включайте!
  • Button Widget - элемент управления кнопка, наверное один из самых популярных, ни одна форма не обойдется без кнопок, поэтому включайте его (кстати, если вы хотите активировать опцию подсказок к кнопкам, вам нужен элемент QuickTips)
  • Tabs Widgets - реализует поддержку вкладочного интерфейса, что особенно полезно при создании насыщенных интерфейсов, где нужно показать много информации. Так что смело активируйте.
  • SplitBar Widget - требует поддержки Drag&Drop.
  • Menu Widget - реализует разнообразные меню, а также, опционально, сложные меню вроде выбора цвета или даты. Как ни странно, по моему, компонент не самых полезный, часто без него можно вполне обойтись.
  • Loading Mask Widget - реализует загрузчик, вернее его часть, отвечающую за индикацию процесса загрузки и активацию элементов интерфейса когда все загружено. Но ведь мы специально оптимизируем все так, чтобы не замечать длительного процесса загрузки? Так что можно и отключить.
  • Date и Color Picker Popup - меню, позволяющие выбрать дату и цвет из выпадающего меню. Если дата может еще пригодится, то выбор цвета функция довольно специфичная, поэтому можно опустить эти два компонента без особого ущерба для типичного приложения.
  • Border Layout Widget - реализация модульной разметки страницы, очень помогает при проектировании действительно приложений со сложным интерфейсом, так что советую обязательно включить, даже если вы создаете простую страницу, этот компонент вам еще пригодится.
  • Toolbar Widget - реализует массив элементов управления в виде строки (гм, как же правильно описать-то?). Довольно полезный для создания сгруппированных наборов элементов управления, поэтому включите его поддержку.
  • Dialog - базовый набор компонент для реализации различных диалоговых окон, самый важный и обязательный элемент интерфейса. Опционально можно включить поддержку вкладок, изменение размера и поддержку перетаскивания мышью. Практически всегда обязателен для подключения.
  • Dialog - Messages Box - реализует отдельный класс диалоговых окон, предназначенных для вывода информации об окончании какого-либо процесса или ошибках, также можно использовать для запроса подтверждения чего-либо у пользователя. Зависит от базового компонента диалогов и также обязателен для подключения.
  • Data Core - основные классы для работы с данными, в том числе и загрузкой с сервера, поэтому лучше подключить, он используется довольно активно.
  • Data - JSON Support - поддержка работы с данными в формате JSON. Он часто используется как удобный формат для обмена данными между клиентом и сервером, поэтому включите этот компонент в вашу библиотеку.
  • Data XML Support - аналогично JSON компоненту, но включает поддержку XML данных. Если же вы не работаете с ними, то можете не включать его, сэкономите на обьеме.
  • Data Simple Store - поддержка простого хранилища данных, которое позволяет извлекать данные из различных источников, в том числе и с сервера и представляет промежуточный унифицированный интерфейс для работы с ними. Рекомендую включить, это очень облегчит вашу работу с данными.
  • Views - Data bound Views - поддержка работы с видами (этот момент также я не разобрал, поэтому не буду ничего комментировать, хотя включить его нужно, он обнаружен в зависимостях к модулях форм).
  • Form - basic fields - обеспечивает основные возможности форм, включая базовые элементы виджетов, которые используются в формах. Для обеспечения динамической валидации вводимых данных нужно выбрать опциональный пакет VTypes.
  • Form - Date Field - поддержка элементов выбора даты в формах, если вы не используете этого, отключите модуль.
  • Form - Html Editor - поддержка визуального редактора текстов. Если вым необходимо вводить и форматировать большие обьемы текста, подключайте. Хотя, если нужны более мощные возможности, лучше использовать сторонний редактора, например, TinyMCE или FCKeditor.
  • Form - Ajax and Loading support - поддерживает отправку данных на сервер и обработку ответа, обязателен для включения если вы используете формы.
  • Form - Dynamic Rendering - поддержка рендеринга элементов формы, включите его.
  • Form - Floating Editor - обеспечивает встроенные возможности редактирования, в частности, в таблицах.
  • Grid - Core. Самый сложный и большой компонент, реализует таблицу с возможностями различного форматирования столбцов, динамического изменения их размера и положения и т.п. В зависимости от требуемого функционала вам нужно подключить дополнительные модули (поддержку Drag&Drop, редактора и другие). Если вы не используете таблиц, можете не подключать его.
  • Grid - Editing Support - поддержка встроенного редактирования данных в ячейках таблицы. Если вы будете использовать только базовые возможности таблицы, например, для отображения данных, то можете отключить редактирование.
  • Grid - Property Grid -обеспечивает расширенные возможности и свойства таблицы, поэтому включите его.
  • Tree - Core. Компонент, реализующий дерево элементов и базовые возможности его построения и операции над узлами. Если используете, к примеру, для отображения иерархических структур - включите его. Для дополнительных возможностей (фильтрация и сортировка, перетаскивание элементов) необходима поддержка соответствующих модулей.
  • Tree - Ajax Loading Support - поддержка динамической загрузки элементов, если планируете загружать данные с сервера или строить дерево из JSON данных - включите его.
  • Tree - Editing support - поддержка редактирования узлов непосредственно в компоненте. Если просто используете компонент для отображения данных - включать его не обязательно.

И так, мы рассмотрели все компоненты фреймворка, и теперь вы готовы к сборке своей собственной версии, которая будет использовать только нужные вам компоненты.

Также можно сделать несколько версий, если на разных страницах у вас используются разные возможности, то можно для каждой из них собрать свою версию библиотеки вместо одной универсальной. Конечно, это немного затруднит кеширование, но во многих случаях это реально сократит время загрузки страницы.

Второй шаг для обеспечения максимальной скорости работы приложения на ExtJS - уменьшения размера CSS стилей. Для приложения нужно как минимум два стилевых файла - ext-all.css и стиль выбранной темы оформления. Но это также значит, что браузер будет поочередно запрашивать два файла, причем основной стиль имеет большой размер - 58 Кб. Если вы не планируете использовать различные темы, то можете объединить эти два файла в один, а также, для еще большего уменьшения размера, удалить стили для тех компонент, которые вы не используете. Единственное, что останется теперь - это загрузка различных вспомогательных графических элементов, которые использует Ext для отрисовки элементов графического интерфейса.

А третий шаг это использование сжатия библиотек и других файлов. Для этого мы используем архиватор 7-Zip, в котором реализован механизм архивации GZip. Выбрав настройки (режим сжатия deflate, размер слова 64 или 128), что позволит сократить размеры файлов очень значительно.

Для примера, собранный файл ExtJS для моего проекта (включены все необходимые возможности, но глубокой оптимизации не проводил, поэтому его, думаю, можно еще сократить) весит 226.3 Кб, а единый CSS файл - 75.1 Кб. Если применить сжатие, то файлы уменьшаться - до 61.3 (ExtJS) и 11.5 Кб (CSS).

Firebug позволяет получить время загрузки каждого элемента страницы. При использовании локального веб-сервера среднее время загрузки библиотеки составило около 900 мс, а стилевого файла - 200 мс. Если подключать сжатые GZip-м файлы, то время уменьшится и составит примерно 600 - 700 мс и 100 -130 соответственно.

Я не ставил за цель провести серьезное исследование, но даже обычные эксперименты показывают, что вполне реально значительно уменьшить размер библиотеки и количество подключаемых файлов и это, в свою очередь, очень позитивно сказывается на быстродействии приложения. Конечно, для разработки лучше всего использовать полные версии библиотек, с включенной отладочной информацией, но при распространении готового продукта и при большой планируемой посещаемости экономия трафика будет вполне заметная.

В принципе, можно вполне использовать вместо ручной оптимизации простенький скрипт на стороне сервера, например на РНР, используя специальные классы для сжатия JavaScript кода, а также на лету архивировать все (например, модуль к веб-серверу Apache - mod_deflate), но это уже тема совсем другого материала.

P.S. А ведь можно использовать и хранилища на стороне клиента, например Google Gears или другие возможности, а самым лучшим выбором для этого станет Dojo toolkit, в состав котрого входят несколько классов для работы с разными хранилищами - на основе Flash и Java апплетов.

  1. vectoroc
    10 ноября 2007 в 14:01 | #1

    много воды…

  2. 10 ноября 2007 в 14:19 | #2

    ну, ввиду полного отсутствия данных по этой теме и фреймворку вообще я считаю что статья оправданна.
    и там вроде все по теме, где вы воду увидели? 😉 напишите лучше, а комментарии лучше использовать для дополнения или уточнения информации.

  3. 10 ноября 2007 в 15:52 | #3

    Спасибо за разъяснения, и русскоязычное описание модулей… Очень помогло

  4. LokiDi L0ck
    12 ноября 2007 в 17:48 | #4

    У меня несжатый ExtJs по данным FireBug загружается за 400-500 ms.
    И как писал Джэк (он рекуомендует всё таки не сжимать) на форуме — сжатые скрипты может и загружаются чуть-чуть быстрее, но браузеру так же необходимо время, чтобы его распоковать (а это время firebug не регистрирует).

  5. 12 ноября 2007 в 20:46 | #5

    в любом случае, распаковка сжатого намного быстрее, чем его передача, ведь размер последнего релиза вплотную приближается к мегабайту (три основных файла), время загрузки такого объёма на даже выделенке 256К достаточно больше. поэтому если делать заглавные страницы сайтов или часто посещаемые части на ексте — нужно тотально уменьшать объём.

  6. LokiDi L0ck
    16 ноября 2007 в 12:37 | #6

    При первой загрузке:
    1) Браузер запрашивает скрипт с сайта
    1) Сжатый скрипт загружается браузером
    2) Размещается в кэше в сжатом виде
    3) Распаковывается браузером
    4) Уходит в память

    При повторном запросе:
    1) Браузер запрашивает скрипт
    2) Сервер отвечает, что скрипт надо брать из кэша
    3) Сжатый скрипт достается из кэша
    3) Распаковывается браузером
    4) Уходит в память

    В случае, если скрипт не сжат — то он берётся из кэша без последующих операций распаковки, на которые уходит время. Об этом и было сказано на оф. форуме.

  7. 16 ноября 2007 в 13:45 | #7

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

    Спасибо за подробное описание, может статью-заметку напишите про механизм работы с кешем?

  8. LokiDi L0ck
    16 ноября 2007 в 16:26 | #8

    >все же время доставания из кёша и распаковка
    >намного быстрее сетевой передачи данных

    Немного поясню.
    Несжатый файл после первой загрузки тоже размещается в кэше. Только в дальнейшем ему не нужно распаковываться, и никаких «сетевых передач» тоже не происходит (кроме отсылки шапок с параметрами типа Last-Modified, Etag — по которым и определяется необходимость повторной загрузки файла с сервера).

    >может статью-заметку напишите про механизм работы с кешем?
    В сети много статей о кэшировании. Достаточно простого php-скрипта (или чему вы отдаете предпочтение) и firebug’а, чтобы побаловаться с заголовками и посмотреть на результаты.

  9. 16 ноября 2007 в 16:35 | #9

    меня заинтересовало, откуда именно данные, что сжатый файл хранится в памяти а не распакованый 🙂

  10. LokiDi L0ck
    22 ноября 2007 в 23:13 | #10

    Да, действительно, был не прав 😀

    Тогда другой вопрос, каким образом вы делали сжатие — посредством apache, серверного языка или сжимали сам файл и подключали его через

  11. LokiDi L0ck
    22 ноября 2007 в 23:14 | #11

    Через src=»script.js.gz» (Неожидал что теги буду вырезаны)

  12. 22 ноября 2007 в 23:24 | #12

    экспериментировал по разному — сначала скрипт через онлайновый сервис javascriptcompressor проганял, потом 7-Zip подбирал размер. вложился в 51 — 55 Кб собранного под себя Ext-а, ещё есть простор для оптимизации остальных файлов, в первую очередь CSS стилей.

    Кстати, недавно реализовал ещё один способ оптимизации, правда подойдёт ограниченному числу проектов — создание плагина-екстеншина к фаерфоксу с библиотекой и другими тяжёлыми файлами. ускорение в разы достигнуто.

  13. LokiDi L0ck
    23 ноября 2007 в 01:38 | #13

    Т.е. вы сжимали файл архиватором и подключали через src=”script.js.gz” тега script, или пользовались сжатием на лету со стороны сервера?

  14. 23 ноября 2007 в 10:56 | #14

    вручную и подключал. кстати 7 ИЕ не понял такого файла, 6 и фф и сафари — гуд, в общем есть много там ньюансов

  15. LokiDi L0ck
    2 декабря 2007 в 13:58 | #15

    При использовании mod_gzip и mod_deflate, Apache отсылает заголовок Vary, показывая кэшам, что данный объект отличается от других запросов для такого же объекта, основанных на определенном критерии — user-agent, charset и т.д.
    Когда сжатый объект принимается кешем, отмечается, что сервер вернул ответ: Vary: Accept-Encoding. Этот ответ показывает, что он был сгенерирован, основываясь на запросе, содержащем заголовок Accept-Encoding: gzip.
    Кеширование сжатого контента может привести к тому, что одновременно будут храниться две копии документа: сжатая и распакованная.

    Источник: http://www.nestor.minsk.by/sr/2004/06/40612.html

  16. 2 декабря 2007 в 14:24 | #16

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

  17. LokiDi L0ck
    2 декабря 2007 в 16:10 | #17

    Я тоже по-тихоньку экспериментирую.
    Пока результаты такие: extjs-all.js (2-ой версии), при включенном mod_deflate на сервере, сжимается до 133Кб.

    Шаги:
    1) Почистил кэш.
    2) Открываю страницу (где подключена наша библиотека)
    3) extjs-all.js (133Кб) загружается по показаниям FireBug в среднем за 550-600ms.

    После этого первого захода на страницу, extjs-all.js кладётся в кэш.
    Чтобы убедиться в этом, нажимаем f5.

    FireBug показывает, что все файлы были загружены из кэша — при этом размер extjs-all.js так и остался 133Кб. Т.е. в кэше он лежит в сжатом виде!
    И средняя загрузка его составляет опять же 490-550 ms. Разницы практически никакой.

    Собственно что представляют из себя эти 500ms? Это парсинг и загрузка в память браузером js-скрипта. В extjs функций довольно много, так что приходиться расплачиваться такой скоростью за огромную функциональность.

    Сжатие же в нашем случае играет роль только при первоначальной загрузке скриптов, и служит для экономии трафика, не более. В дальнейшем никаких плюсов по сравнению с несжатой версией у него нет. Т.к. оба берутся из кэша и оба загружаются в память почти с одинаковой скоростью.

  18. LokiDi L0ck
    3 декабря 2007 в 21:05 | #18

    Моё последнее сообщение в данной ветке =)
    После того, как разобрался с сжатием на лету, последовал совету некоторых забугорных статей и написал скрипт, объединяющий js и css файлы соответственно.
    Как оказалось, именно вариант с объединением дал отличный результат, которого я даже не ожидал.

    Пример объединяющего скрипта так же можно в extplorer’е. Его релизили на официальном форуме в одной из веток.

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

  19. интересующийся extjs
    14 декабря 2007 в 15:44 | #19

    Конечно же лучше пожалеть пользователя,
    и сэкономить его деньги на трафике.

    …или провайдеру помочь… смотря кто больше заплатит

    😆

    Еще давным давно, писал такой скрипт специально для собственного использования, который жмет gzip’ом страницы и перенаправляет ссылки документа на себя.

    Серьезно трафик экономил, раз в 6.

    Еще хотел сделать такую штуку, чтоб картинки облегчала.
    Например делать их ч.б. вариантом, или качество понижать.

  20. 14 мая 2008 в 23:27 | #20

    Привет, не знаю куда еще написать. У кого тормозит Ext при включенном файрбаге? У меня ФФ затыкивается на 5 секунд при обновлении страницы с локалки, хотя первый раз грузит моментально.

  21. 15 мая 2008 в 09:24 | #21

    не знаю, у меня не тормозит совершенно. зависит от браузера и плагинов и т.п. но то, что замедляется работа при отладчике это естественно, даже Google GMail предупреждает про это.

  22. 23 мая 2008 в 09:33 | #22

    в связи с большим потоком спама к этому материалу, комментирование запрещено. Думаю, скоро будет новая версия статьи.

Комментирование отключено.