The blog of dlaa.me

Smaller is better! [A simple step to shrink the download size of Silverlight 2 applications]

When putting content on the web, it's important to get that content to the user as quickly as possible. In general, reducing the amount of data users need to download is a big step in the right direction. As such, the XAP packaging format used by Silverlight 2 wraps everything in a single, compressed archive file that's browser-friendly. At the moment, the compression for XAP files in Beta 2 is not as efficient as it could be, and XAP files tend to be a bit larger than necessary. Until this is addressed in a future release of the Silverlight tools, here is something that's almost as good. :)

XAP files are really just standard ZIP files with a different extension, so we can use ZIP-file tools to improve the XAP situation quite easily. I wrote a simple batch file named XapReZip.cmd (contents below) that can be added to a Visual Studio 2008 Silverlight project to automatically re-compress the project's XAP file more efficiently. All you need to do is add a single command to your project's post-build events (detailed below) and from then on all your XAP files will be even smaller and quicker to download!

To demonstrate its effectiveness, I've run XapReZip against three test applications, two simple demonstration applications of mine, and the current version of two professional-grade applications you're probably already familiar with. The table below shows the starting XAP file size, the size after running XapReZip, the difference between the two, and the percent difference. (All sizes are in bytes.)

Scenario Starting Size After XapReZip Difference Reduction
New Silverlight Project 3,980 3,202 778 20%
... with DatePicker 73,228 56,513 16,715 23%
... and DataGrid 194,452 151,646 42,806 22%
HtmlTextBlock 12,360 10,312 2,048 17%
SimpleSilverlightXpsViewer 13,879 11,408 2,471 18%
NBC Olympics Video Player 789,523 615,239 174,284 22%
Line Rider 789,496 538,784 250,712 32%

Basically, you can expect to see about a 22% reduction in size for XAP files in general - slightly less for code-intensive XAPs and potentially much more for larger, richer XAPs. For example, it looks like Line Rider could shave a quarter of a megabyte off its download size without breaking a sweat - which is even more compelling given how easy it would be! :)

The complete code for XapReZip.cmd is below. As written, XapReZip assumes that Zip.exe and UnZip.exe will be located in the same directory as XapReZip.cmd (this is easy to change) and that all of the files that are part of the XAP are available in the same directory as the XAP file itself (which just happens to be true after compiling with Visual Studio or MSBuild). For the purposes of this demonstration, I've used Zip 2.32 and UnZip 5.52 from the Info-ZIP group because they're free and have a nice license. Of course, you can use whatever tools you're most comfortable with.

@REM XapReZip - Recompresses XAP files smaller

@REM Invoke as a VS post-build event like so:
@REM C:\XapReZip\XapReZip.cmd $(TargetName).xap

@echo off
setlocal

REM Define paths to zip.exe and unzip.exe
set ZIPEXE="%~p0zip.exe"
set UNZIPEXE="%~p0unzip.exe"

REM Define paths for intermediate files
set XAP=%1
set XAPDIR=%~p1
set XAPBAK=%1.bak
set XAPZIP=%1.zip

REM Output a banner message
echo XapReZip: %XAP%

REM Change to XAP file directory
pushd %XAPDIR%

REM Create new XAP file with maximum compression
%UNZIPEXE% -Z -1 %XAP% | %ZIPEXE% -@ -9 -X %XAPZIP%

REM Abort if something went wrong
if ERRORLEVEL 1 goto :DONE

REM Replace original XAP file with smaller one
copy /y %XAP% %XAPBAK% > NUL
copy /y %XAPZIP% %XAP% > NUL
del %XAPZIP%

REM Output a success message
echo XapReZip: Success

:DONE

REM Restore previous directory
popd

endlocal

Adding XapReZip to a Silverlight Project in Visual Studio is easy. Just go to the Project menu, choose Properties (it's the last item), switch to the Build Events tab, and set a post-build event command line like this: C:\XapReZip\XapReZip.cmd $(TargetName).xap. Here's what it looks like in Visual Studio:

Configuring XapReZip as a post-build event in Visual Studio

After you've set that one command, you can forget about it - XapReZip will go to work every time you recompile the application and you'll be able to run and debug it just like always. Except a little smaller. :)

So if you're eager to keep your Silverlight applications as lean as possible, consider adding XapReZip to your project. It'll probably be the easiest 22% savings you get all day!

[XapReZip.cmd]