Idag satt jag och ändrade i mina CSS-filer, tog bort lite radbrytningar och liknande, för att minimera mängden data som måste skickas till klienten. Efter ett tag tänkte jag att det måste finnas ett sätt att automatisera detta. Först tänkte jag mig att jag skulle parsa igenom den renderade html-koden för att hitta <link>-taggar som pekade på css-filer, och sedan hänvisa om dessa till en WebHandler som parsar igenom samtliga filer och slår ihop dem, och tar bort radbrytningar och onödiga mellanslag.
Sen tänkte jag om, jag kom nämligen på att jag inte kan vara den första som har haft denna idé. Således gav jag mig på min favoritsökmotor (jag tänker inte säga vilken). Jag hittade på en blogg där någon beskrivit WebHandlern CssCompact, som verkade passa mina behov alldeles utmärkt. Den tar bort whitespaces och radbrytningar och annat onödigt från CSS-filen, men den fungerar bara för en CSS-fil åt gången. Jag valde därför att modifiera den något, så den kan ta mot flera parametrar, och på så vis slå ihop dem.
Anledningen till detta är dels att minska antalet Requests, men det hade jag ju kunnat göra genom att manuellt slå samman CSS-filerna. Nej, som Peter Westlund (Agilerate Design) påpekade för mig så gör det att jag kan hålla isär olika delar av designen, i olika filer. Det underlättar ju mycket för mig som utvecklare. Den färdiga koden ser ut som följer:
<%@ WebHandler Language="C#" Class="CssCompact" %>
using System;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;
public class CssCompact : IHttpHandler
{
public void ProcessRequest(HttpContext c)
{
string[] stylesheets = c.Request.QueryString["stylesheet"].Split(',');
for (int i = 0; i < stylesheets.Length; i++ )
{
string stylesheet = stylesheets[i];
c.Response.ContentType = "text/css";
if (stylesheet != null)
{
string filename = c.Server.MapPath(stylesheet);
if (filename.EndsWith(".css"))
{
if (File.Exists(filename))
{
FileInfo f = new FileInfo(filename);
c.Response.AddHeader("Last-Modified", f.LastWriteTime.ToString("U"));
c.Response.Expires = 0;
if (c.Request.HttpMethod != "HEAD")
{
using (StreamReader cssStream = f.OpenText())
{
// remove linebreaks, whitespace and comments
Regex remove = new Regex(@"^\s+|/\*([^*\\\\]|\*(?!/))+\*/|\r|\n|\t", RegexOptions.Multiline);
string cssContent = cssStream.ReadToEnd();
cssContent = remove.Replace(cssContent, "");
c.Response.Write(cssContent);
}
}
}
}
}
}
c.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
Det är två ändringar jag har gjort från grundkoden. Dels har jag lagt in en kontroll att det faktiskt är en CSS-fil du försöker parsa. Det är ett stort säkerhetshål i grundkoden, som gör att du kan hämta vilken fil som helst, till exempel web.config som kanske innehåller ConnectionString med både användarnamn och lösenord till databasen. Mycket slarvigt... Dessutom har jag gjort så att du kan skicka in flera stylesheets som QueryStrings, det är bara att ha ?stylesheet=MyStyle.css&stylesheet=OtherStyle.css osv. Hur många som helst.
Det man eventuellt skulle vilja göra är att implementera cache.
e3c231a5-3c1d-43f5-aaec-1b36e4cef949|0|.0