Google’s Closure Compiler Service API: Optimizing a JavaScript File

In this third part of the series, I develop an example that illustrates how to use the Closure Compiler Service API for optimizing a JavaScript file via the set of PHP classes defined previously. In this example, the level of optimization applied to the target file is basic, limited to stripping its white space and nothing else.

In consonance with its typical diversification, this time Google has put its effort into a field other than search engines recently by launching a brand new web service. Called Closure Compiler Service API , it allows developers to optimize JavaScript files by using a set of easily customizable options. Moreover, the service can be consumed manually via a graphical user interface, or programmatically by using any server-side programming language, like PHP, Python, Ruby and so forth.

By far, the most interesting facet of the new optimization service provided by Google is its ability to be queried directly from within a web application. This process permits you to compile JavaScript files on the fly, which can be cached later on.

To elaborate further on this concept, in the two articles that preceded this one I started building a simple PHP-based back end which was made up of two basic classes. The first one was an abstract parent responsible for handling HTTP requests at a very generic level, while the second class was a refined implementation of the parent, tasked with interacting specifically with the Closure Compiler Service API.

With these two classes already up and running, it’s time to begin demonstrating how to use them for optimizing some sample JavaScript files. In this third part of the series I’m going to create an introductory example that will employ the aforementioned classes (and a few more) to compile a single JavaScript file via Google’s API.

Does my proposal sound appealing enough to you? Then keep reading!

Giving the final touches to previous PHP-based back end: adding a couple of sample classes    

As I said in the introduction, my plan is simply to show you how to consume the Closure Compiler Service API from within a PHP-based application. But before I reach that point, it’s necessary to add a couple of additional classes to the back end created previously. The first of these extra classes will be called “FileHandler.” It will be charged with reading and writing data to a specified file. Its corresponding definition is as follows:  

(FileHandler.php)

<?php

class FileHandler
{
    protected $_path = ‘function.js’;
    protected $_data;
   
    // constructor
    public function __construct($path = ”)
    {
        if ($path !== ”) {
            $this->setPath($path);
        }
    }
   
    // set the path to read/write data
    public function setPath($path)
    {
        if (!file_exists($path)) {
            throw new FileHandlerException(‘The specified path is not valid.’);
        }
        $this->_path = $path;
    }
   
    // get the specified path
    public function getPath()
    {
        return $this->_path;
    }
   
    // set new data to be written
    public function setData($data)
    {
        $this->_data = $data;
    }
   
    // get the stored data
    public function getData()
    {
        return $this->_data;
    }
       
    // read data from the specified path
    public function read()
    {
        if (!$this->_data = file_get_contents($this->_path)) {
            throw new FileHandlerException(‘Error reading from the target file.’);
        }
        return $this->_data;
    }
   
    // write data to the specified path
    public function write($data)
    {
        if (!file_put_contents($this->_path, $data)) {
            throw new FileHandlerException(‘Error reading from the target file.’);
        }
        $this->_data = $data;
    }           
}


    
<?php

class FileHandlerException extends Exception{}

As you can see, the above “FileHandler” class behaves like a simple wrapper for the “file_get_contents()” and “file_put_contents()” PHP native functions, which permit you to write and read data from a given file. The reason to code such a class is merely to read a given JavaScript file via a clean object-oriented interface. Keep in mind, however, that identical results can be obtained by using procedural code, so stay procedural if you’re more comfortable with this approach.

Having defined the previous file handler, the only thing we need to do is create an autoloader that lazy-loads classes using the PHP SPL stack. In this case, the “Autoloader” class shown below performs that task pretty simply. Check it out:

(Autoloader.php)

<?php

class Autoloader
{
    private static $_instance;
   
    // get the Singleton instance of the autoloader
    public static function getInstance()
    {
        if (!self::$_instance) {
            self::$_instance = new self;
        }
        return self::$_instance;
    } 
   
    // constructor
    private function __construct()
    {
        spl_autoload_register(array($this, ‘load’));
    }
   
    // prevent cloning instance of the autoloader
    private function __clone(){}
   
    // load a given class or interface
    public static function load($class)
    {
        $file = $class . ‘.php’;
        if (!file_exists($file)) {
            throw new ClassNotFoundException(‘The file containing the requested class or interface ‘ . $class . ‘ was not found.’);
        }
        require $file;
        unset($file);
        if (!class_exists($class, FALSE) AND !interface_exists($class, FALSE)) {
            throw new ClassNotFoundException(‘The requested class or interface ‘ . $class . ‘ was not found.’);
        }
    }  
}

 

<?php

class ClassNotFoundException extends Exception{}

As I just said, the previous “Autoloader” class is responsible for loading classes on demand by using the built-in autoloading mechanism included with PHP 5. Again, it’s valid to note that the implementation of this autoloader is entirely optional and can be skipped, especially if you’re used to working with multiple PHP includes instead. You’ve been warned!

So far, so good. Having defined the two previous classes, the scenario is finally set to start testing the actual functionality of the Closure Compiler Service API when invoked from inside a PHP application. Therefore, in the following segment I’m going to build a sample JavaScript file, which will be passed to the API so it can be optimized.

To see how this sample file will be created, click on the link below and keep  reading.

{mospagebreak title=Creating a simple JavaScript file for further optimization}

