As I use more and more JavaScript and Ajax on my sites the number and the size of the JavaScript include files grow. What do to about this? jQuery comes in a uncompressed and minimized version, ideally I want to use the first on my Dev-box and the second on the production server. Asp.net 3.5 SP1 comes with the feature CompositeScript which allows us to combine several script into one download. Well, I am trying to get away from the asp.net ScriptManager, so I came up with my own solution.
The first version supports the following:
During development the fullsize script files are used
In Production mode, a single minimized file is used that includes all the JavaScript code needed for the page.
This file is not generated on the fly, instead it is stored on the file system. This makes it more scalable.
Here’s how in works:
All my common JavaScript include files are in one location /css/. Instead of referencing them with
<script src="../css/jquery.js" type="text/javascript"></script> <script src="../css/topas.js" type="text/javascript"></script>
On the page, I just have a single literal control:
<asp:Literal runat="server" ID="litSciptIncludes"></asp:Literal>
Which results in the following html:
<script src="../css/lib/3.js" type="text/javascript"></script>
3.js has the compressed content of both jquery.js and topas.js
In the Page_Load method in code behind I have some code to add scripts:
ScriptIncluder inc = new ScriptIncluder();
inc.AddScript(ScriptIncluder.Scripts.jQuery);
inc.AddScript(ScriptIncluder.Scripts.Topas);
litSciptIncludes.Text = inc.GetIncludes();
The ScriptIncluder class is responsible for building the <script src…> tags. We add all the scripts we need on the page with the AddScript method, a fixed number of scripts are defined in a enumeration.
[Flags] public enum Scripts { jQuery = 1, Topas = 2, TopasDate = 16, TopasEdit = 32, jQueryUI = 256, jQueryMaskedEdit = 512, } public void AddScript(Scripts scriptID) { _scripts.Add(scriptID); _scriptCode += (int)scriptID; }
In my application framework I have a setting in the web.config which defines the Debug-Mode, when in development I just loop through all the added scripts and return one <script> tag for each added script. However when in production, I return a single script tag that points to a single file.
public string GetIncludes() { string html = string.Empty; string start = "<script type=\"text/javascript\" src=\"" + Core.Config.VirtualRoot + "css/"; string end = "\"></script>" + Environment.NewLine; if (Core.Config.CurrentDebugLevel >= Core.Config.DebugLevels.SharedDev) { // include plain text files foreach (Scripts script in _scripts) { html += start + _scriptNames[script] + end; } } else { // include compressed file html = start + "lib/" + _scriptCode + ".js" + end; } return html; }
_scriptNames[] is a generic list of all the script file names, _scriptCode is the sum of all the scriptIDs as defined in the Scripts enumeration.
So where do all the /css/lib/nn.js files come from that are needed for the single compressed file?
I use a batch file to create them:
pushd \websites\foo\wwwroot\css jsmin.exe lib/769.js jquerymin.js jqueryuimin.js jquery.maskedinput.js jsmin.exe lib/819.js jquerymin.js jqueryuimin.js jquery.maskedinput.js topas.js topas.date.js topas.edit.js jsmin.exe lib/49.js topas.js topas.date.js topas.edit.js jsmin.exe lib/3.js topas.js jquerymin.js jsmin.exe lib/1.js jquery.js popd
In theory I need hundreds of these /lib/nnn.js files, but in practice there are only a few combinations that I use. What is jsmin.exe? It is a small tool based on Douglas Crawford’s jsmin (http://www.crockford.com/javascript/jsmin.html). He has C# code to minimize a single JavaScript file. I added some code to process any number of files into a single file. I can just run the batch file every time I have changed any of my JavaScript include files and can also make it part of my build process.
Any drawbacks? If every page uses a different combination of include files, all these combinations have to be downloaded once and then cached, so the actual jQuery code may be downloaded several times.