Concat js files on demand

by Patrick on February 16, 2012

At connectiv! we always have a load of JavaScript files to be loaded for some interactive stuff. Sometimes it’s so many that the amount of HTTP requests slows down the pageload.

With the help of a small PHP script we reduced the number of HTTP requests to one. What the script does is it reads all the JavaScript files we need and outputs them to the browser. But I’ve taken the idea a little further now.

js.php FTW!

This new version takes all the scripts and saves them into a new JS file called scripts.js. Which doesn’t really sound cool. But the thing is that this is done only if the JS files are updated or the list of files itself changes. If there isn’t anything new, the scripts.js (actually it’s name is a little different, take a look at the code) will be outputted to the browser so that js.php only takes about 0.00098800659179688 seconds to execute.

<?php

$start = microtime(true);

$dir = dirname(__FILE__) . '\js';

// list of files to load
$files = array(
    '/libs/jquery-1.7.1.js',
    '/libs/modernizr-2.5.2.min.js',
    '/Cat.js',
    '/Dog.js',
    '/Mammal.js',
    '/extend.js',
    '/index.js',
    '/plugins.js',
);

// md5 fingerprint in case the list of files changes in some way
$scriptjsFile = $dir . '\scripts' . md5(implode('-', $files)) . '.js';

$lastBuild = null;
$rebuild = false;

if (file_exists($scriptjsFile)) {
    $lastBuild = filemtime($scriptjsFile);
} else {
    $rebuild = true;
}

// if there isn't a scripts.js we have to initially build the file, so there's
// no need to check for the newest js file
if (!$rebuild) {
    foreach ($files as $file) {
        $filePath = str_replace('/', DIRECTORY_SEPARATOR, $dir . $file);

        // if there is any file which was changed after the last build, we need
        // to rebuild scripts.js
        if (isset($lastBuild) && filemtime($filePath) > $lastBuild) {
            $rebuild = true;
        }
    }
}

if ($rebuild) {
    $scriptjs = @fopen($scriptjsFile, 'w+');

    foreach ($files as $file) {
        $filePath = str_replace('/', DIRECTORY_SEPARATOR, $dir . $file);

        @fwrite($scriptjs, file_get_contents($filePath));
    }

    fclose($scriptjs);
}

header('Content-type: application/javascript');

readfile($scriptjsFile);

$end = microtime(true);
echo '/* Time taken to build: ' . ($end - $start) . ' */';

The only thing you need to include into the <head/> of your layout is this file. Example:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title></title>
        <script type="text/javascript" src="scripts.php"></script>
    </head>
    <body>
        Hai! :)
    </body>
</html>

There are a lot of things to add, such as reasonable cache control headers and the ability to pass some parameters, i.e. base dir. But this is a working thing nonetheless and probably will find it’s way into connectiv! web sites some day, most likely as a more sophisticated version.

So long, thanks for reading!

Object-oriented programming in JavaScript

by Patrick on February 3, 2012

Although JavaScript is not an object oriented language, you can use some OOP like paradigms to structure your code. This tutorial is meant to be introductory. After reading this, you will know the very basics, a point to start and go on if you like.

JavaScript is so called “prototype based”, which  basically means that there aren’t any classes, only objects. But you can use any object as a blueprint for other objects by “cloning”  them. This is at least enough knowledge to get from a not-so-strict, OOP-like language like PHP to JavaScript.

In this tutorial, I’ll reuse one of the figures I’ve seen plenty of times when somebody tried to explain OOP: Mammals, cats and dogs. But please keep in mind that I won’t go into OOP itself here. Thus you should know the basics of OOP, such as inheritance, in order to understand this tutorial.

Read the rest of this entry »

Faster jQuery

by Patrick on December 25, 2011

Although jQuery gets faster with almost every release, there are a few things to remember when working with it. Scott Kosman posted a nice roundup on writing faster jQuery code on 24ways.org. Some of those tips are already in use in my day-to-day code, but not all of them.

Twitter Bootstrap

by Patrick on October 30, 2011

I found a really interesting thing for, well, bootstrapping web projects: Twitter’s Bootstrap. One problem I have every time I start a project is the styling. That basic stuff, like typography, margins here, paddings there. Things that don’t really add up to what the project is actually about. It feels felt like wasting time. With Bootstrap, you have everything you need right there. A big  bunch of CSS classes, from rather simple things like labels within the text flow up to a grid system and basic website layouts. It also implements LESS, a “dynamic stylesheet language”. I frankly haven’t looked into it yet, but it might be the right time now.

The only thing you need to do is download Bootstrap and use it as the base to start the project. Or, even simpler, just link their stylesheet in your <head/> (of course you won’t have the cool jQuery plugins that way).

The styles are like the ones you find at twitter.com, blue glow around focused text fields and the buttons look like the ones found at twitter. You may of course change these to fit the project, although I think it’s not really needed for small training or test projects.

