Click here to Skip to main content
Click here to Skip to main content

Central jQuery Version Control

By , 21 Oct 2013
Rate this:
Please Sign up or sign in to vote.

Introduction

This article describes a way for central control of jQuery version in an application which will make code consistent and make it easy to upgrade jQuery.

Background

I have been worked with a web application which has more than 10 years history. It has no centralized jQuery version control, and there are several different versions of the jQuery library co-existing in it, from 1.3.2 to 1.8.3. Each developer arbitrarily or randomly (from copy paste) decides a specific version jQuery he wants to use. Indeed sometimes jQuery is referenced in some pages whereas it has never been used at all (again, from careless copy paste). This brings many headaches, the same code may not be used in some other pages due to version differences, and if I want to upgrade jQuery I need to modify about 40 pages one by one. To get rid of this problem and make code easier to maintain, I came up with this solution.

Solution description

When I was thinking about this solution, I knew I needed to achieve two points:

  1. Centralize the jQuery version control;
  2. Allow the developer to freely choose any specific version jQuery as he wants (because of the reality that some jQuery plug-in has dependency on some specific older version jQuery).

It is not good to put a reference in the master page because:

  1. there are multiple master pages in the application
  2. many pages are not using jQuery so there is no reason for these pages to be loaded with jQuery by default.

The general idea is to override the Render event to force to inject a jQuery reference into the first position of the head segment

Step 1: Add a new key into web.config, which is the central place to store the standard jQuery version.

<add key="StandardJQueryVersion" value="1.10.1" / >

Step 2: Add an enum type to list all the jQuery reference modes. Here Standard means the current common jQuery version in the system, which is the newly added web.config key from step 1.

public enum JQueryReferenceMode
{
    None = 1,
    Standard,
    Customized
}

Step 3: As usual, the application has a base page class which is inherited by almost all of the web pages in the system. I add three class level variables to indicate the jQuery reference rendering mode.

protected JQueryReferenceMode mJQueryReferenceMode = 
          JQueryReferenceMode.None; //By default no jQuery reference
protected bool mIncludeMinifiedJQuery = true;
protected string mCustomizedJQueryVersion = 
  WebConfigurationManager.AppSettings["StandardJQueryVersion"];
  //If not assigned, use standard version as customized version

Step 4: Override the Render event of the base page:

protected override void Render(HtmlTextWriter writer)
{
    if (mJQueryReferenceMode != JQueryReferenceMode.None)
    {
        RenderWithJQueryReference(writer);
    }
    else
    {
        base.Render(writer);
    }
}

Add the method for rendering page with jQuery reference, standard or customized.

protected void RenderWithJQueryReference(HtmlTextWriter writer)
{
    System.IO.MemoryStream myMemoryStream  = new System.IO.MemoryStream();
    System.IO.StreamWriter myStreamWriter  = new System.IO.StreamWriter(myMemoryStream);
    System.Web.UI.HtmlTextWriter myHtmlTextWriter = new HtmlTextWriter(myStreamWriter);
    base.Render(myHtmlTextWriter);
    myHtmlTextWriter.Flush();
    myHtmlTextWriter.Dispose();

    System.IO.StreamReader myStreamReader = new System.IO.StreamReader(myMemoryStream);
    myStreamReader.BaseStream.Position    = 0;
    string pageContent = myStreamReader.ReadToEnd();        
    myStreamReader.Dispose();
    myMemoryStream.Dispose();
    if (pageContent.Trim().EndsWith("</html>"))
    //Only if it is rendering full html page content, not partial update.
    {
        //Find position of the head start tag
        //The header can contain id attribute, like "<head id='head1>",
        //so we cannot simply search by "<head>"
        int headStartTagBeginIndex = pageContent.IndexOf("<head", 0); 
        int headStartTagEndIndex   = pageContent.IndexOf(">", headStartTagBeginIndex);
        //Divide the page content in the position of the head segment's start tag.
        string pageContentPart1 = pageContent.Substring(0, headStartTagEndIndex + 1);
        string pageContentPart2 = pageContent.Substring(headStartTagEndIndex + 1);

        string jQueryVersionNumber = mJQueryReferenceMode == JQueryReferenceMode.Standard ? 
          WebConfigurationManager.AppSettings["StandardJQueryVersion"] : mCustomizedJQueryVersion;
        jQueryVersionNumber += mIncludeMinifiedJQuery ? ".min" : "";
        string jQueryPath = "../script/JQuery/jquery-" + jQueryVersionNumber + ".js";
        string jQueryReference = "\r\n <script src=\"" + jQueryPath + 
             "\" type=\"text/javascript\"></script> \r\n ";

        //Inject jQuery reference into the position right after the head segment's start tag
        pageContent = pageContentPart1 + jQueryReference + pageContentPart2;                        
    }

    writer.Write(pageContent);
}

Step 5: To reference the jQuery version you need, you only need to set the variables in the page_load event.

  1. Standard jQuery reference
  2. protected void Page_Load(object sender, EventArgs e)
    {
        mJQueryReferenceMode = JQueryReferenceMode.Standard;
  3. Customized jQuery reference
  4. protected void Page_Load(object sender, EventArgs e)
    {
        mJQueryReferenceMode = JQueryReferenceMode.Customized;
        mCustomizedJQueryVersion = "1.8.3";

Benefit

With this solution it becomes quite easy to control the jQuery version. If you want to upgrade your jQuery  version, you only need to change one key value in web.config. It is easy to roll back if you are not satisfied with the upgraded version of jQuery, just change it back. The developer no more needs to care about which version jQuery he is using, unless he wants to define the customized jQuery version in his page.

Some questions

Question 1: Why not use some more elegant code-behind to add a Literal control into the head's Controls collection, like this?

LiteralControl jQueryReferenceControl = new LiteralControl(
  "<script src=\"..script/JQuery/jquery.1.10.1.js\" type=\"text/javascript\"></script>");
Page.Header.Controls.Add(jQueryReferenceControl);

Answer: This code will break if the web page has a script block which contains a server tag, for example:

var nameTextBoxId = '<%= NameTextBox.ClientID %>';

Question 2: Why should the script be in the first position inside the head segment?

Answer: This guarantees that jQuery is always referenced before any script block that may contain jQuery code. I got some problems because of the JavaScript reference order.

Question 3: Why do we need this condition "if (pageContent.Trim().EndsWith("</html>"))"?

Answer: Partial update will not render full page HTML. In that case, there will be no head segment in the content. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sitang Ruan
Software Developer (Senior) TrafficTech Inc.
Canada Canada
I am Sitang Ruan, a .Net developer focus on web application development for 6 years. I like to write elegant and efficient codes to provide user a smooth and solid experience. I also like to take very complicated and challenging tasks.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140421.2 | Last Updated 21 Oct 2013
Article Copyright 2013 by Sitang Ruan
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid