YUI’s CompressorTask with MSBuild and Visual Studio
While trying to integrate YUI Compressor as a build task in my current project…
http://yuicompressor.codeplex.com/documentation
Post Build Event:
$(MSBuildBinPath)\msbuild.exe "$(SolutionDir)MinificationSettings.xml" /property:SourceLocation=$(ProjectDir) /p:JavaScriptOutputFile=$(ProjectDir)ContentMin\Scripts\Example.min.js /p:CssOutputFile=$(ProjectDir)ContentMin\CSS\Site.min.css
I got the error:
MSBUILD : error MSB1008: Only one project can be specified.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "c:\users\spade\documents\visual studio 2010\Projects\ExampleYUICompressorTask\MinificationSettings.xml"
/p:SourceLocation=c:\users\spade\documents\visual studio 2010\Projects\ExampleYUICompressorTask\MVCExample\
/p:JavaScriptOutputFile=c:\users\spade\documents\visual studio 2010\Projects\ExampleYUICompressorTask\MVCExample\ContentMin\Scripts\Example.min.js
/p:CssOutputFile=c:\users\spade\documents\visual studio 2010\Projects\ExampleYUICompressorTask\MVCExample\ContentMin\CSS\Site.min.css
It seems that the spaces in the folder path are preventing me from enjoying YUI Compressor. Quite the same problem this person is having: MSDN Forums: Unable to correctly pass parameters to MS build. Although I suspect he gave up a bit too early.
I tried adding quotes around the value of the parameters, you would think this is going to work, it doesn’t.
Looking for a way to replace the spaces, I came across MS Build Property Functions.
With Build Property Functions, it becomes possible to run the simple replace command in all the spots where I need to, my first guess was to replace space with ‘%20′. That had mixed results, so I was left with choosing an arbitrary token for replacement.
Post Build Event:
$(MSBuildBinPath)\msbuild.exe "$(SolutionDir)MinificationSettings.xml"
/p:SourceLocation=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])
/p:JavaScriptOutputFile=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])ContentMin\Scripts\Example.min.js
/p:CssOutputFile=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])ContentMin\CSS\Site.min.css
MinificationSettings.Xml:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
<UsingTask
TaskName="CompressorTask"
AssemblyFile="packages\YUICompressor.NET-MsBuild-Task.1.6.0.2\lib\NET35\Yahoo.Yui.Compressor.MsBuildTask.dll" />
<PropertyGroup>
<CssOutputFile Condition=" '$(CssOutputFile)'=='' ">SylesSheetFinal.css</CssOutputFile>
<JavaScriptOutputFile Condition=" '$(JavaScriptOutputFile)'=='' ">JavaScriptFinal.js</JavaScriptOutputFile>
</PropertyGroup>
<PropertyGroup>
<CssOutputFileFix>$(CssOutputFile.Replace('[[REPLACESPACE]]', ' '))</CssOutputFileFix>
<JavaScriptOutputFileFix>$(JavaScriptOutputFile.Replace('[[REPLACESPACE]]', ' '))</JavaScriptOutputFileFix>
</PropertyGroup>
<Target Name="MyTaskTarget">
<ItemGroup>
<JavaScriptFiles Include="$(SourceLocation.Replace('[[REPLACESPACE]]', ' '))Content\Scripts\Example.js"/>
<CssFiles Include="$(SourceLocation.Replace('[[REPLACESPACE]]', ' '))Content\CSS\Site.css"/>
</ItemGroup>
<CompressorTask
CssFiles="@(CssFiles)"
DeleteCssFiles="false"
CssOutputFile="$(CssOutputFileFix)"
CssCompressionType="YuiStockCompression"
JavaScriptFiles="@(JavaScriptFiles)"
ObfuscateJavaScript="True"
PreserveAllSemicolons="False"
DisableOptimizations="Nope"
EncodingType="Default"
DeleteJavaScriptFiles="false"
LineBreakPosition="-1"
JavaScriptOutputFile="$(JavaScriptOutputFileFix)"
LoggingType="ALittleBit"
ThreadCulture="en-au"
IsEvalIgnored="false"
/>
</Target>
</Project>
Using the registry to resolve Visual Studio reference paths.
Note: To skip the long journey of what lead me to figuring this out, click here to go to the howto.
Recently I was asked to look at a fiddler plugin Stan, the founder of this blog, was developing. He gave me a SVN path and asked me to build it and test it.
So I checked out the source code and hit F5. I got a bunch of compiler errors relating to the fact that I didn’t have fiddler installed. I rectified that matter and still got errors. The problem was that the hintpath of fiddler.exe was wrong. On my machine, Fiddler is installed in ‘C:\Program Files\Fiddler2\’, while on Stan’s machine it is installed to ‘C:\Program Files (x86)\Fiddler2′. I consulted the mighty google, which led me to a stackoverflow question. The question pointed out that you can have multiple hintpaths to an assembly. However, I wanted a better solution. What if someone installed Fiddler to a custom location?
I got the idea of using the registry. Fiddler has an installer. Surely the installer records its install location to the registry. It does in ‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fiddler2′ (Apparently fiddler is written by a Microsoft Employee). So the question is how to get MSBuild, the tool that visual studio uses to parse project files, to read a value from the registry.
The answer was found in a post on the MSBuild team blog.
How To
Unfortunately, Visual Studio does not allow you to edit hintpaths to referenced assemblies. So you’re going to have to edit your vcproj or vbproj file in notepad or some other text editor. Here are the steps:
- Open the project file in your text editor.
- Look for the <Reference/> element for fiddler.exe. It should look similar to this:
<Reference Include=”Fiddler, Version=2.2.7.5, Culture=neutral, processorArchitecture=MSIL”>
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files\Fiddler.exe</HintPath>
<Private>False</Private>
</Reference>
- Change the hintpath as follows:
<Reference Include=”Fiddler, Version=2.2.7.5, Culture=neutral, processorArchitecture=MSIL”>
<SpecificVersion>False</SpecificVersion>
<HintPath>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fiddler2@InstallPath)\Fiddler.exe</HintPath>
<Private>False</Private>
</Reference> - Save the file
- Visual studio will detect the file change and ask you to reload the file. If you are using SharpDevelop as you’re IDE, you will have to close and reopen the solution.
Thats all there is to it. Happy coding!