They also offer some simple jQuery plugins such as modal windows, tabs, popovers or “twipsys”. I suggest you take a look at it, really useful stuff.

If you like the idea of having such bootstrap files, but Bootstrap takes it a little too far for your needs, check out the HTML5 Boilerplate. It offers a lot of cross-browser optimizations and implements a huge bunch of best practices for creating websites, but no default styles to the extend Bootstrap does.

I actually tried to combine both Bootstrap and the boilerplate, but I just began, so I have to see how it’ll work out.

Java MVC with “note”

by Patrick on April 11, 2011

In order to train my Java skills I started a little program called “note”. It was thought to be some note manager, with adding, editing, deleting, etc. notes. Since I don’t have any clue of swing or AWT it was started as a console program – and never left that stadium.

The only interesting thing, well the only thing which might be interesting, is that it’s implementing the MVC (Model View Controller) pattern. You are able to write controller classes und action methods inside these classes, just like you know it from good ol’ Zend Framework. note’s implementation of the console-MVC is much like that found in Zend_Tool. This means that you write your commands as follows:

add note "Test"

This command would call the action “add” on the controller “note”, passing a single parameter with the value “Test”. note reads this input, splits it by spaces and searches for a class called “note.Controllers.note” and instantiates it. Next thing is setting the arguments of the controller and calling the action on that newly instantiated object. This is all done via reflection.

The code is poorly to not at all commented. On the other hand it’s not that hard to understand what is going on. If you have any questions, feel free to ask. Furthermore I’m sure as hell that there is some stuff in that code which doesn’t make any sense, or could be made better. So feedback is welcomed.

The GitHub repository can be found here: https://github.com/patrickburke/note

jQuery.inlineComplete – Inline auto-complete for text input (2nd Update)

by Patrick on February 28, 2011

UPDATE NO. 2:

Plugin page is now online!

Yay, my first jQuery post.

jQuery.inlineComplete is a plugin which auto completes your typing inside the input text field, just like you see it in Google Chrome’s Omnibar.

Currently, this isn’t even tested in other browsers than Firefox 4 RC1, but I want this to be usable in production sometime, so expect some updates.

Demo: http://patrickburke.de/jquery/inlinecomplete/

GitHub repository: https://github.com/patrickburke/jquery.inlineComplete

It’s licensed under the MIT license, which also can be found in the README.txt

Questions and criticism are welcomed!

UPDATE:

Hell, a lot of changes, take a look into GitHub to see all the details. Here’s the short version: You’re now able to have the terms loaded from a URL. The plugin now also makes use of the HTML5 data attribute to accept a list or source of terms. There are examples in the index.html. I’ve also uploaded them to the demo directory, so go ahead and try it out!

I’m also working on a reference and manual page, shoudn’t take too long until it’s finished.

How I got to do this?

Google Chrome’s Omnibar in Firefox

by Patrick on February 28, 2011

I’m using Google’s Chrome browser for quite some time now, and one of my favorite features is the auto-completion inside the address bar.

For those not familiar with it: If you type “face” in the address bar, Chrome completes it with “book.com”, and by pressing enter, http://www.facebook.com is opened by Chrome. For that completion, Chrome uses terms which were typed in there previously by you.

Today I installed the latest beta of Firefox 4 (Beta 12), which is laking this extremely awesome feature.

I googled several hours to find an extension which enables that feature. The solution I found was the “browser.urlbar.autoFill” about:config setting of Firefox. With default settings, you have to type the visited URL of the website you want to open. Thus, you have to type “http://www.face” to get the completion for “http://www.facebook.com”, which is rather impractical. But by setting the “browser.urlbar.default.behavior” setting (also found under about:config) to “32″, Firefox restricts the completion to terms typed in previously by the user, just like our old pal Chrome. A reference of the available values for this option can be found on the mozillaZine sites.

browser.urlbar.autoFill = true
browser.urlbar.default.behavior = 32

Now, our little fox turns up completing “face” with “book.com”, thus perfectly recreating Chrome’s behaviour.

In order to replicate the search- in address bar feature, you can install the Omnibar Add-On for Firefox, it’s small and does it’s job.

Zend View Helper in database stored content

by Patrick on February 13, 2011

One of my co-workers currently writes his own website based on the Zend Framework. He wanted to use view helpers inside of the content, just like you do in view scripts. But the thing with content nowadays is that it is stored inside a database. He came up with a pretty simple, yet somewhat brilliant solution.

Basically, he loads the content from database, saves them as a file and passes the path to that file directly to Zend_View::renderScript(), which in turn handles the content as if it were a view script.


