Wednesday, 29 June 2011

Combining resources

It is recommended that you download all your scripts/styles in a single request to the server, instead of getting files one by one, thus blocking the browser.

So, instead of:


   <script type="text/javascript" src="../Scripts/romama.js"></script>
   <script type="text/javascript" src="../Scripts/notes.js"></script>

I really want to have something like this:

   <script type="text/javascript" src="../Scripts/combined.js"></script>


Even if there are ready-to-use solution available, like Yahoo! combo handler, this never stopped me before from implementing my own custom solution.

What I want for myself is to be able to put one single script tag in a master page and have all my scripts downloaded as a single file.

    <script type="text/javascript" src="CombineResources.axd?type=script"></script>

I am going to achieve this with the custom HttpHandler, which will know which resources are needed for any particular page. Here is implementation:

public class CombineResources : IHttpHandler
{
       #region Static Members

       private static Dictionary<string, List<string>> ScriptMap = new Dictionary<string, List<string>>()
       {
              {"/Notes/CategoryEditor.aspx", new List<string>() {"/Scripts/romama.js", "/Scripts/categoryEditor.js"}}
       };

       #endregion

       #region IHttpHandler Members

       public bool IsReusable
       {
              get { return true; }
       }

       public void ProcessRequest(HttpContext context)
       {
              string resourceType = context.Request.QueryString["type"] as String;
              if (String.IsNullOrWhiteSpace(resourceType))
              {
                     return;
              }

              string localPath = context.Request.UrlReferrer.LocalPath;
              string combined = context.Cache[localPath + ":" + resourceType] as String;
              if (combined != null)
              {
                     context.Response.Write(combined);
                     return;
              }

              List<string> resources = new List<string>();
              if (resourceType == "script")
              {
                     if (ScriptMap.ContainsKey(localPath))
                     {
                           resources = ScriptMap[localPath];
                     }
              }
              else if (resourceType == "style")
              {
                     // TODO:
              }
              else
              {
                     throw new InvalidOperationException(String.Format("unrecognized resource type: {0}", resourceType));
              }

              StringBuilder sb = new StringBuilder();
              foreach(var resource in resources)
              {
                     sb.AppendLine(File.ReadAllText(context.Server.MapPath("\\") + resource));
              }
              sb.AppendLine(@"// Generated: " + DateTime.Now.ToLocalTime());
              context.Response.Write(sb.ToString());
              context.Cache.Insert(localPath + ":" + resourceType, sb.ToString(), null, DateTime.UtcNow.AddMinutes(1), Cache.NoSlidingExpiration);
       }

       #endregion
}

The thing I need to look into is whether the scripts going to be cached in a browser.

No comments:

Post a Comment