To demonstrate how to use the Closure Compiler Service API with the set of PHP classes defined in this and previous parts of this series, it’s mandatory to create a JavaScript file that can be optimized by the service, and then sent back to the browser.

To fit this requirement, below I created a somewhat rudimentary file called “function.js,” whose trivial definition looks like this:

function createDiv(idAttr, classAttr) {
    // create the div
    var div = document.createElement(‘div’);
    // assign the ‘id’ attribute to the div element
    div.setAttribute(‘id’, idAttr);
    // assign the ‘class’ attribute to the div element
    div.setAttribute(‘class’, classAttr);
    // append the div element to the document
    document.getElementsByTagName(‘body’)[0].appendChild(div);
};
// call the previous function
createDiv(‘divid’, ‘divclass’);

As you can see above, this sample JavaScript file defines a function named “createDiv(),” which uses a few common DOM methods to first create a “div” element, then assign to it an “id” and a “class” HTML attribute, and finally append the pertinent element to the end of the web page. Lastly, the function is called with a couple of basic arguments that are self-explanatory.

Having shown the definition of the previous “function.js” file, it’s time to put all of the pieces together and see how to apply a basic level of optimization to it with the Closure Compiler Service API. The full details of this process will be discussed below.

Seeing Google’s Closure Compiler Service API in action: applying a basic level of optimization to the earlier JavaScript file

If you’re like me, you want to see how the PHP classes built before can be used for optimizing the JavaScript file coded above via the Closure Compiler Service API. Well, it’s time to set up a concrete example that shows how to accomplish this in a few simple steps.

At its most basic level, the API requires four POST parameters to do its business as expected. The first one is called “js_code” and must contain the JavaScript snippet that will be optimized (although its URL can be passed too). The second argument is named “compilation_level” and can be used for specifying the level of optimization the will be applied to the target JavaScript code.

The other two are called “output_format” and “output_info” respectively. They come in handy for controlling in which format the compiled output will be served to the client (text, XML or JSON), and for specifying what kind of data will be returned to the browser (compiled code, statistics, etc.).

The API also supports some additional arguments that perform more advanced optimizations, but those will be discussed in depth in upcoming tutorials. For the moment, focus your attention on the following example. It first compiles the previous “function.js” JavaScript file by removing its white space, and then returns the compiled code in text/javascript format:  

<?php

// example using optimization level = WHITESPACE_ONLY
try {
 
    // include the autoloader class
    require_once ‘Autoloader.php’;
    Autoloader::getInstance();

    // create an instance of the file handler class and read the specified JavaScript file
    $fileHandler = new FileHandler;
    $js = $fileHandler->read();
   
    // build the array of arguments that will be passed to the closure compiler API
    $data = array(
         ‘js_code’ => $js,
         ‘compilation_level’ => ‘WHITESPACE_ONLY’,
         ‘output_format’ => ‘text’,
         ‘output_info’ => ‘compiled_code’
    );
   
    // create an instance of the ClosureCompilerHandler class
    $compilerHandler = new ClosureCompilerHandler($data);
    // query the closure compiler API and get the compiled JavaScript function
    $response = $compilerHandler->sendRequest();
    $compilerHandler->sendHeader(‘js’);
    // print to screen the compiled JavaScript function
    echo $response;
}
catch (Exception $e) {
    echo $e->getMessage();
    exit();
}

Even though the above script seems to be rather complex, its driving logic is fairly simple to follow. In this case, the script simply grabs the Singleton instance of the autoloader to include all of the PHP classes that you saw before, and uses the file handler to fetch the contents corresponding to the previous “function.js” JavaScript file.

Finally, an array containing the fourth parameters required by the Closure Compiler Service API is passed to the ”ClosureCompilerHandler” class, which queries the API and returns the compiled version of the target file. Since in this example, the value assigned to the “compilation_level” argument is WHITESPACE_ONLY, this is the output that the compiler sends back to the client:   

function createDiv(idAttr,classAttr){var div=document.createElement("div");div.setAttribute("id",idAttr);div.setAttribute("class",classAttr);document.getElementsByTagName("body")[0].appendChild(div)}createDiv("divid","divclass");

That worked like a charm! As you can see above, the compiler has effectively removed all the white space included in the target JavaScript file, thus stripping some bytes from its original size. While this is only a basic example, it shows in a nutshell how to programmatically compile a JavaScript file using a PHP class that talks directly to Google’s compiler API.

Naturally, the API is capable of optimizing files through more advanced options; but as I said before, those will be explored in detail in forthcoming parts of the series. Meanwhile, feel free to edit all of the code samples included in this article; doing so will provide you with a more solid understanding of how to put the Closure Compiler Service API and PHP to work together.

Final thoughts

In this third part of the series, I developed a concrete example that illustrated how to use the Closure Compiler Service API for optimizing a JavaScript file via the set of PHP classes defined previously. In the earlier example, the level of optimization applied to the target file was basic, limited to stripping its white space and nothing else.

It’s fair to note, though, that the API allows you to use more complex compiling algorithms in JavaScript files. To demonstrate how to achieve this, in the upcoming tutorial I’m going to set up another example that will perform a better optimization by assigning a different value to the pertinent “compilation_level” argument.

Don’t miss the next part!

Google+ Comments

Google+ Comments