Pull to refresh

Xaps Minifier. Дополнение для Visual Studio 2010, позволяющее уменьшать размер Silverlight приложений

Reading time 6 min
Views 1.9K
Я постоянно работаю с Silverlight приложениями и выкладываю релизы регулярно. Как правило, я использую паттерн MVVM и его реализацию Prism. В результате создаётся несколько XAP файлов, содержащих сборки приложения и манифест.

Каждый, кто работает в соответствии с таким подходом, замечает, что большинство XAP файлов содержат дублирующиеся сборки. Например, при использовании библиотеки Prism, практически каждый XAP файл будет содержать все сборки из этой библиотеки. Prism добавляет порядка 300 Кб к каждому XAP файлу, что может увеличить размер приложения более чем на 1 Мб (при наличии 4-5 XAP файлов). Кроме того, дополнительные библиотеки (в первую очередь UI элементов) могут ещё более увеличить размер приложения.

Все эти факты заставили меня начать поиск пути уменьшения размеров XAP файлов.

Идея


Я работал над одной проблемой, когда наткнулся на заметку в блоге Jeff Prosise. Он упоминал, что сборка может быть добавлена в приложение, но не в XAP файл. Для этого достаточно установить параметр

CopyLocal=false

для каждой требуемой сборки, которая находится в списке References. В этом случае проект будет ссылаться на нужную сборку, но не будет добавлять её в папку bin при компиляции.

Это натолкнуло меня на мысль, что всем дублирующимся сборкам в приложении можно проставить

CopyLocal=false

не изменяя только параметры сборок главного XAP файла. Именно главный XAP файл должен содержать все дублирующиеся сборки, которые будут автоматически загружаться в Application Domain, и будут доступны для всех сборок из остальных XAP файлов.

Так будет выглядеть солюшн после минимизации

Картинка выше демонстрирует, как солюшн будет обновлён, если его изменить в соответствии с описанными выше правилами. Представим, что каждый проект является отдельным XAP файлом. В таком случае, Project 1 и Project 2 содержат одинаковую пару сборок (Assembly 1 и Assembly 2), и я устанавливаю для них CopyLocal=false для исключения их из Project1.xap и Project2.xap.

Сборка 1 (Assembly 1) уже находится в главном проекте (Main Project), а потому его добавлять в главный проект не требуется. В отличие от неё, Сборка 2 (Assembly 2) должна быть добавлена в главный проект для обеспечения работоспособности первого и второго проекта.

Проект 2 (Project 2) содержит сборку 4 (Assembly 4), которая уже присутствует в главном проекте — исключаем эту сборку из проекта 2.

Проект 3 (Project 3) не изменяем, т.к. он содержит только уникальные сборки.

Давайте просуммируем, что было оптимизировано:
Проект Число сборок в XAP до оптимизации Число сборок в XAP после оптимизации
Project 1 4 2
Project 2 4 1
Project 3 3 3
Main Project 3 4
Итого 14 10

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

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

Реализация дополнения


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

  1. Получение всех Silverlight проектов. Поиск основывается на том, что файл проекта содержит параметр

    ProjectTypeGuids

    Он содержит GUID, который указывает на тип проекта (консольное приложение, asp.net приложение и т.д.)
  2. Поиск главного проекта. С этого проекта начинается запуск приложения и именно в него следует добавлять дублирующиеся сборки из других проектов. Поиск основывается на значении параметра проекта

    SilverlightAppEntry

    Если этот параметр инициализирован именем валидного (присутствующего в проекте) класса, то такой проект является главным в приложении.
  3. Получение списка дублирующихся сборок. Происходит обход всех Silverlight проектов приложения и запоминаются все сборки, которые встречаются более двух раз
  4. Добавление сборки-дубликата в главный проект, если её там нет.
  5. Устанавливаем для сборки параметр

    CopyLocal=False

    во всех проектах, где она встречается, кроме главного проекта.

В результате выполнения этого алгоритма, текущее приложение в Visual Studio будет обновлено. Его можно будет сразу скомпилировать и увидеть разницу в размерах XAP файлов.

Визуализация работы


Visual Studio позволяет использовать различные встроенные механизмы для отображения текущего состояния выполняемого дополнения.

Я выбрал четыре варианта:
  1. Анимация. В строке состояния отображается анимированная иконка в течении всего процесса работы дополнения
  2. Указатель прогресса. В строке состояния показывается процент оптимизации относительно каждой сборки-дубликата
  3. Текстовое сообщение. В строке состояния показывается текстовое сообщение о текущем выполняемом шаге дополнения
  4. Логирование действий в OutputWindow. В отдельное окно выводятся все сообщения за время работы дополнения

