Lately I’ve been working with Mads Kristensen on a cool new Visual Studio Extension, Farticus, and wanted to share with you guys one of the things that I learned.
When you are developing Visual Studio extension on of the things you should keep in mind is the download size of the extension. This is the size of the .vsix file which you upload to the gallery. If the download size is too large typically people may get impatient and cancel the install. Because of this it’s a good idea to try and get your .vsix to the smallest size possible.
The good news here is that the .vsix file is already compressed. It’s actually a .zip file renamed to .vsix. If you want to see what’s in a .vsix just rename it to .zip and extract it out. The bad news is that the CreateZipPackage task used by the Microsoft.VsSdk.targets file does not perform the best compression. Fortunately there are tasks to create Zip files that we can use. I have chosen to use the Zip task from the MSBuild Extension Pack.
Before I go over all the details let’s take a look at what the final result will be after we compress with the MSBuild Extension Pack. See the table below for the comparison for two different projects.
VSIX Size Before
VSIX Size After
|Farticus||442 kb||248 kb||43 %|
|VS Web Essentials||2102 kb||740 kb||65 %|
From the table above we can see that we can gain a significant amount of additional compression by using the MSBuild extension pack.
Below is the content that I pated into the .csproj file. I’ll paste it in it’s entirety and then explain.
<PropertyGroup> <EnableCompressVsix Condition=" '$(EnableCompressVsix)'=='' ">true</EnableCompressVsix> <BuildLib Condition=" '$(BuildLib)'=='' ">$(MSBuildProjectDirectory)\..\Build\Lib\</BuildLib> </PropertyGroup> <UsingTask AssemblyFile="$(BuildLib)MSBuild.ExtensionPack.dll" TaskName="MSBuild.ExtensionPack.Compression.Zip"/> <Target Name="CompressVsix" AfterTargets="CreateVsixContainer" DependsOnTargets="PrepareReplceVsixTemp" Condition=" '$(EnableCompressVsix)'=='true' "> <!-- copy the file to the obj folder and then party on it --> <MakeDir Directories="$(_TmpVsixDir);$(_TmpVsixDir)\Extracted\"/> <Copy SourceFiles="$(TargetVsixContainer)" DestinationFolder="$(_TmpVsixDir)"> <Output TaskParameter="CopiedFiles" ItemName="_TmpVsixCopy"/> </Copy> <!-- extract out the .zip file --> <MSBuild.ExtensionPack.Compression.Zip TaskAction="Extract" ExtractPath="$(_TmpVsixDir)Extracted\" ZipFileName="@(_TmpVsixCopy->'%(FullPath)')"/> <ItemGroup> <_FilesToZip Remove="@(_FilesToZip)"/> <_FilesToZip Include="$(_TmpVsixDir)Extracted\**\*"/> </ItemGroup> <MSBuild.ExtensionPack.Compression.Zip TaskAction="Create" CompressFiles="@(_FilesToZip)" ZipFileName="%(_TmpVsixCopy.FullPath)" RemoveRoot="$(_TmpVsixDir)Extracted\" CompressionLevel="BestCompression" /> <Delete Files ="$(TargetVsixContainer)"/> <Copy SourceFiles="%(_TmpVsixCopy.FullPath)" DestinationFiles="$(TargetVsixContainer)" /> </Target> <Target Name="PrepareReplceVsixTemp" DependsOnTargets="CreateVsixContainer"> <ItemGroup> <_VsixItem Remove="@(_VsixItem)"/> <_VsixItem Include="$(TargetVsixContainer)" /> <_TmpVsixPathItem Include="$(IntermediateOutputPath)VsixTemp\%(_VsixItem.Filename)%(_VsixItem.Extension)"/> </ItemGroup> <PropertyGroup> <_TmpVsixDir>%(_TmpVsixPathItem.RootDir)%(_TmpVsixPathItem.Directory)</_TmpVsixDir> </PropertyGroup> <RemoveDir Directories="$(_TmpVsixDir)"/> </Target>
The snippet above perform the following actions.
- Remove the old VsixTemp folder from any previous build if it exists
- Copy the source .vsix to the intermediate output path (i.e. obj\debug or obj\release)
- Extract out the contents to a folder
- Re-zip the file using MSBuild extension pack
- Replace the output .vsix with the compressed one
When building now the .vsix in the output folder should be smaller than it was before.
In my case I have copied the necessary assemblies from the MSBuild Extension pack and placed them in the projects repository. For the Zip task you’ll need the following files.
In my case I’ve placed them in a folder named Build\lib\.
You should be able to copy/paste what I have here into your VSIX projects. You’ll need to update the path to the MSBuild extension pack assemblies if you put them in a different location. Note: I’ve only tested this with Visual Studio 2012.
The MSBuild elements used here is pretty straight forward. If you have any questions on this let me know.
You can find the source for the Farticus project at https://github.com/ligershark/Farticus/. Please send us a Pull (my finger) Request.