CodeIgniter…Meet Minify

NOTE: This post has an update that explains an improved technique. The technique below will still work (with some tweaks for CodeIgniter 1.7.1 or above), but is probably not preferred at this point.

As a followup to one of my previous posts I wanted to go through how I managed to get CodeIgniter and Minify to play nice with each other. Hopefully this will make someone else’s life easier. For those not using CodeIgniter this post might be either confusing or boring. Or both I guess.

My approach might seem code-heavy compared to other solutions but it has the virtue of requiring only a small change to single file that would be included by all pages on your site. That’s typically not a problem since the first thing I do when I’m working on a site is to break out the common elements such as the <html> and <head> tags to their own included header file.

In CodeIgniter I created a library called MY_Includes.php (/system/application/libraries/MY_Includes.php). This is the core class that contains the mappings between each controller and the JavaScript and CSS files required by the view that will be loaded by the controller that was invoked by the browser. Obviously this implies the extra step. If I create a new JavaScript or CSS file I can’t go into the globally included header file and add a <script> or <link> tag there – I have to edit MY_Includes.php to map the JavaScript or CSS file to that particular view. Yea, it seems weird to edit a PHP file to add a CSS or JavaScript file, but there are a couple of different factors at work here and this solution made the most sense to me. The big win was that it helped integrate Minify into my codebase with almost minimal effort.

You can see an edited version of MY_Includes.php here (Note: this is an old version). I wanted to walk through this code a bit to highlight the important parts, but hopefully it’s readable on its own.

First, you’ll notice the constructor requires the name of the controller that was invoked. I’ll show you how I get that later on, but essentially the whole class relies on that piece of information. My application is fairly linear in the sense that once I know the controller’s name I know (barring exception cases) which view will be invoked.

This in turn allows me to map controllers directly to JS and CSS files, which is why you’ll see the init method set up 2 hashes containing the JS and CSS files that I have access to, jsFilesHave and cssFilesHave. The key in the hash is a logical name I will use when adding the file to a view. This will improve readability and reduce errors and maintenance. The value in the hash is a string that specifies where the corresponding source file can be found. This is relative to the web root and is of a form that Minify understands. Whenever I create a new JS or CSS file I have to first add it to one of these hashes so that I can refer to it later in the file.

One other note on the init – I’m not sure if I needed to, but I found it easiest to break with the CodeIgniter way of doing things and issue a PHP include statement to tell the class where to find the Minify source in the below snippet from that method.

//from minify examples:
//Add the location of Minify’s “lib” directory to the include_path.
ini_set(‘include_path’, ‘/home/vdibart/minify/lib/.:’ . ini_get(‘include_path’) );
require ‘Minify/Build.php’;
require ‘Minify.php’;

After init, the constructor will call compileTags. This is the heart of the logic. You can see it populate the cssFilesNeed and jsFilesNeed hashes, first with the files that are common to all views and then the ones depending on which controller was invoked.

Determining which controller was invoked is fairly straightforward. The following code is at the top of my globally included header file:

//for globally included header file
//so know which CSS or JS files to include
$pageName = $this->uri->segment(1, 0);
$pageName .= “/” . $this->uri->segment(2, “index”);
$this->load->library(“MY_Includes’, $pageName);

So if the controller was “http://www.mysite.com/member/register”, this code will pass “member/register” to the constructor of my class. Later on in the same header file I have the following 2 lines, which will extract the appropriate CSS and JS links:

<!– for globally included header file –>
<link rel=”stylesheet” href=”<?= $this->CI->my_includes->cssTag(); ?>” type=”text/css” media=”screen” />
<script src=”<?= $this->CI->my_includes->jsTag(); ?>” type=”text/javascript” charset=”utf-8″></script>

Switching back to the source code of MY_Includes.php, you can see those 2 methods invoke Minify to build the included files and then return a URL that can be used to retrieve the files. There’s a little bit of work in each of those to make the URL look like something that CodeIgniter will work with. So once the PHP executes the above tags will look like this in the final source code for the page:

<link rel=”stylesheet” href=”http://www.mysite.com/includetag/css/member-register/1222014216″ type=”text/css” media=”screen” />
<script src=”http://www.mysite.com/includetag/js/member-register/1222098068″ type=”text/javascript” charset=”utf-8″></script>

So each rendered page on my site has only 1 CSS file and 1 JS file included. And those files are minimized and cached. All of that is due to Minify. But you’ll notice there’s one piece of the puzzle still missing. The above <link> and script tags refer back to my site, and there has to be something that knows how to interpret that and return the appropriate CSS or JavaScript data. It turns out that “includetag” is a CodeIgniter controller that I created. I’ve included the source code here. There’s not a ton to mention here. The class loads the exact same helper class MY_Includes.php that interfaces with Minify to retrieve the CSS or JS file and return them to the client.

Hopefully there’s enough to get you through to a working version. To summarize the steps:

  1. Download MY_Includes.php (here – see updated version) and put it in your /system/applications/libraries directory
  2. Edit the init method inside of MY_Includes.php to include the correct path to your Minify installation
  3. Edit the init method inside of MY_Includes.php to include your CSS and JS files
  4. Edit the compileTags method inside of MY_Includes.php to include the correct files for each controller
  5. Download includetag.php (here) and put it in /system/applications/controllers directory
  6. Add the two code fragments commented with “for globally included header file” above to the appropriate file in your application
  7. Fire it up

Feel free to post a comment if you have troubles and I’ll walk you through it or edit the post to fix any errors as needed.

NOTE: This post has an update that explains an improved technique. The technique above will still work (with some tweaks for CodeIgniter 1.7.1 or above), but is probably not preferred at this point.

Be Sociable, Share!
14 comments