Публикация дополнения


Для того, что бы опубликовать дополнение на Visual Studio Gallery, достаточно иметь Live аккаунт, зайти на сайт галереи, нажать Upload и следовать за мастером публикации дополнения.

Установка дополнения


Самым быстрым и удобным вариантом установки дополнения является использование Visual Studio Gallery. Для этого достаточно в Visual Studio 2010 открыть Visual Studio Extension Manager (главное меню-Tools-Extension Manager), выбрать Online Gallery, и ввести “xap” в Search Online Gallery поле. После этого можно выбрать Xaps Minifier и нажать Download — загрузка и установка дополнения начнутся.

Установка дополнения через Visual Studio Extension Manager

Использование дополнения


После установки и перезапуска Visual Studio, следует загрузить Silverlight проект, вызвать контекстное меню для солюшена и выбрать пункт Minify Xaps.

Запуск дополнения

Будет запущен процесс анализа и оптимизации приложения, а прогресс будет отображаться в строке состояния Visual Studio. После окончания процесс оптимизации, появится диалоговое окно с информацией, сколько сборок удалось исключить из приложения, на сколько сборок увеличился главный проект и в какое число проектов были внесены изменения.

Оптимизация реальных проектов


Первым тестовой программой была моё демо-приложение, которое я представил на конференции Remix10. Это приложение содержало 5 Silverlight проектов и 4 XAP файла. Размер неоптимизированного приложения составлял 1.2Мб, а после оптимизации оно уменьшилось до 500 Кб. Вместе с тем, размер главного проекта увеличился с 120 Кб до 400 Кб.

Вторым приложением было Prism Demo приложение, представленное John Papa на конференции PDC09. Это приложение содержало 7 Silverlight проектов и 4 XAP файла, а общий размер XAP файлов составлял 5.7 Мб. После оптимизации это приложение уменьшилось до 1.6 Мб(!!!).

Известные аналоги


Мне не известны прямые аналоги моей реализации дополнения к Visual Studio. Но тема оптимизации размера Silverlight приложений актуальна, а потому такие компании как Component One и Telerik предлагают свои инструменты. В отличии от моей идеи, они используют совершенно другой подход. Их инструменты анализируют готовый XAP файл, находят неиспользуемый код (классы, XAML код) и удаляют его из сборок.

На мой взгляд, это в некоторой степени спорное решение. Вот мои аргументы:
  1. Я могу загружать классы динамически, а это нельзя отследить. В этом случае, мне следует помнить все классы/контролы, которые не следует удалять. Это может привести к резкому снижению стабильности приложения, повышению нагрузки на отдел тестирования и пр. Моё дополнение не изменяет никакие сборки, а потому намного безопаснее.
  2. Я не думаю, что сторонние поставщики платных библиотек будут включать в лицензионные соглашения пункт о согласии модификации их библиотек. Именно это сейчас происходит при работе инструмента компании Component One. Мне кажется, что это просто незаконно.
  3. Я и мой коллега Алексей потратили на этот проект около одной человеко-недели. Упомянутые компании потратили гораздо больше времени и усилий.
  4. Моё дополнение не зависит от библиотек, которые используются в приложении. В тоже время, Telerik Assembly Minifier может оптимизировать только библиотеки Telerik.
  5. При использовании моего дополнения, разработчикам не требуется проводить повторную оптимизацию приложения при появлении новых версий библиотек

В любом случае, моё дополнение может быть использовано совместно с инструментами Component One XapOptimizer и Telerik Assembly Minifier.

Текущие ограничения


В настоящее время дополнение не работает с:
  • Silverlight for Windows Phone 7;
  • XNA for Windows Phone 7;
  • Silverlight for Symbian;

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

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

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

Благодарности


Хотел бы высказать благодарность моему другу и коллеге Алексею Гладких за реализацию прототипа алгоритма оптимизации XAP файлов.

Исходные тексты


Последние исходные тексты можно скачать здесь. Инсталляцию дополнения можно загрузить c официальной страницы дополнения на сайте Visual Studio Gallery или установить через Visual Studio Extension Manager (см. выше).

Поделитесь своим опытом


Мне очень важно получить отклик реальных пользователей дополнения. Пожелания, которые я уже получил, позволили сделать XAPs Minifier удобнее и быстрее. Ваши замечания могут вывести его на новый уровень.

Надеюсь, что этот инструмент станет must have для каждого Silverlight разработчика.
Tags:
Hubs:
+20
Comments 5
Comments Comments 5

Articles