Configuration, Directories, and Builds for Javascript Web Applications
A lot of attention is paid to the structure of files and directories for server side web applications, and the use of swappable configuration. Think build scripts and ant. But almost none has been paid to the ideal structure for files that will be used by the client, such as javascript. In the past, javascript was just an afterthought stuck onto web pages. But that is no longer the case. And with today’s complicated javascript driven web applications, we have to start thinking about how to best structure our files to allow for easier development, maintenance, and creation of build scripts.
As you know, I use Dojo as my javascript toolkit of choice. Dojo’s file structure has matured and is now quite conducive to creating your own parallell structure. Their shrinksafe build system is quite flexible, and can easily optimize your script and get it ready for production. I think spending the time up front thinking about file structure and configuration, and giving at least a little thought to what your ultimate build will look like, will pay significant dividends in the long run.
My web application structure looks like this:

A little explanation:
- Notice the /web/config directory. This is where I setup my djConfig variable. I make sure to make this the first script included on my pages. On a production server, this is just an empty file, since djConfig is baked into the scripts with shrinksafe.The content of this file configues djConfig, and then includes the dojo file and the corresponding “pages” javascript file (see below).
/** * include this file with a SCRIPT tag on each dojo page * @author maulin */ djConfig = { isDebug:true, debugAtAllCosts:false, modulePaths:{medryx:"../../medryx"}, modulePaths:{pages:"../../pages"}, usePlainJson:true //for MOCKS ONLY }; var CURRENT_PATH = window.location + ""; //the path to dojo can be created from the /pages directory var PATH_TO_JS = CURRENT_PATH.substring(0, (CURRENT_PATH.indexOf('/pages'))) + "/lib/js"; //now include the dojo.js document.write(""); //finally include the page-specific javascript document.write(" "); This is actually quite magical, and allows for a lot of flexibility without having to touch your html (or your graphic designer’s html for that matter!)
- The dojotoolkit contains the source folders from Dojo, and contains the dojo, dijit, dojox, and util directories.
- Next, notice the “medryx” folder that is a sister to dojotoolkit. This is where all of my javascript lives. I’ll describe its configuration in my next post.
- The js/pages directory is a folder for all page-related javascript. This is where I handle the dojo.require statements, and any specific page related javascript. Each page has a corresponding file in this directory (that is automatically injected into each page).
- The lib/mock and lib/asp folders are the implementation of my RPC services. The asp folder uses ASP (duh), and the mock uses javascript via my MockJsonService. You could also create a php, or any other script-language implementation of rpc services in these folders. Or, if using J2EE with JSP for the service, the JSP files could live in a jsp folder (Though, if you are using RPC with java, you could avoid this altogether with a JSON-RPC servlet, but that is way beyond the scope of this post!).
- The /pages directory contains all my html pages. You may need an index.html at / that redirects to your home page in the pages directory.
- The /themes directory contains the css for the project. The css is setup in two types of files: “theme” css files that use css-includes to include all the appropriate css styles for all the widgets for a particular theme into one file (e.g. tundra.css), and the other that is the specific css for this application, and uses css includes to include the “theme” of choice as well as any page-specific css for this application’s pages.That sounds complicated. Let me illustrate:
tundra.css
@import url("../lib/js/dojotoolkit/dojo/resources/dojo.css"); @import url("../lib/js/dojotoolkit/dijit/themes/tundra/tundra.css"); @import url("../lib/js/medryx/widgets/themes/tundra/tundra.css"); @import url("../lib/js/dojotoolkit/dojox/grid/_grid/tundraGrid.css");site.css
@import url("tundra.css"); body { /* snip */ }
So this leaves me with a very simple html header for my pages that looks like:
<head> <title>My Home Page</title> <script type="text/javascript" src="../config/dojo-config.js"></script> <link rel="stylesheet" type="text/css" href="../themes/site.css" /> </head>
And with a simple change to my dojo.config.js, I can completely change what happens on the production server versus in development. For example, I can change the dojo loading script tag to my compiled, optimized javascript file created by shrinksafe.
In this post I describe a simple folder structure that leads to easier development, maintenance, and conversion from development to production (or other) environments. I hope you found it helpful. In my next post about this, I will dive little deeper into my “medryx” js folder and describe how it can be used to make unit testing and development consistent and simple!
[...] Friends « Configuration, Directories, and Builds for Javascript Web Applications [...]
Pingback by Medryx Observations » Blog Archive » Configuration, Directories, and Builds for Javascript Web Applications (Part 2) — June 8, 2008 @ 12:36 am