14 Comments so far

  1. Paul from Costa Rica on September 22nd, 2008

    Wow nice! I’ll dig in to this and let you know my results! Thank you!

  2. Padraig on September 29th, 2008

    Your link in step 5. links to your MY_Includes.php file instead of includetags.php

    The correct link is: http://www.nodroidsallowed.com/minify/includetags.php.txt

    Cheers for this though, I’m working on trying it out now.

    PK

  3. vdibart on October 1st, 2008

    Thanks Padraig! Fixed.

  4. Mathew on October 8th, 2008

    Oh my thankyou for this plugin. But when it comes to CI libs and plugins my question is where do I install so and so. So my question is after I downloaded the minify_2.1.0.zip where do I install the core files?

  5. Mathew on October 8th, 2008

    Oh another thing I did everything you instructed. But it seems I caught a snag in the process. I placed all the files in their respective directories but when I tried to load the library in my global header. CI spits an error saying that it cannot load the library. hmmm….

  6. vdibart on October 8th, 2008

    Mathew,

    Thanks for the question.

    I installed Minify outside of my web root. So, for instance, on my hosting account it was in /home/vdibart/minify. It actually doesn’t matter because of the line I pointed out towards the top of the post:

    ini_set(’include_path’, ‘/home/vdibart/minify/lib/.:’ . ini_get(’include_path’) );

    This is the absolute path to the Minify install directory, so effectively you can put Minify anywhere. I don’t have any opinion on the “right” place to put it, but others might.

    Hope this helped.

  7. vdibart on October 8th, 2008

    I’ll take this offline and report back once the issue is worked out so others know what was going on….

  8. Mathew on October 8th, 2008

    No it’s quite alright I just had to make a few adjustments. First off I think the version of CI I’m using does not allow loading of the library in the views(my suspicion actually). So I had to load the library the traditional OOP way. I change the the name of MY_Include.php to MinifyToo.php and it worked.

    But I haven’t found a way to output JS and CSS. It just outputs something like this…

    or

    href=”http://pleeperps.localhost/includetag/css/project-viewProject/0″

    I don’t know what that means but I’m more than willing to sit down with you and help you rewrite some parts of the library.

  9. […] No Droids Allowed has integrated Minify into a CodeIgniter project. […]

  10. Ki on June 22nd, 2009

    Hi,
    I was wondering if you can give me some guidance in using this class. I have downloaded the latest minify and installed it in my main directory (moved the ‘min’ folder into /home/user/public_html). However, I am was not able to get it to work until I modified the MY_Includes.php to:
    //from minify examples:
    //Add the location of Minify’s “lib” directory to the include_path.
    ini_set(‘include_path’, ‘min/lib/.:’ . ini_get(‘include_path’) ); <= removed ‘/’ before ‘min’
    require ‘Minify/Build.php’;
    require ‘Minify.php’;
    I have added default CSS sheets to be included in all pages, but they do not seem to be showing up at all – any idea?

  11. Ki on June 23rd, 2009

    Great Job – but need lots and lots of effort making it work – need better documentation…
    Have you tried using this?
    Your Controller is called includetags.php
    while
    src=”http://www.mysite.com/includetag(NO ‘s’)/js…”
    Even after this fix there are implementation issues.
    In addition, library needs to be loaded in Controller or master library, no the view…

  12. vdibart on June 23rd, 2009

    Ki,

    I make no claims that it’s a drop-in upgrade. I’ve thought about making it more of a plugin, but honestly it doesn’t fit my needs and I’m not sure I have time to manage a spin-off project at this point. I’d be more than happy to help someone else get that going though. In general this article was meant to be a tutorial for how I did it, inspiration to others if you will. Your mileage may vary. Yes, it is loaded from the controller because in strict MVC architecture little or no actual logic is performed in the view. Also, the JS and CSS all have to be configured before you can write the header and footer of the HTML page.

    Thanks for the feedback though and I hope it helps you to some degree. I will fix the typo you mention. The version I posted was edited to remove proprietary code, so that explains why some typos exist. If you sent me a list of the “implementation issues” you mention I’d be happy to see if there’s something I can do to make integration smoother but as I said that wasn’t my primary intention.

    Thanks again.

  13. ki on June 23rd, 2009

    Hi,
    Firstly, thanks for the ONLY tutorial on how to integrate minify into CI. It is truely a great work. I guess CI updates have rendered some parts inoperable, but I was hoping to ask you if you could assist me in finishing this tutorial update to latest CI?
    This is what I got so far…
    1) $pageName was added to an array – CI did not allow it to be passed on as a variable – but that was when it was in the view, now its in my Master controller called MY_Controller that loads variables used throughout the whole site. I added this to the end of MY_Controller:
    //for globally included header file
    //so know which CSS or JS files to include
    $pageName = $this->uri->segment(1, 0);
    $pageName .= “/” . $this->uri->segment(2, “index”);
    $minify_data[‘pageName’] = $pageName;
    $this->load->library(“MY_Includes”, $minify_data);
    $this->data[‘js_stitched’] = $this->my_includes->jsTag();

    2) MY_Includes loader is now:
    $this->controller = $controller[‘pageName’];

    3) This is where I got stuck…
    includetag.php was not producing any result – I was getting the reference correct, but it was blank..
    Code:
    <script src=”” type=”text/javascript” charset=”utf-8″>
    Would Produce:

    (as seen with firefox FireBug extension)

    When I played around, I found out that the
    $this->load->library(‘MY_Includes’, $data );
    in includetag.php may not be loading…

    Any thoughts?

  14. […] previous article about CodeIgniter and Minify was a relative hit (relative only to my other posts that is), but some thinking since the original […]

Leave a Reply