Leaking Abstraction

Loosely coupled thoughts on web development

Managing CSS and JavaScript files within a Zend Framework App

with 6 comments

When I’m creating a large external facing website or application, one of the biggest messes I used to end up making was in my CSS and JavaScript files.

As a developer/designer (jack of all trades, master of none, if you will) I tend to stay away from some of the more common developer solutions that take care of a lot of the design overhead (e.g., jQuery UI framework, Dojo, etc). Flexibility is paramount to good design — boxing yourself into a specific layout for every page is bound to produce a boring, forgettable website. Design is highly underrated to developers, I believe a good aesthetic sense is a skill worth maturing for anyone who develops web applications. After all, you can have the most beautiful underlying code, but if it’s presentation is anything short of beautiful it completely loses its “wow” factor.

Full design control usually means large, thousand plus line CSS files that equal serious pain when it comes to maintenance or building upon. If you don’t namespace your selectors carefully you’ll end up paying for it down the road. And heaven forbid you apply a default HTML tag styling. So, ranting aside, how do you maintain flexibility and still keep tidy CSS and JavaScript? My solution is to keep the very same directory/file structure that is used for the application for my CSS and JavaScript. The best part is by writing a very simple view helper, it’s super easy to automate the proper head link and script file inclusions.

Here’s what my CSS and JavaScript view helpers look like:

File: application/views/helpers/JavascriptHelper.php

getRequest();
		$file_uri = 'media/js/' . $request->getControllerName() . '/' . $request->getActionName() . '.js';

		if (file_exists($file_uri)) {
			$this->view->headScript()->appendFile('/' . $file_uri);
		}
	}
}

File: application/views/helpers/CssHelper.php

getRequest();
		$file_uri = 'media/css/' . $request->getControllerName() . '/' . $request->getActionName() . '.css';

		if (file_exists($file_uri)) {
			$this->view->headLink()->appendStylesheet('/' . $file_uri);
		}

		return $this->view->headLink();

	}
}

With that done, add the helper to your layout in the section:

File: application/layouts/scripts/layout.phtml


	
    <title>My app title</title>
    <?= $this->headTitle() ?>
    <?= $this->headMeta() ?>
    <? $this->headLink()->appendStylesheet('/media/css/global.css') ?>
    <?= $this->headLink()->appendStylesheet('/media/css/iefix.css','screen','lt IE 7') ?>
    <?= $this->cssHelper() ?>
    <?= $this->javascriptHelper() ?>

Now, anytime a controller action is invoked it will look for a javascript and css file in the same controller/action file path. In the above examples I’ve hard-coded the CSS and Javascript parent directories (/public/media for me) directly in to the code, but this would be pretty easy if you wanted to throw it in a config file or something instead. Otherwise just change to your preferred directory and your good to go.

The next thing I’d like to explore is automatically packing/minifying all CSS and Javascript into one file (or possibly outputting them directly to the layout in-line) and then caching the results of that to optimize bandwidth usage. If I ever have the luxury of that being a priority, that is :)

Advertisement

Written by Andy Baird

February 1, 2010 at 5:26 pm

Posted in Tutorials

Tagged with , ,

6 Responses

Subscribe to comments with RSS.

  1. I love the general idea and your specific view helper.

    Even better, I am relieved that you, too, use page-specific (in the case of an MVC-framework like Zend Framework, controller-action-specific) styles and scripts. Looking at so many sites and samples, it was beginning to appear that best practice was a single global css file and a single javascript file (to reduce the number of HTTP requests, etc). But it always bugged me that there would be some styles/scripts that would be page-specific, so why should they be parsed/executed on *every* page?

    Thanks for a bit validation that at least I am not alone in this. On the other hand, any ideas on the best way to address this – like your allusion to packing/minifying in a way that would still create significant caching benefits – would be most welcome.

    David Weinraub

    February 1, 2010 at 10:37 pm

    • Thanks! I’m glad this was useful for someone else. It’s also nice to see that someone else shares my point of view. As much as we try to avoid it, CSS is a language with it’s own set of best practices.

      My thoughts for a packer/minifier would probably be to take hints from this project and this one (if not just using them outright). Instead of including the file, read the contents of the file and send it to the packer/minifier class. Send the returned value to a Zend_Cache object. The view helper could handle the caching and either output the script inline (which would be the best bandwidth optimizing, however, I suspect you might run into some CSS rendering issues) or include it all in one simple file.

      If I have time, I’ll try to whip this up — but in my experience thus far, this is more of a nice-to-have than a requirement. When I first started using my CSS/JS view helpers I was very concerned about loading an additional file per controller/action, but in practice I’ve discovered the overhead is pretty minimal for the maintainability you end up getting out of it.

      Andy Baird

      February 2, 2010 at 12:37 am

  2. I would say that gziping your css/js is a must for reducing the load on your servers! I’m had pretty good YSlow results using php_speedy in the past http://aciddrop.com/2009/02/02/php-speedy-wp-052-bug-fix/. If any of us ever have the luxury of time, this would be nice to have ported over to Zend Framework ;)

    David

    February 4, 2010 at 1:23 pm

  3. Hi, interesting article (saw this here and on the zend site). I figured I would share my approach for handling CSS/JS files in zend since it is quite different.

    http://www.devpatch.com/2010/02/view-plugin/

    Thoughts and opinions are welcome.

    Ben

    February 6, 2010 at 11:32 am

  4. Interesting, but I like to keep details about presentation out of my controllers as much as possible. The code in your layout plugin I usually code directly into the layout (but then again, I don’t mind putting a few PHP tags in my layouts as long as they control markup, I know some people prefer not too)

    Also, even for me I don’t use a separate JS/CSS file for every controller/action, but because the view helper only loads the files *when* they exist that works perfectly fine.

    Andy Baird

    February 6, 2010 at 11:25 pm

  5. Always good to see different approaches, I think this is especially true with ZF since it is not strictly structured.

    Not sure if this matters for your application but caching the view seems like a good idea if you use this method. I would think there would be some performance hit by doing the file system read. Just something that I was noodling on when re-reading your article.

    Thanks again for your thoughts.

    Ben

    February 8, 2010 at 11:22 am


Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.