Apache2::Response::FileMerge - Merge and include static client-side style and code


Apache2::Response::FileMerge gives you the ability to merge, include, minimize and compress multiple js/css fles of a single type into a single file to place anywhere into an HTTP document, all encapsulated into a single mod_perl Response handler.


Problem(s) Solved

There are a number of best practices on how to generate content into a web page. Yahoo!, for example, publishes such a document ( and is relatively well respected as it contains a number of good and useful tips for high-performance sites along with sites that are less strained but are still trying to conserve the resources they have. The basis of this module will contribute to the resolution of three of these points and one that is not documented there.

File Merging

A common problem with the standard development of sites is the number of <script/>, <style/> and other static file includes that may/must be made in a single page. Each requiring time, connections... overhead. Although this isn't a revolutionary solution, it is in terms of simple mod_perl handlers that can easily be integrated into a single site. Look to 'URI PROTOCOL' to see how this module will let you programaticlly merge multiple files into a single file, allowing you to drop from 'n' <s(?:cript|style)> tags to a single file (per respective type).

File Minimization

A feature that can be administered programatically (see ATTRIBUTES), will minimize whitespace usage for all CSS/Javascript files that leave the server.

File Compression

A feature that can be administered programatically (see ATTRIBUTES), will gzip the content before leaving the server. Now, I can't ever imagine the need to apply compression to a style or script file without wanting to apply it to /all/ content. That said, I recommend the use of mod_gzip ( rather than this attribute. Still, I wanted to implement it, so I did.

C-Style Inlcudes

Merging files through a URI protocol is useful, however if you have a large-scale application written in javascript, you quickly introduce namespacing, class heirarchies and countless dependancies and files. That said, it's tough to ask a developer "List all the dependancies this class has, taking each of it's super-classes and encapsualted heirarchies into consideration". Most modern languages take care of this by allowing the developer to include it's particular dependancies in the application code in it's particular file. That said, this module lets you do the same thing with CSS and Javascript.

As an example:

     * foo/bar.js
     * @inherits foo.js

     // Rather tha including foo.js as it's required by foo/bar.js,
     // simply include it directly in the file with the following
     // syntax:

     /** Include foo.js **/
     Foo.Bar = {};
     Foo.Bar.prototype = Foo;

Where, with that example, the file 'foo.js' will be a physical replacement of the include statement and therefore will no longer need to be added to the URI.




Will enable HTTP 304 return codes, respecting the If-Modified-Since keyword and therefore preventing the overhead of scraping through files again.

Given the nature of the module, the mtime of the requested document will be the newest mtime of all the combined documents.

Furthermore, the server will only find the mtime of a collection of documents when it reads the disk for the content. Therfore, when enabled, any changes to the underlying files will also require a reload/graceful of the server to pick up the changes and discontinue the 304 return for the particular URI.



Will include statictics (pre-minimization) in a valid comment section at the top of the document. Something like the following can be expected:

             URI: /js/
           mtime: 1229843477
           Cache: 1
        Minimize: 0
        Compress: 0
          Render: 0.0628039836883545



Will use <JavaScript::Minifier> to minimize the Javascript and CSS::Minifier to minimize CSS, if installed.



Will use <Compress::Zlib> to compress the document, if installed.


    # Will change the separator from '~' to '-'

Will change the default file separator from '~' to any character you choose. The default is '~' as defined in the URI PROTOCOL section.



Will change the module's relative document root from the servers default and defined root to that of any string passed to the attribute.


Will append each inclucded file name, as a comment, into the included file. The intent is only to find a file that needs attention within the merged document with a little more ease. A nice feature when developing swarths of JS/CSS code.

Where, for example, if the handler merged 'foo/bar.js' and 'foo/bar/baz.js', the output would look similar to the following (when enabled, default off):

    /* foo/bar.js */
    Foo.Bar = function(){}();

    /* foo/bar/baz.js */
    Foo.Bar.Baz = function(){}();



If all you want is the URI protocol and C-style includes, this is all you have to do:

    # httpd.conf
    <LocationMatch "\.js$">
        SetHandler perl-script
        PerlResponseHandler Apache2::Response::FileMerge

C-Style includes

This can be applied to either CSS or JS at any point in your document. The moduel will implicitly trust the developer and therefore must be syntaxually correct in all cases. The handler will inject the code of the included file into it's literal location.

The include will be respective of the DocumentRoot of the server.

Note the double-asterisks ('**') comment to indicate the include.

The 'Include' keyword is required (but can be replaced with 'Inc' if you're lazy like me).

    /** Include foo/bar/baz.js **/

    /** Include foo/bar/baz.css **/

In all cases, the intent is that any file that is consumed by this module can also be rendered and executed without this module, which is the point behind the commented include structure.

URI Protocol

The URI will also allow you to include files. The URI will include files in the exact order they are listed, from left to right. Furthermore, if a URI that is requested is already included in a dependant file, the handler will only include the first instance of the file (which will generally be the first Include point).

The URI will be respective of directory location relative to the DocumentRoot.

'.' implies directory traversal.

'~' implies file separation (Default, see ATTRIBUTES).

    # File foo/bar.js will be loaded, which is in the '/js/' directory

    # Will do the same as above, but makes less sense IMHO

    # File foo/bar.js will be loaded, which is in the document root

    # Will include foo.js and foo/bar.js respectively


The generall usefulness of the advanced URI protocol is to combine files that are seemingly not dependant upon one another. See the EXAMPLES section for more details on this.


mod_perl v1.x

This will only work as a mod_perl 2.x PerlResponseHandler. If there is demand for 1.x, I will take the time to dynamically figure out what the right moduels, API, etc to use will be. For now, being that /I/ only use mod_perl 2.x, I have decided to not be overly clumsy with the code to take into consideration a platform people may not use.

CPAN shell installation

The unit tests each require Apache::Test to run. Yet, there are a lot of conditions that would prevent you from actually having mod_perl installed on a system of which you are trying to install this module. Although I don't really see the need or think it's good practice to install Apache2 namespaced modules without mod_perl, I have not made Apache::Test a prerequisite of this module for the case I mentioned earlier. That said, no unit tests will pass without mod_perl already installed and therefore will require a force install if that is what you would like. If that method is preferred, it is always possible to re-test the module via the CPAN shell once mod_perl is installed.

At the time of this writing, Apache::Test is included with the mod_perl 2.x distribution.




Trevor Hall, <>


Copyright (C) 2009 by Trevor Hall

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.