Introduction
When you use multiple CSS files in project, for each CSS file it makes extra HTTP request to server. Even though you use ASP.NET theme, it breaks out into multiple CSS files. Also, if you minimize the size of CSS files, then your page will load faster.
Background
In development time, you might want to organize CSS into multiple files and with proper whitespace and comments. But you should keep in mind that Internet Explorer 6, 7 do not support more than 31 CSS files in a single page. In case of deployment, you can combine multiple CSS files into a single CSS file and also minimize size of file using minifier like YUI compressor for loading your page faster. Here I have given a way to combine multiple CSS files and also minify CSS and JavaScript files.
Implementation
If you use ASP.NET theme, then there would not be any direct reference of CSS link in your page. So combining multiple CSS files into a single file does not affect application wide. You can combine multiple JavaScript files into one using composite script references in the Script Manager Combining Client Scripts into a Composite Script. Here, I will discuss only deployment time process which will help to load your page faster. So, I only minify JavaScript files using Nant.
For automating all these processes, I used NAnt tool. Combining multiple files into one file is easy in NAnt using Nant tasks. Also for minifying CSS and JavaScript files, I used YUI compressor.
First, I discuss process steps before going to an example:
-
Combine all CSS files into one files. NAnt gives you an easy way to do this using Nant concat task.
-
After combining multiple CSS files and JavaScript files are minified using YUI compressor. YUI compressor safely minimizes your CSS and JavaScript file size.
-
Add creating a single CSS file in project and removing other unused CSS files from project reference so that it does not break your setup and after deployment you get only one compressed CSS file.
I have attached my Nant.build file here and in my previous two articles, Work Flow of Build Automation and Automate Publishing a WebSite into IIS using MSDeploy and NAnt Scripts, I have discussed steps of my build process and also there I have described NAnt scripts.
In this article, I am using the same script and will describe about scripts which combine CSS files and minify JavaScipts and CSS files.
I have given a code block which combines multiple CSS files into a single style.css file and deletes other CSS files from Theme folder.
Multiple files can be concatenated using Nant concat task which is found after loading Nant contrib.Task.dll and for that, you need to have NAnt contrib DLL registered or you can add <loadtasks assembly="${NAntContrib}\NAnt.Contrib.Tasks.dll" />
before calling <concat>
task.
<target name="css" description="Concatenate CSS source files">
<loadtasks assembly="${NAntContrib}\NAnt.Contrib.Tasks.dll" />
<echo message="Building ${BuildDir}\${CssFileLocation}\style.css" />
<concat destfile="${BuildDir}\${CssFileLocation}\style.css" append="true">
<fileset>
<include name="${BuildDir}\${CssFileLocation}\*.css" />
<exclude name ="${BuildDir}\${CssFileLocation}\default.css"/>
</fileset>
</concat>
<echo message="${BuildDir}\${CssFileLocation}\style.css built." />
<echo message="delete other files except style.css" />
<delete>
<fileset>
<include name="${BuildDir}\${CssFileLocation}\*.css"/>
<exclude name="${BuildDir}\${CssFileLocation}\style.css"/>
<exclude name ="${BuildDir}\${CssFileLocation}\default.css"/>
</fileset>
</delete>
<echo message="delete other files except style.css is done" />
</target>
In theme folder, I had seven CSS files. You can see CSS files in CssFileLocation folder is concatenated into a single style.css file, but here I have also excluded default.css file. You might have a CSS file that will be loaded dynamically and have alternate style which style.css contains. So I have excluded default.css file in my project. After this operation, I have only two CSS files under CssFileLocation which are style.css and default.css.
For minimizing the size of CSS files and JavaScipts files, I used YUI compressor, the article YUI Compressor and NAnt nice scripts file for minifying CSS and JavaScripts and I also took help from that code. Here is my code:
<target name="JavaScript.minify">
<foreach item="File" property="filename">
<in>
<items>
<include name="${BuildDir}\${JsFileLocation}\**\*.js"/>
<exclude name ="${BuildDir}\${JsFileLocation}\jquery.min.js"/>
<exclude name ="${BuildDir}\${JsFileLocation}\jquery.min-vsdoc.js"/>
<exclude name ="${BuildDir}\${JsFileLocation}\jquery-ui.custom.min.js"/>
</items>
</in>
<do>
<echo message="${filename}" />
<exec program="java">
<arg value="-jar" />
<arg value="${YUI}" />
<arg value="--type" />
<arg value="js" />
<arg value="-o" />
<arg value="${filename}.min" />
<arg value="${filename}" />
</exec>
<move file="${filename}.min" tofile="${filename}" overwrite="true" />
</do>
</foreach>
</target>
Here, I have excluded minifying jquery.min.*.js files as they are already minified. Also the CSS minifying code:
<target name="css.minify" depends="css" description="Minimize CSS files">
<foreach item="File" property="filename">
<in>
<items>
<include name="${BuildDir}\${CssFileLocation}\**\*.css"/>
</items>
</in>
<do>
<echo message="${filename}" />
<exec program="java">
<arg value="-jar" />
<arg value="${YUI}" />
<arg value="-o" />
<arg value="${filename}.min" />
<arg value="${filename}" />
</exec>
<move file="${filename}.min" tofile="${filename}" overwrite="true" />
</do>
</foreach>
</target>
But the problem is I had 7 CSS files under CssFileLocation folder which is the location of Theme folder. I have removed 6 CSS files - expect default.css in my 'css
' target but these files still have references in my web project file with <Content include="App_theme\Base\xxx.css"\>
tag. So after the above operations, it will give error when you create setup as content files are missing in your source project. So before you build your solution, you have to remove the references of those removed CSS files. I have used C# code for removing those references in WebProject.cproj.
This code first finds all references of CSS files in web project and then removes these references and also adds new style.css reference.
<target name="ReplaceCss">
<property name="filename"
value="${BuildDir}\Development\Client\Web\WebProject.csproj" />
<script language="C#">
<code>
<![CDATA[
public static void ScriptMain(Project project)
{
StreamReader projectFileReader =
new StreamReader(project.Properties["filename"]);
string x = @"<Content Include=\""App_Themes\\Base\\(?!Default)[\w-]*.css\"" />";
string output = @"<Content Include='App_Themes\Base\style.css'/>";
Regex sourcePathRegx = new Regex(x);
string projectFile;
try
{
projectFile = projectFileReader.ReadToEnd();
}
finally
{
projectFileReader.Close();
}
MatchCollection match = sourcePathRegx.Matches(projectFile);
if(match.Count>0)
{
int i = 0;
foreach (Match collection in match)
{
if(i==0)
{
projectFile = projectFile.Replace(collection.Value, output);
}
else
{
projectFile = projectFile.Replace(collection.Value, string.Empty);
}
i++;
}
}
StreamWriter projectFileWriter =
new StreamWriter(project.Properties["filename"]);
try
{
projectFileWriter.Write(projectFile);
}
finally
{
projectFileWriter.Close();
}
}
]]>
</code>
</script>
</target>
And as all these scripts need to run before creating build of solution, so I have called these targets before creating build using MSbuild.
<target name="BuildPublish" depends="setversion">
<call target = "css.minify"/>
<call target = "JavaScript.minify"/>
<call target = "ReplaceCss"/>
<echo message="Build solution"/>
<exec program="${MSBuildPath}">
<arg value="${BuildDir}\${SolutionFileName}" />
<arg value="/property:Configuration=release" />
<arg value="/t:Rebuild" />
</exec>
</target>
So after all these operations you have only two minified CSS files in which style.css file is a combination of 6 CSS files in your project. So now, you have only two HTTP requests to server whereas before it was seven HTTP requests. Also JavaScript codes are minified.
Point of Interest
The advantage of this process is that you are maintaining separate CSS files according to your module and also JavaScript, CSS files are readable with proper alignment as spaces. And only creating build of solution using automated build minifying and combining CSS and JavaScripts. So it does not hamper your CSS and JavaScript organization.