How we did it: mavention.nl – Part 2a: Dealing with minified files

Header of the www.mavention.nl website.
In the previous part of the How we did it series about our new website I told you about how we optimized our website for performance. One of the optimization techniques that we applied was minifying asset files such as CSS and JavaScript. While minification allows you to decrease the size of files it has one serious disadvantage: it often makes them unreadable. So how did we deal with it?

Minification 101

Minification is a well known process of decreasing the size of files. Depending on the type of the file that you want to minify there are often multiple minification approaches: from the most simple one such as removing optional characters such as spaces and tabs, to more complex ones where the contents are being modified and optimized for smaller footprint.

In our scenario we chose for the highest compression level. While our choice offered us the biggest benefit of the minification process it introduced another challenge: how to deal with the minified contents in the development process?

After reviewing all options such as manual switching the references in the Master Page and custom HTTP Handlers which would do the minification on-the-fly, we decided on a slightly different approach, one that is closer to what SharePoint 2010 uses itself.

Minification in SharePoint 2010

If you have looked carefully at how things work under the hood in SharePoint 2010 you might have noticed that SharePoint 2010 ships with two versions of every JavaScript file: a debug one which is readable and ends with .debug.js and the release one which is minified and ends with .js. Depending on the value of the debug setting in web.config SharePoint 2010 dynamically loads either the debug version of the JavaScript file or the release one. And this is exactly the approach that we decided to use on our website.

Minification @ mavention.nl

For our new website we decided to work with two version of files: original (raw) and minified. Depending on the configuration of the website we would dynamically load the raw or the minified version. To support both CSS and JavaScript files we decided to create two custom controls that would allow us to dynamically create references to the right versions of CSS and JavaScript files.

First we created a control for creating JavaScript references:

public class ScriptLink : Control  
{
    public string Src { get; set; }
    public bool WithDebug { get; set; }

    protected override void Render(HtmlTextWriter writer)
    {
        if (!String.IsNullOrEmpty(Src))
        {
            string scriptSrc = SPUtility.GetServerRelativeUrlFromPrefixedUrl(Src).Replace("~Locale/", SPContext.Current.Web.Locale.LCID + "/");

            if (WithDebug && HttpContext.Current.IsDebuggingEnabled)
            {
                scriptSrc = GetDebugUrl(scriptSrc);
            }

            writer.Write("<script type=\"text/javascript\" src=\"{0}\"></script>", scriptSrc);
        }
    }

    private static string GetDebugUrl(string url)
    {
        string debugUrl = url;

        if (!String.IsNullOrEmpty(debugUrl))
        {
            debugUrl = String.Concat(debugUrl.Substring(0, debugUrl.LastIndexOf('.')), ".debug.js");
        }

        return debugUrl;
    }
}

The first thing that we do here is building the URL. Using the SharePoint’s tokens capability (~SiteCollection/ and ~Site/) we can turn dynamic URLs into static ones. Additionally, to support multilingual solutions, we extended the standard tokens list with a custom ~Locale/ token which is being replaced with the locale of the current site.

Once we have the URL in place we check if the script has a debug version available (the WithDebug parameter is set to true) and if the website is running in debug mode (the HttpContext.Current.IsDebuggingEnabled property is set to true). If that is the case we dynamically turn the JavaScript URL into its debug equivalent.

Finally the JavaScript link is being rendered as a reference using the script HTML tag.

Having the ScriptLink control in place we can use it easily in our Master Pages and Page Layouts as follows:

<Mavention:ScriptLink Src="~SiteCollection/_layouts/maventionnl/js/mv-maventionnl.js" WithDebug="true" runat="server"/>  

We use a similar control for dynamically loading CSS files:

public class StylesheetLink : Control  
{
    public string Href { get; set; }
    public bool WithDebug { get; set; }

    protected override void Render(HtmlTextWriter writer)
    {
        if (!String.IsNullOrEmpty(Href))
        {
            string stylesheetHref = SPUtility.GetServerRelativeUrlFromPrefixedUrl(Href);

            if (WithDebug && HttpContext.Current.IsDebuggingEnabled)
            {
                stylesheetHref = GetDebugUrl(stylesheetHref);
            }

            writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
            writer.AddAttribute(HtmlTextWriterAttribute.Href, stylesheetHref);
            writer.RenderBeginTag(HtmlTextWriterTag.Link);
            writer.RenderEndTag(); // link
        }
    }

    private static string GetDebugUrl(string url)
    {
        string debugUrl = url;

        if (!String.IsNullOrEmpty(debugUrl))
        {
            debugUrl = String.Concat(debugUrl.Substring(0, debugUrl.LastIndexOf('.')), ".debug.css");
        }

        return debugUrl;
    }
}

It can be used similarly to the ScriptLink control:

<Mavention:StylesheetLink Href="~SiteCollection/_layouts/maventionnl/css/styles.css" WithDebug="true" runat="server"/>  

By using our ScriptLink and StylesheetLink controls we can easily switch between the raw and minified version of our asset files without touching the code. This allows us to easily perform changes on the asset files in the development process as well as benefit of the optimizations in the production environment. Additionally, because we provide the minified versions manually ourselves, we avoid the penalty for dynamically generating the files what would take place if used a custom HTTP Handler instead.

What’s next

In the next part of this How we did it series, I will tell you, as promised, about how we optimized our site for search engines. Stay tuned!

Technorati Tags: SharePoint 2010,Web Content Management,Mavention

Comments

comments powered by Disqus