class IndexController extends Custom_Controller_Action
{
    /**
     * Index action
     *
     * @return void
     */
    public function indexAction()
    {
        // Content article
        $conGUID = $this->getRequest()->setParam('con_guid', 'default');

        // Category
        $catGUID = $this->getRequest()->setParam('cat_guid', 'main');

        //  content action
        $this->contentAction();

        // Deactivate auto render, we will render in content action
        $this->_helper->viewRenderer->setNoRender();
    }

	/**
	 * Show content article action
	 *
	 * @return void
	 */
	public function contentAction()
	{
        // Evaluate params

        // Content article
        $conGUID = $this->getRequest()->getParam('con_guid');

        // Category
        $catGUID = $this->getRequest()->getParam('cat_guid');

        // Set loaded false
        $loaded = false;

        // Content article AND category requested
        if ( $conGUID && $catGUID ) {

            // Configure cache object

            // Set cache frontend options
            $frontendOptions = array(
                'lifetime' => 7200 // save for 2 hours
            );

            // Get script path
            $scriptPath = $this->view->getScriptPaths();

            // Set cache backend options
            $backendOptions = array(
                'cache_dir' => $scriptPath[0].'index/cache/'
            );

            // Create Zend_Cache_Core object
            $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);

            // If no cache available for this content page
            if(!$cache->test('content_'.$conGUID)) {
                // Load content article
                $content = new Custom_Content_Page();

                if ( $content->load($conGUID) ) {
                    // Content assigned to requested category?
                    if ( $content->c_guid === $catGUID && true === $content->isOnline() ) {
                        // Content loaded
                        $loaded = true;
                    }
                }

                // Not found or not online
                if ( false === $blLoaded ) {
                    throw new Custom_Content_Exception('Cannot load content page. Invalid parameter specified ('.$conGUID.').');
                } else {
                    // Save content in cache object
                    $cache->save($oContent->getContent(), 'content_'.$conGUID);
                }
            }

            // Try to load cache file
            if ( $result = $cache->load('content_'.$conGUID) ) {

                // Get metatags if guid is set
                $oMeta = new Custom_Content_Meta();

                if ( $oMeta->load($conGUID) ) {
                    $this->view->oMeta = $oMeta;
                }

                // Assign content
                $this->view->content = $result;

                // @TODO: dynamic ftw
                $this->renderScript('index/cache/zend_cache---content_'.$conGUID);
            }
        }
    }
}

The code itself should be self-explanatory, though it’s commented pretty detailed. As you can see, this is a basic database caching mechanism, but instead of caching the final output of the content page which would be parsed by the browser, the code itself is cached and used as a view script. That way, the view helpers (and any other PHP code inside the content) are executed and produce the desired output. Of course without using include() directly or, even worse, eval().

In order to have a real cache, one would need to cache the final output of that rendering action, say, as a HTML file. In this case, Zend_Cache is just used because you can quite comfortably check for already stored files and then load or write them. Zend_File anyone?

in_array()’s lame!

by Patrick on January 26, 2011

Did you know that PHP’s in_array() is pretty lame? I didn’t.

Here is a german blog post about it (maybe Google translator does a good job?): http://www.phpgangsta.de/php-in_array-die-performance-bremse

He wanted to write a “Search-as-you-type” tool, which internally worked with in_array() to check for uniques in an array. With about 50.000 entries, this took about two freakin’ minutes. Using md5 hashes as array keys and isset() instead of in_array(), he was able to reduce the loadtime to about a second, which is quite an improvement.


if(isset($freakinBigArray[md5($val)])) {
    // do something fancy...
}

Dynamic script loaders

by Patrick on December 28, 2010

Recently I ran over HeadJS. I never heard of such script loaders before. Although I read that Google offers a JavaScript interface to load scripts from their CDN, I didn’t think of reducing the page load time in the first place.

Today I checked back to the website just to see how things are going. In the download section there was a link posted by the author which explains why HeadJS (and another script loader called “ControlJS“) aren’t as great in (pre)loading JavaScripts as LAB.js is. Miraculously the post is written by the creator of the latter script loader :)

I read the whole post (really long indeed…) and setup a little test (hopefully Apple won’t mind me using their scripts :). When you open up the three pages while your browser cache is deactivated, you will notice that the loading of the HeadJS “enabled” site takes twice as long as the page using the conventional script tags. LAB.js is indeed the fastet of all three.

In your network tab of Firebug, you’ll also see that the scripts get loaded twice by HeadJS, just as Kyle Simpson (a.k.a. “getify”) predicted it.

Of course this is not a real world-simulating test, I just wanted to see what happens.

Nonetheless, and as I wrote in the comments, I’d rather prefer HeadJS because of the additional features it offers. The browser feature detection, HTML5 enabling, and so on. But things are looking good, Tero Piirainen said he would eventually merge all that “wisdom” into HeadJS. Then HeadJS would be nearly perfect.

By the way, why do the ControlJS and LAB.js sites look so ugly? Not that I’m much of a designer, but it doesn’t need to be that “pragmatic”, take a look at headjs.com.