I wanted to try and come up with something that was a "best of both worlds" kind of solution. And so, I called once again upon my friend, the ColdFusion custom tag. I am not 100% satisfied with this solution, but I have built a small set of ColdFusion custom tags that allow you to list the files in the HEAD tag, as usual, but will compile the files and then write the HTML to link to the final file. Take a look at this example:
Notice that all the scripts were compiled down to a single, subsequent HTTP request.
While I like this, the down side to a technique like this is that it has to process the ColdFusion custom tags for every single page request; the nice thing about a build script, like an ANT script, is that it only has to be done once. But, like I said, I don't like "compilation gestures"; I find them to be not intuitive to your average programmer. So, to get around this, I tried to make the ColdFusion custom tags as clean as possible and have them build the file only when necessary, taking super care to read from the file system as little as possible!
The best I could do was limit the file reads to a single FileExists() on the target file for each page request. I am not sure if I am satisfied with this. I really don't like the idea of reading from the file system for every single request - this could become a huge overhead if I am not careful. I think I might dump the idea of checking file existence and make the rebuild process something that can only be launched manually using the RebuildParam. After all, it's not like I have to rebuild the file for every request - once the file is built, my only real responsibly, which is the largest use-case, is to output the SCRIPT or LINK tags.
Anyway, here is what I have so far. This is the Files ColdFusion custom tag:
The File tag doesn't have much to it. It basically just collects file paths and stores them in the base tag (Files):
<!--- Check to see which mode we are executing. ---> <cfswitch expression="#THISTAG.ExecutionMode#"> <cfcase value="Start"> <!--- Get base tag data. ---> <cfset VARIABLES.FilesTag = GetBaseTagData( "cf_files" ) /> <!--- Param tag attributes. ---> <!--- This is the expanded path to the given file. ---> <cfparam name="ATTRIBUTES.Path" type="string" /> <!--- Check to see if we even need to worry about this file. Only go further if the base tags contains the rebuild flag. ---> <cfif NOT VARIABLES.FilesTag.Rebuild> <!--- We have no need to use the child tag, so exit it without processing. ---> <cfexit method="exittag" /> </cfif> <!--- ASSERT: At this point, we know that the compiled file needs to be rebuilt and therefore we will need to check this child tag. ---> <!--- Store path in base tag. Check to see if the file exists so that we only have valid files passed up to the base tag. ---> <cfif FileExists( ATTRIBUTES.Path )> <cfset ArrayAppend( VARIABLES.FilesTag.FilePaths, ATTRIBUTES.Path ) /> </cfif> </cfcase> <cfcase value="End"> </cfcase> </cfswitch>
So, there you have it. Like I said, I'm not fully satisfied with it, but I think I am headed in the right direction. I didn't include any kind of file compression in this version. When reading in the individual files, I could have done things like strip out white space and comments, but this was more a proof of concept than a final product.
Want to use code from this post? Check out the license.