Archiv für die ‘MSBuild’ Kategorie

Microsoft Ajax Minifier

Donnerstag, 12. November 2009

Bislang habe ich immer Packer von SmallSharpTools verwendet, um JavaScript Files für die Produktionsumgebung zu verkleinern und ggf. zu komprimieren.

Microsoft hat nun mit einer neuen Version ihrer Microsoft Ajax Library (ehemals ASP.NET AJAX) auch ein neues freies Programm, den Microsoft Ajax Minifier verfügbar gemacht. Anders als es der Name vermuten lässt, können damit jegliche JavaScript Files “minified” werden.

Ich habe es gleich im “Hypercrunch” Modus am Beispiel des jQuery Plugins für das Grid von etcetera.Mvc ausprobiert. und das Resultat hat mich überzeugt:

  • jquery-etcetera.js Entwicklerversion: 6′618 Bytes – 100%
  • jquery-etcetera.min.js mit Packer: 3′521 Bytes – 53%
  • jquery-etcetera.min.js mit Ajax Minifier: 2852 Bytes – 43%

Die geringere Grösse resultiert vor allem durch das Umbenennen von lokalen Variablen.
Das gute am neuen Tool ist, dass es auch einen MSBuild Task mitbringt, somit also ideal in den Build Prozess integriert werden kann.

Fehler im Build Prozess

Dienstag, 20. Oktober 2009

Ich war etwas voreilig mit meiner Anpassung des Build Prozesses. Ich wollte für einen Release Build automatisch alle relevanten Files in ein definiertes Verzeichnis kopieren. Dies funktionierte grundsätzlich auch sehr gut, nur hatte ich das Projekt noch nicht in ein Subversion Repository aufgenommen.
Sobald dies aber der Fall ist, fügt Subversion jede Menge eigene Dateien in die lokale Arbeitskopie ein. Diese befinden sich immer in versteckten .svn Verzeichnissen und enthalten Informationen über die lokale Arbeitskopie.

Wie kann man nun das Kopieren dieser Dateien verhindern? Glücklicherweise ist das ItemGroup Element in der Lage mittels des Exclude Attributs einen Filter für Dateien anzugeben:

<ItemGroup>
 <EtcDll Include="$(MSBuildProjectDirectory)\bin\Release\etcetera.Mvc.dll" />
 <MvcContrib Include="$(MSBuildProjectDirectory)\bin\Release\mvccontrib.dll" />
 <MvcContribLic Include="$(MSBuildProjectDirectory)\..\..\lib\MvcContrib\License.txt" />
 <Css      Include="$(MSBuildProjectDirectory)\UI\css\**\*.*"
           Exclude="$(MSBuildProjectDirectory)\UI\css\.svn\**\*.*" />
 <Images   Include="$(MSBuildProjectDirectory)\UI\images\etcetera\**\*.*"
           Exclude="$(MSBuildProjectDirectory)\UI\images\etcetera\.svn\**\*.*" />
 <Scripts  Include="$(MSBuildProjectDirectory)\UI\scripts\**\*.*"
           Exclude="$(MSBuildProjectDirectory)\UI\scripts\.svn\**\*.*" />
 <ZipFiles Include="$(MSBuildProjectDirectory)\Release\**\*.*" />
</ItemGroup>

Der Filter unterstützt auch Wildcards und kann auch für das Include Attribut angewendet werden.
Informationen zum eigentlichen Projekt folgen nächstens :-) .

Visual Studio Projekt Files für Release Builds erweitern

Dienstag, 13. Oktober 2009

Ich bin momentan in den Vorbereitungen um eine kleine Library auf CodePlex zu publizieren. Ich will auf der Projektseite nebst dem Source Code, den man ja einfach via Subversion Client hochladen kann, auch binäre Releases zum Download anbieten.

So ein Release von meinem kleinen Projekt besteht aber immerhin aus einigen Files. Nebst dem eigentlichen Assembly wären da noch Bilddateien, Stylesheets, JavaScripts und natürlich auch die notwendigen externen Libraries, die benötigt werden. Nun wäre es doch sehr mühsam, für jeden Release alle diese Dateien immer wieder einheitlich und genau gleich zusammenzukopieren. Zum Glück lässt sich dies relativ einfach mit einer kleinen Erweiterung des Visual Studio Projektfiles erreichen.

