November
2009

Include Javascript files — the professional way

When I find an interesting website I often look at its source code – a habit that I probably share with most other web developers. In the end I’m simply interested in improving myself whenever possible and learn from other people. I’m interested what CMS people are using, what Javascript frameworks, plugins and backend languages, so I check the source code for hints. Often you can also learn a lot about the developer’s attitude and character by looking at their coding style.

Personally I don’t like it when I find 15 single Javascript files linked in the source code. Not only does it look like a mess, it can also produce overhead and reveals a lot about the plugins and scripts that were used. By showing people what external scripts and plugins you’re using, you create potential security risks, for the same reason admins of corporate websites often try to remove any revealing hint about the CMS that was used. For some clients it may also be an advantage to have the site look 100% custom built – if the source code reveals that it’s only a collection of free plugins and widgets, it may lead some people into questioning your abilities or the rates you charge.

The best way of linking Javascript in a website would be to have a single merged file that contains all scripts, to keep it clean style, to reduce HTTP requests, with smallest possible file size and with simple code obfuscation through minimising and compressing. Now I can already hear some developers crying that they want to keep their scripts and classes separated for easier editing. Here’s an example where you can have it all, keeping files separated, but still linking only one single file from your website.

Organising files

I like to organise Javascript files in a folder structure like this:

/js
/js/src

In /js/src I put all my single scripts files, the parent folder is the one where the merged file will be stored.

The PHP

A popular Javascript minimiser is JSMIN. Download the PHP version here and put the source file in your /js/src folder. If you want to use this example in another language than PHP, JSMIN is also available for other languages, see here.

Now create a file merge.php with the following code:

<?php
  require_once('jsmin.php');

  $path = dirname(__FILE__);
  $merged = $path . '/../scripts.js';

  $files = array(
    $path . '/mootools.js',
    $path . '/mootools_more.js',
    $path . '/datepicker.js',
    $path . '/popup.js',
    $path . '/somescripts.js',
    $path . '/mystuff.js'
  );

  // if merged file doesn't exist yet, create a placeholder
  if (!file_exists($merged)) :
    file_put_contents($merged, 'Futurama FTW!');
    touch($merged, 1);
  endif;

  $lastmodified = filemtime($merged);

  //check if any of the files were modified
  $js = '';
  $changes = false;
  foreach ($files as $file) :
    if (filemtime($file) > $lastmodified) $changes = true;
  endforeach;

  // if a file was modified, write a new merged one
  if ($changes) :
    foreach ($files as $file) :
      $js .= JSMin::minify(file_get_contents($file));
    endforeach;

    file_put_contents($merged, $js);

    // finally set all file modification dates to the one of the merged one
    foreach ($files as $file) :
      touch($file, filemtime($merged));
    endforeach;
  endif;
?>

First we set some paths and define the source files that should be merged. If the merged file doesn’t exist yet, a placeholder will be created with modification date set to unix time 1 (make sure both directories including the files are writable!). If at least one source file is newer than the merged one, a new merged file will be created and all source files will get their modification date set equal to the new merged one. So if a source file changes, it will be noticed the next time the script runs, since the modification date will be newer than the one of the merged file.

To make sure that users always get to see the latest file version, the script should be called on every page load. Simply add the following line on top of your page templates:

<?php require_once('/path/to/js/src/merge.php') ?>

Now that we made sure that the merged file is always up-to-date, you can link it in your template:

<script src="/path/to/js/scripts.js?<?php echo filemtime('/path/to/js/scripts.js'); ?>" type="text/javascript"></script>

Adding a timestamp at the end of a Javascript or CSS file prevents the browser from using a cached version, since it changes every second. However, since the merged file is only generated when source files change, we simply use the file modification timestamp, so it is really only transferred when a newer version is available.

To further reduce traffic you should check that your web server supports ZIP compression (Deflate algorithm). Transferring Javascript with ZIP enabled can reduce the file size by 70% or more! If you’re not sure whether your server runs compression, you can check the HTTP response headers with Firebug. To enable compression, either change your Apache config, or simply add the following line to your .htaccess file:

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript text/css

Conclusion

Including Javascript with the method explained here, has a range of benefits:

  • Only a single file is served to visitors, which keeps your code clean and reduces HTTP requests.
  • Source files can still be kept separate and uncompressed for easier editing.
  • Code is minimised and ZIP compressed to reduce traffic and speed up loading times.
  • Visitors can’t easily recognise the scripts and plugins used on the site which can increase security.
  • Visitors will always get the latest version of the script file, because the different timestamp will indicate that it’s a new file.
  • The script file will still only be transferred if it differs from the one in the visitors’ browser cache.