Fullybaked-logo

fullybaked | davebaker

I'm a developer living in the UK and when I'm not spending time with my wife and our 2 wonderful little boys, I love hacking around with code

I'm passionate about technology, web development, gaming and fencing

28 October 2013

CakePHP Asset Strategy - Part 2

This is the second part in my Asset Strategy series. Read the first part here

An apology

What can I say other than I have certainly learnt a lesson here. After posting part 1, I suffered a writers block on this topic and while other articles seemed to pop into my head I couldn't get the motivation to finish this one. The lesson: Not to publish multi-part articles until all parts are ready (or at least in draft form).

I am truly sorry for keeping people waiting on this, part 1 has been a popular post on the blog and there is no excuse for leaving you waiting on the conclusion for as long as I have.

With that out the way, lets carry on where we left off.

Getting on with it

At the end of part 1 you should have run the build command on Asset Compress and generated the CSS and JS files from your assets.

./Console/cake AssetCompress.asset_compress build -f

There are a number of steps now to set up both your development environment to ensure it always has the latest copies of assets as well as your deployment pipeline to make sure the production copies of your code are running from compiled versions of the JS and CSS which users browsers can use with out compile-on-request delays.

Layout Setup

To enable your development environment to always run the latest version of the code you first need to take advantage of functionality provided by the Asset Compress plugin itself.

First add the helper to your AppController helpers array

<?php
// app/Controller/AppController.php
class AppController extends Controller
{
    public $helpers = array(
        'AssetCompress.AssetCompress'
    );
}

Then add the following to the layout file (you can read up on the Asset Compress helper usage here)

<?php 
if (Configure::read('debug') > 0) {
    echo $this->AssetCompress->script('application', array('raw' => true));
    echo $this->AssetCompress->css('application', array('raw' => true]));
} else {
    $this->Html->script('application');
    $this->Html->css('application');
} 
?>

This if block basically uses the Asset Compress helpers to generate the CSS and JS in the layout if your debug value is a non-zero, which is usually the case in development. The raw param in the second argument makes Asset Compress generate each part of the build file individually so you can debug your client side easily (leave it out if you want the compressed versions)

For non-debug requests it uses CakePHP's built in Html helper methods for adding assets to a View.

If you have many layouts you could move this code into an Element and call it in from each layout separately.

Deployment

I'm a big fan of using Capistrano for deployment. It is originally from the Ruby on Rails toolchain but has grown into a language/framework agnostic tool. Although you still need a smattering of Ruby to use it as Capistrano's DSL is built in Ruby.

While I'm not going to go massively into depth on Capistrano (a blog post in its own right), I am going to touch briefly on its setup and configuration to show how to call the Asset Compress shell tasks during a deployment to ensure that the application.js and application.css files are created and ready for your production code.

Capistrano is a topic in its own right, so I hope you will forgive me that I'm not going to cover the entire setup of a deployment process (but that does give me another blog post to write).

For now I would say that the to ways you could go about deploying your assets are as follows

Local Compile

Originally I said that you should add the compiled assets to your .gitignore and only run with the components on your local/development machine. However, when it comes to deployment one of the ways you could handle this is to ignore my original advice.

But... only compile and commit your production asset files in the release branch that will be pushed and deployed to your server. Ensure that any feature/development branches rely on the component assets files.

Then just push the branch and deploy as normal, either with Capistrano or which ever tool you use. The release branch that goes into your production environment will include the compiled files.

Alternatively, if you are using Capistrano, or an alternative deployment tool, you could compile the assets and scp them up to the production server to remove the need for committing them to the repository.

Both of these methods, while I have suggested them, do seem a bit messy to me. I definitely prefer the following alternative:

Remote Compile

Rather than compiling the assets locally, ensure that the production server has access to the Asset Compress plugin and both the CSS and JS minifiers. Then as part of your deployment script, whether it is Capistrano, a Git post-receive hook or something else, you can run the Asset Compress command to compile the assets into the webroot directory.

The command you want is the same as compiling locally to test

/path/to/your/application/app/Console/cake AssetCompress.asset_compress build -f

The caveat here is to ensure that the user that runs the deployment scripts has write access to your webroot/js and webroot/cs

Conclusion

Any way, this is an alternative if complex way to deal with Assets in CakePHP and it certainly isn't right for every app or every developer. It really depends on how you like to work and what you find easiest.

Personally I love the separation of my client side code into different files so I'm not ploughing through thousands of lines of Javascript or CSS looking for that one line to change. I've also totally fallen for the pre-processor movement (Coffeescript & SASS) regardless of the mixed feelings many devs have. This means I need to have some form of automated compile and minify in place and this is just one of the ways I've experimented with.