Die Visual Studio Projektdatei ist sogar schon dafür vorbereitet. Am Ende jeder .csproj Datei (wahrscheinlich in ähnlicher Form auch bei .vbproj Files) findet man folgenden Kommentar:

<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
 Other similar extension points exist, see Microsoft.Common.targets.
 <Target Name="BeforeBuild">
 </Target>
 <Target Name="AfterBuild">
 </Target>
 -->

Microsoft hat also zwei definierte Targets vorgesehen, welche für eigene Erweiterungen genutzt werden können. Wenn nun der Build beendet wird, wird das Target “AfterBuild” ausgeführt. Hier kann man also durch eigene Tasks wiederkehrende Aufgaben automatisieren lassen. Das Zusammenkopieren meiner Dateien in einen Release Ordner und Anlegen einer Zip Datei wird so zum Kinderspiel:

<PropertyGroup>
  <MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\..\..\lib\MSBuild.Community.Tasks</MSBuildCommunityTasksPath>
  <ReleasePath>$(MSBuildProjectDirectory)\..\..\Release</ReleasePath>
</PropertyGroup>

<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />

<Target Name="AfterBuild" DependsOnTargets="ClearRelease" Condition="'$(Configuration)' == 'Release'">
  <!-- Create an item collection of assemblies and other artifacts produced by the build -->
  <ItemGroup>
    <EtcDll Include="$(MSBuildProjectDirectory)\bin\Release\etcetera.Mvc.dll" />
    <MvcContrib Include="$(MSBuildProjectDirectory)\bin\Release\mvccontrib.dll" />
    <Css Include="$(MSBuildProjectDirectory)\UI\css\**\*.*" />
    <Images Include="$(MSBuildProjectDirectory)\UI\images\**\*.*" />
    <Scripts Include="$(MSBuildProjectDirectory)\UI\scripts\**\*.*" />
    <ZipFiles Include="$(MSBuildProjectDirectory)\Release\**\*.*" />
  </ItemGroup>

  <Copy SourceFiles="@(EtcDll)" DestinationFolder="$(ReleasePath)" />
  <Copy SourceFiles="@(MvcContrib)" DestinationFolder="$(ReleasePath)\Dependencies" />
  <Copy SourceFiles="@(Css)" DestinationFolder="$(ReleasePath)\css" />
  <Copy SourceFiles="@(Images)" DestinationFolder="$(ReleasePath)\images\etcetera" />
  <Copy SourceFiles="@(Scripts)" DestinationFolder="$(ReleasePath)\scripts" />

  <!-- Create a release zip file using the MSBuild Community tasks -->
  <ItemGroup>
    <ZipFiles Include="$(ReleasePath)\**\*.*" />
  </ItemGroup>
  <Zip Files="@(ZipFiles)" ZipFileName="$(ReleasePath)\etcetera.Mvc.zip" WorkingDirectory="$(ReleasePath)" />
  <Message Text="Copied all etcetera.Mvc files to folder $(MSBuildProjectDirectory)\Release" Importance="high" />
</Target>

<Target Name="ClearRelease">
  <ItemGroup>
    <OldReleaseFiles Include="$(ReleasePath)\**\*.*" />
  </ItemGroup>
  <Message Text="Clearing files in folder $(ReleasePath)" Importance="high" />
  <Delete Files="@(OldReleaseFiles)" />
</Target>

Das Zusammenstellen des Releases soll aber nur stattfinden, wenn auch die “Release” Konfiguration ausgewählt ist. Dafür kann das Target eine Condition auswerten. Zuvor sollen aber die Files des letzten Builds gelöscht werden, deshalb wird das “AfterBuild” Target vom “ClearRelease” Target abhängig gemacht. Somit wird dieses zuerst ausgeführt.

Zusätzlich zu den von Microsoft bereitgestellten Tasks (wie Copy, Delete etc.) lassen sich auch eigene oder Tasks von Dritten verwenden. Mein Beispiel verwendet den Zip Task der äusserst praktischen MSBuild Community Tasks.

Wenn ein Text im Output Fenster von Visual Studio ausgegeben werden soll, muss das “Importance” Attribut des Message Tasks auf “high” gesetzt werden.

Wenn die Projekt Datei derart angepasst wird, kann es sein, dass Visual Studio beim Laden des Projekts warnt, dass die Projektdatei erweitert wurde.