By Bruno Skvorc

Look, Ma! No NodeJS! – A PHP Front-end Workflow Without Node

By Bruno Skvorc

If you’re intimidated, exhausted or irritated by Gulp, Grunt, NPM, Yeoman, and all the other NodeJS tools that aim to help but often do the opposite, a good asset management workflow is possible in PHP, and this tutorial aims to prove it. In this article, we’ll go through a NodeJS-free PHP front end asset management setup.

Robo Logo

What we’ll be doing

We’ll be adding asset management into a Slim 3 project. We’ll be using Rob Allen’s Slim3 Skeleton as a base “app”, along with:

  • BowerPHP instead of Bower for installing assets
  • markstory/mini-asset for minification
  • Robo for resource tracking (watching for changes) and executing a rebuild (minification) when a change is detected

Why mini-asset and not Munee or Assetic? Because it’s dead simple – configure with an .ini file, run, and it executes. No server alterations, no in-depth configuration, ready to go OOTB.

Note that Slim 3 is used here only as a base app, and doesn’t really matter in the whole picture – we won’t be using any of Slim’s particular functionality. As such, you can use any framework you want, or skip using a framework altogether. We’ll be using Homestead Improved as usual to set up a local dev environment.

Getting Started

git clone hi_assets
cd hi_assets
sed -i '' "s@Project@test@g" Homestead.yaml
vagrant up
vagrant ssh

The sed line is a shortcut to editing the Homestead.yaml file – it will replace the word Project with test, so our app can be in the test folder rather than Project. This is purely personal preference. If any of this is confusing, please see this introduction to Vagrant.

As soon as these commands execute, we should be able to get the No input file specified error when visiting in the browser, provided we have added to /etc/hosts on the host operating system, as per instructions.

Let’s set up the skeleton now.

cd Code
composer create-project -n -s dev akrabat/slim3-skeleton test
cd test

Simple enough. That should produce a screen not unlike this one:

Slim3 greeting page

Finally, let’s install the other prerequisites. BowerPHP isn’t in stable status yet, so we need to allow Composer to download beta packages. Open the global configuration file with:

composer global config -e

and add in the following statement:

"minimum-stability": "beta"

Now, we can install beta packages.

composer global require beelab/bowerphp codegyre/robo markstory/mini-asset natxet/CssMin --dev

Note that mini-asset will suggest installing some other packages, each specific to a context you might require. The CssMin package is one such addition – without it, mini-asset wouldn’t be able to handle CSS files. Refer to the suggestions list the installation procedure outputs for more filter packages you might need.

We now have all the prerequisites in place. Let’s start dealing with assets.

Asset Management

The bare bones Slim3 skeleton from Rob is a bit plain – no standardized stylesheets or front end frameworks attached (as it should be in any framework, in my opinion). Let’s change that.

Bootstrap via BowerPHP

Let’s add in Bootstrap, and just for kicks, Bootstrap-social – this will allow us to demonstrate the merging of various CSS files along with letting us use social network button styles in our front end.

cd ~Code/test
bowerphp install bootstrap
bowerphp install bootstrap-social

A bower_components folder should now be in the test folder, containing everything we requested. We could install the components into public and use them directly in our layout code (see app/templates/home.twig), but that’s horribly inefficient, if great for debugging styles. Let us instead produce the CSS we need in a filtered, concatenated and minified manner. This is where mini-asset comes in.


As per the documentation, mini-asset is configured via an .ini file. Let’s add the assets.ini file to the root of our project:

