dotsunited/bundlefu

BundleFu is a PHP 5.3+ library which bundles multiple css/javascript files into a big package and sends it out at once

Installs: 1 199

Dependents: 2

Stars: 54

Watches: 6

Forks: 5

Language: PHP

v1.0.2 2013-01-18 14:41 UTC

README

Build Status

BundleFu is a PHP 5.3+ library which bundles multiple css/javascript files into a big package and sends it out at once.

It is highly inspired by the Ruby on Rails plugin bundle-fu.

In short, it turns this:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.myplugin.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/app.module.js"></script>
<link media="screen" type="text/css" href="/css/reset.css">
<link media="screen" type="text/css" href="/css/jquery.myplugin.css">
<link media="screen" type="text/css" href="/css/app.css">
<link media="screen" type="text/css" href="/css/app.module.css">

Into this:

<link href="/css/cache/bundle_3f84da97fc873ca8371a8203fcdd8a82.css?1234567890" rel="stylesheet" type="text/css">
<script src="/js/cache/bundle_3f84da97fc873ca8371a8203fcdd8a82.js?1234567890" type="text/javascript"></script>

Features

  • Automatically detects modifications to your css and javascript files and regenerates the bundles automatically.
  • Bundle contents can be modified by filters for css url rewriting to avoid broken images, code minification and compression etc. (A Google Closure Compiler filter using the Service API comes with the library).

Installation

BundleFu can be installed using the Composer tool. You can either add dotsunited/bundlefu to the dependencies in your composer.json, or if you want to install BundleFu as standalone, go to the main directory and run:

$ wget http://getcomposer.org/composer.phar
$ php composer.phar install

You can then use the composer-generated autoloader to access the BundleFu classes:

<?php
require 'vendor/autoload.php';
?>

Usage

Configure a Bundle instance:

<?php
$bundle = new \DotsUnited\BundleFu\Bundle();

$bundle
    // Set the document root
    ->setDocRoot('/path/to/your/document_root')

    // Set the css cache path (relative to the document root)
    ->setCssCachePath('css/cache')

    // Set the javascript cache path (relative to the document root)
    ->setJsCachePath('js/cache');
?>

Alternatively, you can pass an options array to the constructor (or use the method setOptions later):

<?php
$options = array(
    'doc_root' => '/path/to/your/document_root',
    'css_cache_path' => 'css/cache',
    'js_cache_path' => 'js/cache',
);

$bundle = new \DotsUnited\BundleFu\Bundle($options);
?>

Use the instance to bundle your files in your templates:

<?php $bundle->start(); ?>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.myplugin.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/app.module.js"></script>
<link media="screen" type="text/css" href="/css/reset.css">
<link media="screen" type="text/css" href="/css/jquery.myplugin.css">
<link media="screen" type="text/css" href="/css/app.css">
<link media="screen" type="text/css" href="/css/app.module.css">
<?php $bundle->end(); ?>

Output the bundle <script> and <link> tags wherever you want:

<?php
// Renders both <script> and <link> tags
echo $bundle->render();

// Renders the <link> tag only
echo $bundle->renderCss();

// Renders the <script> tag only
echo $bundle->renderJs();
?>

Using the Factory

You can also use a factory to create bundle instances. The advantage is, that the factory can hold global options (like bypass and doc_root) which are shared across all created bundles:

<?php
$options = array(
    'doc_root' => '/path/to/your/document_root',
    'css_cache_path' => 'css/cache',
    'js_cache_path' => 'js/cache',
);

$factory = new \DotsUnited\BundleFu\Factory($options);

// $bundle1 and $bundle2 use the same doc_root, css_cache_path and js_cache_path options
$bundle1 = $factory->createBundle();
$bundle2 = $factory->createBundle();
?>

You can pass specific options to the createBundle method (global factory options will be overwritten):

<?php
$bundle1 = $factory->createBundle(array('name' => 'bundle1', 'doc_root' => '/path/to/another/document_root'));
$bundle2 = $factory->createBundle(array('name' => 'bundle2'));
?>

The factory also lets you define name aliases for filters. You can then define the string alias for the css_filter and js_filter options instead of passing a filter instance:

<?php
$filters = array(
    'js_closure_compiler' => new \DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter()
);

$factory = new \DotsUnited\BundleFu\Factory(array(), $filters);

$bundle1 = $factory->createBundle(array('js_filter' => 'js_closure_compiler'));
?>

Filters

You can manipulate the loaded css/javascript files and the bundled css/javascript code with filters. Filters are classes which implement DotsUnited\BundleFu\Filter\FilterInterface.

You can add filters like this:

<?php
$bundle->setCssFilter(new MyCssFilter());
$bundle->setJsFilter(my MyJsFilter());
?>

If you need multiple filters, you can use DotsUnited\BundleFu\Filter\FilterChain like this:

<?php
$filterChain = new \DotsUnited\BundleFu\Filter\FilterChain();

$filterChain->addFilter(new MyCssFilter1());
$filterChain->addFilter(new MyCssFilter2());

$bundle->setCssFilter($filterChain);
?>

Default filters

BundleFu provides the following filters out of the box.

CssUrlRewriteFilter

The DotsUnited\BundleFu\Filter\CssUrlRewriteFilter rewrites relative URLs in your CSS file to avoid broken image references:

<?php
$bundle->setCssFilter(new \DotsUnited\BundleFu\Filter\CssUrlRewriteFilter());
?>
ClosureCompilerServiceFilter

This filter compiles javascript code with the Google Closure Compiler using the Service API.

Simply add the DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter filter and your javascript bundles will be automatically compiled:

<?php
$bundle->setJsFilter(new \DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter());
?>
CallbackFilter

The DotsUnited\BundleFu\Filter\CallbackFilter can filter by using any PHP callback. If you want to compress your CSS using YUI Compressor you can either write a custom filter or use the following code leveraging the Callback filter:

<?php
$filter = new \DotsUnited\BundleFu\Filter\CallbackFilter(function($content) {
    $descriptorspec = array(
         0 => array('pipe', 'r'),  // STDIN
         1 => array('pipe', 'w'),  // STDOUT
         2 => array('pipe', 'a')   // STDERR
    );

    $handle = proc_open('java -jar /path/to/yuicompressor.jar --type css' , $descriptorspec, $pipes);

    if (is_resource($handle)) {
        fwrite($pipes[0], $content);
        fclose($pipes[0]);

        $compressed = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        proc_close($handle);

        if ($compressed) {
            return $compressed;
        }
    }

    return $content;
});

$bundle->setCssFilter($filter);
?>

Notes

  • All content inside of $bundle->start() and $bundle->end() will be lost. Be sure to only put css/javascript includes inside of the block.
  • Scripts/stylesheets are detected by parsing the output and looking for include files. HTML comments are ignored, so if you comment out a script like this:

    <!-- <script src="/js/script.js" type="text/javascript"></script> -->

    the comment will be ignored and the file will be bundled anyways. Be sure to comment out via PHP:

    <?php /* <script src="/js/script.js" type="text/javascript"></script> */ ?>
  • External dependencies via querystring loading will not work:

    <script src="/js/scriptaculous.js?load=effects,controls" type="text/javascript"></script>

    Instead, you'll need to include each javascript file as normal.

License

BundleFu is released under the MIT License.