We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 18641
    • 22 Posts
    Matt and Jake Reply #1, 19 years ago
    :D Hi there,

    For a while now I have been obsessing about reducing http connections (if it wasn’t that it would be something else). On one of my modx-less dev sites I have been using a tasty script written by Ed Elliot, here it is: http://www.ejeliot.com/blog/72 I use both the standard script (for css) and the one that supports JSMIN compression (for my GIGANTIC moo experiments). It does a bloody good job.

    This is What it Does
    Basically I can split my .css / .js into loads of fragments and the script scoops them up and outputs a single file. If I modify one of the fragments, it scoops them all up again and re-builds a new cache file with a new name so browsers get the new stuff... The updated script also whacks the .js through JSMIN.php and leaves me with a single skinny js file. yummy.

    Now I have tried to snippetize this thing, It all looks good, when I update one of the "fragments" the script inserts a new link in my doc with a new file name, but will not create the files/folders on the server. Can anyone please take a quick look at the script and see what’s wrong and why it doesn’t love Modx the way I do kiss, I only know enough PHP to break a page in ugly and unexpected ways, and could really do with some help. huh

    I hope others here benefit from this workflow dooby.. It’s real easy to end up with half a dozen scripts and styles up there in the <head>..
      • 14050
      • 788 Posts
      I will not likely be able to offer any help in the PHP department, but this sounds like something that would be more akin to a plugin that could work sitewide, that gets fired off on some system event.
        Jesse R.
        Consider trying something new and extraordinary.
        Illinois Wine

        Have you considered donating to MODx lately?
        Donate now. Every contribution helps.
        • 18641
        • 22 Posts
        Matt and Jake Reply #3, 19 years ago
        Hmm OK thanks, I will have a play around with that and see if I can get it to work that way, I was wondering if there were any conditions that need to be met by this script, things that perhaps a straight forward snippet can’t do, like for example creating the archive folder and writing to it etc.. the problem is I don’t know enough php to even know where to begin looking for the problem, thanks for taking a look. Time to buy some books I think.
          • 18641
          • 22 Posts
          Matt and Jake Reply #4, 19 years ago
          UPDATE
          All is working as it should be. I have no idea why. I guess the problem was with my re-write rule and not the script, since that is the only thing I have changed recently.

          This really is a nice workflow solution, give it a go. You can reduce all the js / css in the <head> down to 2 files and leave comments in them pointing to the originals for fellows devs peeking at your code. Combined with a css sprites approach for you core site images, you can reduce your connections from dozens down to a mere handful (if you’re careful) - giving you improved performance on high capacity sites.

          Not sure if its worth it on sites with a low user base, but still a single css file, and compressed js file will download quicker than a handful of each... Since the majority of browsers can, by default, only make 2 simultaneous requests to a site at a time. Once a site is complete and you know you probably won’t touch the css for a while, You could even open up the merged / cached css, manually compress it using the many css compression utilities about, paste it back in to the cache file and save it. Resulting in a tiny single css files, leaving all of the originals intact and readable.

          Just food for thought I guess..

          <?php
             // Written by Ed Eliot (www.ejeliot.com) - provided as-is, use at your own risk
             
             /****************** start of config ******************/
             define('FILE_TYPE', 'text/css'); // type of code we're outputting
             define('CACHE_LENGTH', 31356000); // length of time to cache output file, default approx 1 year
             define('CREATE_ARCHIVE', true); // set to false to suppress writing of code archive, files will be merged on each request
             define('ARCHIVE_FOLDER', 'styles/dev2/archive'); // location to store archive, don't add starting or trailing slashes
             
             // files to merge
             $aFiles = array(
                'styles/dev2/aesthetics.css',
                'styles/dev2/structural.css'
             );
             /****************** end of config ********************/
             
             // this is prepended to all file / folder paths so files and archive folder should be specified relative to this
             $sDocRoot = $_SERVER['DOCUMENT_ROOT'];
             
             /*
                if etag parameter is present then the script is being called directly, otherwise we're including it in 
                another script with require or include. If calling directly we return code othewise we return the etag 
                representing the latest files
             */
             if (isset($_GET['version'])) {
                $iETag = (int)$_GET['version'];     
                $sLastModified = gmdate('D, d M Y H:i:s', $iETag).' GMT';
                
                // see if the user has an updated copy in browser cache
                if (
                   (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $sLastModified) ||
                   (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $iETag)
                ) {
                   header("{$_SERVER['SERVER_PROTOCOL']} 304 Not Modified");
                   exit;
                }
                
                // create a directory for storing current and archive versions
                if (CREATE_ARCHIVE && !is_dir("$sDocRoot/".ARCHIVE_FOLDER)) {
                   mkdir("$sDocRoot/".ARCHIVE_FOLDER);
                }
                
                // get code from archive folder if it exists, otherwise grab latest files, merge and save in archive folder
                if (CREATE_ARCHIVE && file_exists("$sDocRoot/".ARCHIVE_FOLDER."/$iETag.cache")) {
                   $sCode = file_get_contents("$sDocRoot/".ARCHIVE_FOLDER."/$iETag.cache");
                } else {
                   // get and merge code
                   $sCode = '';
                   $aLastModifieds = array();
                   foreach ($aFiles as $sFile) {
                      $aLastModifieds[] = filemtime("$sDocRoot/$sFile");
                      $sCode .= file_get_contents("$sDocRoot/$sFile");
                   }
                   // sort dates, newest first
                   rsort($aLastModifieds);
                   
                   if (CREATE_ARCHIVE) {
                      if ($iETag == $aLastModifieds[0]) { // check for valid etag, we don't want invalid requests to fill up archive folder
                         $oFile = fopen("$sDocRoot/".ARCHIVE_FOLDER."/$iETag.cache", 'w');
                         if (flock($oFile, LOCK_EX)) {
                            fwrite($oFile, $sCode);
                            flock($oFile, LOCK_UN);
                         }
                         fclose($oFile);
                      } else {
                         // archive file no longer exists or invalid etag specified
                         header("{$_SERVER['SERVER_PROTOCOL']} 404 Not Found");
                         exit;
                      }
                   }
                }
             
                // send HTTP headers to ensure aggressive caching
                header('Expires: '.gmdate('D, d M Y H:i:s', time() + CACHE_LENGTH).' GMT'); // 1 year from now
                header('Content-Type: '.FILE_TYPE);
                header('Content-Length: '.strlen($sCode));
                header("Last-Modified: $sLastModified");
                header("ETag: $iETag");
                header('Cache-Control: max-age='.CACHE_LENGTH);
             
                // output merged code
                echo $sCode;
             } else {
                // get file last modified dates
                $aLastModifieds = array();
                foreach ($aFiles as $sFile) {
                   $aLastModifieds[] = filemtime("$sDocRoot/$sFile");
                }
                // sort dates, newest first
                rsort($aLastModifieds);
                
                // output latest timestamp
                echo $aLastModifieds[0];
             }
          ?>
          
            • 25663 MODX Staff
            • 12,272 Posts
            Matt and Jake ... very nice and thanks... I’ve been wanting to look into this for a while. smiley
              Ryan Thrash, MODX Co-Founder
              Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
              • 18641
              • 22 Posts
              Matt and Jake Reply #6, 19 years ago
              Hi there mr rthrash, I’m glad you like it. I have this thing working under some weird kind of amateur trial and error freak show scenario... Which goes like this:

              - Save the script as a snippet and call it in the right .css and .js places in your <head>...
              - Put the Combine.php script in the css / js directory, and a re-write rule in .htaccess pointing at the script
              - When ever you want to add another css / js file to the merge and spit dooby, you have to update both the snippet and the script... grin Clever eh? err... .. .

              Haha what a rubbish mess... I’m dead certain one of you guys will be able to take this and make it work beautifully with Modx, the way it should.

              If you get this working in a much friendlier way please post back because I’d love to use this in a commercial site I’m working on.

                • 6726
                • 7,075 Posts
                Thanks a lot I will definitely try this snippet out as optimization is a constant preoccupation... I didn’t know about this script (nice blog post too, very educationnal !).
                  .: COO - Commerce Guys - Community Driven Innovation :.


                  MODx est l&#39;outil id