cachePath = public/css/build
paths[] = bower_components/*
filters[] = CssMinFilter

files[] = bootstrap/dist/css/bootstrap.min.css
files[] = font-awesome/css/font-awesome.css
files[] = bootstrap-social/bootstrap-social.css
files[] = public/css/style.css

As per the bootstrap-social docs, we need to include Bootstrap, FontAwesome, and Bootstrap-social in our HTML. That’s exactly what we did above by merging the different libraries.

cachePath tells mini-asset where to put our compiled CSS. Paths lists all the locations in which CSS files can be found. Filters lists all the additional packages used for processing the assets. In our case, it’s just the aforementioned CSSMin package.

The next section lists compiled CSS files, one by one, and the files they consist of.

If we now run mini-asset (and create the cachePath folder first, of course), we should get a compiled CSS file as output.

mkdir public/css/build
mini_asset build --config assets.ini

A final tweak we need to do is copy the fonts subfolder of font-awesome into public/css, because the paths in the compiled CSS are relative, and go up one folder to find the font. A compiled file placed in build won’t have the fonts one folder up, so we need to put them there:

cp -R bower_components/font-awesome/fonts public/css/

Now we can replace the style link in home.twig file with this one:

<link href='/css/build/app.css' rel='stylesheet' type='text/css'>

We can also throw in a social bootstrap button for good measure, just to make sure it works.

<a class="btn btn-small btn-social btn-twitter">
            <i class="fa fa-twitter"></i> Sign in with Twitter

Screenshot of working social button


At this point, it’s easy enough to re-run the compilation every time one makes an important change to the style files, but why not automate things? Robo is here to help. There are other watchers out there, too, but Robo is such a robust and versatile task runner, it would be a shame not to use it. In fact, Robo has its own asset processing built in, but given that many might opt not to use Robo in the first place, this tutorial followed a more decoupled path. Feel free to use its asset pipeline if it feels better than mini-asset, though – the sky’s the limit!

To run, Robo needs a RoboFile.php in the working directory. Robo can create that file for us if we just run it in a folder where there is no such file:

> robo
  RoboFile.php not found in this dir 
?    Should I create RoboFile here? (y/n)  
RoboFile.php created

The idea is to trigger a rebuild of the app.css file every time style.css in public/css changes – that’s the user’s custom stylesheet, and it’s where we’ll be putting our own styles to override or use the ones included before them (Bootstrap, etc.)

First, let’s set up a watcher and see if it triggers every time the file changes. This is done by defining a public method in RoboFile which houses the watching commands:

public function build()
            ->monitor('public/css/style.css', function () {
                $this->say("style.css changed!");

If we launch the watcher now and change the CSS file, Robo will alert us to it.

> robo build
 [Watch] Watching public/css/style.css for changes...
➜  style.css changed!

Now all that’s left is triggering a mini-asset rebuild on change. This is done with the _exec or taskExec command:

public function build()
            ->monitor('public/css/style.css', function () {
                $this->say("Starting CSS rebuild");
                $this->_exec('mini_asset build --config assets.ini');
                $this->say("CSS rebuilt successfully!");

And that’s all it took – re-running Robo, we now have an auto-rebuild file-watcher active which recompiles CSS files on every change.

> robo build
 [Watch] Watching public/css/style.css for changes...
➜  Starting CSS rebuild
 [Exec] Running mini_asset build --config assets.ini
 [Exec] Done in 0.556s
➜  CSS rebuilt successfully!
➜  Starting CSS rebuild
 [Exec] Running mini_asset build --config assets.ini
 [Exec] Done in 0.558s
➜  CSS rebuilt successfully!


In this tutorial, we looked at getting started with asset management (installation, concatenation, and minification) in PHP projects. We saw that NodeJS is unnecessary for this aspect of development and isn’t worth the extra trouble.

We used BowerPHP as a replacement for Bower, mini-asset to concat and minify, and Robo to watch for changes and trigger the minification task. With this knowledge, you should now be able to compile more complex assets, including LESS to CSS, JavaScript, and more.

Do you use a different approach? Let us know in the comments!

  • Hi Bruno,

    Love this approach. Nice to see that there are alternatives for PHP devs out there.

    I personally (still) use grunt for such tasks, but these tools look interesting.

    Any suggestions for uglifying and merging js files ?


  • Stef

    awesome. Will switch to robo and drop the npm stuff.

  • Cool stuff Bruno! Is there a way to also do cachebusting by adding a version number to the processed files?


    • With mini-asset, not at this point. But it’s easy to extend, and there are other implementations that handle this automatically, like
      Add in Puli integration, and you have location-agnostic asset compilation, too. The sky’s the limit, really.

      • You lost me there. Htpl is a template engine, isn’t it? Where can it help me add versioning to the .js or .css file titles?


        • I just linked to it for inspiration – it has a version-powered minification system built in. Perhaps building this into mini-asset would be a good idea for a post :)

          • Ahhh…Ok. I’ll have to look into the code a bit deeper. I noticed you put in some issues. What do you think of that template engine over the likes of Twig?


          • It’s pretty good, but I’m still testing it.
            One big plus is all the tags being HTML5 tags, rather than {{}} metasymbols, which makes it more approachable to front end web designers, I guess. The built-in minificiation is really nice, too, and it’s very simple to extend the engine with new functionality.
            More detailed post soon.

  • Ryan

    Incredibly interesting concept, but there’s a few things that I’m currently doing with Node that I’m not sure that a PHP approach can handle. The two big ones are live reloading and making my sites available to other devices on the same network. Do you have any insight there?

    • That’s outside asset management territory, so not sure. Probably, yes, but I haven’t given it much thought.

  • Hi..really nice article..It was just one day late :) so I already went with grunt and bower..although I would still choose grunt..but this looks very you recommend this approach in production? Is it stable enough for a bigger project?


    • There’s no issue of stability. Assets are compiled pre-deployment, so as long as they compile fine, you’re good for any project of any size. You won’t have file watchers and compilers running on a live server, so stability is moot.

  • Gene Kelley

    Wow! It just works. Imagine that! Great article. Thank you Bruno.

  • Because I don’t only develop on a Mac. It’s one of the reasons I made Homestead Improved – to enhance platform portability of my development environment.

  • Finally. I concur.

  • jamlee

    it’s nice work, thanks the author of three application. but bowerphp is a beta app so i am expecting the stable version. it is nice article too . O^0^O

    • NodeJS has been under version 0.2 for half a decade. I think you’re safe using something like BowerPHP, especially considering it’s for development use only – it’s not like you’ll be using asset management tools in production.

Get the latest in PHP, once a week, for free.