Compile assets with laravel-elixir on Laravel 4.2 or any other framework

You want to modernize your assets compilation before you switch to Laravel 5?
Elixir is great tool on top of Gulp, and you can use it for anything with little configuration. Here is my setup for Laravel 4.2 which can be easily adapted to any other framework.


Setup node, npm, global and local dependencies, Bower and Gulpfile

  1. Ensure you have node and npm on your development machine.
  2. Install Gulp globally: npm install gulp -g.
  3. Run npm init to prepare package.json file.
  4. Install laravel-elixir with npm install laravel-elixir --save to preserve that dependencies in your package.
  • If you want you can install bower for managing front end dependencies:

  • Run npm install bower --save

  • Create .bowerrc file and set destination for bower components, eg.:

    {
    	"directory": "app/assets/vendor"
    }
    
    • Run node_modeules/.bin/bower init to create bower.json with desired configuration
    • Now you can install frontend dependencies, eg.: node_modules/.bin/bowewr install angular --save
  1. Create elixir.json file and set root assets and public paths. Something like this:

    {
      "assetsPath": "app/assets",
      "publicPath": "public/assets"
    }
    
  2. Create gulpfile.js and add initial configuration (I don't want source maps in production):

    var elixir = require('laravel-elixir');
    var config = require('laravel-elixir').config;
    
    var bowerDir = 'app/assets/vendor/';
    var jsOutput = 'public/assets/js';
    var cssOutput = 'public/assets/css';
    var jsAssets = 'app/assets/js';
    
    config.sourcemaps = !config.production;
    
    // Example compile setup:
    
    elixir(function (mix) {
    	// MAIN STYLES
        mix
            // MAIN STYLES
            .sass('main.scss')
            
            // VENDOR STYLES
            .styles([
                'normalize.css/normalize.css',
            ], cssOutput + '/vendor.css', bowerDir)
    	;
    });	
    
  3. Now you can run gulp tasks from your project, eg.:

  • gulp - compile assets
  • gulp --production - compile production assets (minified and without sourcemaps)
  • gulp watch - Compile assets every time some source file is changed

Add elixir helper function from Laravel 5, or use custom functions for loading styles and scripts

To achieve functionality form Laravel 5 you should copy elixir helper function to some file loaded by composer, eg. app/helpers.php and load that in composer.json.

if ( ! function_exists('elixir'))
{
	/**
	 * Get the path to a versioned Elixir file.
	 *
	 * @param  string  $file
	 * @return string
	 */
	function elixir($file)
	{
		static $manifest = null;
		if (is_null($manifest))
		{
			$manifest = json_decode(file_get_contents(public_path().'/build/rev-manifest.json'), true);
		}
		if (isset($manifest[$file]))
		{
			return '/build/'.$manifest[$file];
		}
		throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
	}
}

If you don't plan to use elixir's version task for versioning assets you can add something like this, and relay on appended timestamp in query string (like Rails 3). Just keep in mind that Laravel 5 doesn't come with HTML helpers, so this won't work after update. You'll have to switch it to something like this:

  • HTML::style($path.'?'.File::lastModified($file))
    '<link href="'.$path.'?'.File::lastModified($file).'" rel="stylesheet" type="text/css" />'
  • HTML::script($path.'?'.File::lastModified($file))
    '<script src="'.$path.'?'.File::lastModified($file).'" type="application/javascript"></script>'
if ( ! function_exists('stylesheet_tag'))
{
	/**
	 * Create path from stylesheet's name
	 * Append last modification date as query string
	 *
	 * @param string $name
	 * @return string
	 */
	function stylesheet_tag($name)
	{
		$path = "assets/css/{$name}.css";
		$file = public_path($path);

		if (File::exists($file))
		{
			return HTML::style($path.'?'.File::lastModified($file));
		}
	}
}

if ( ! function_exists('javascript_tag'))
{
	/**
	 * Create path from javascripts's name
	 * Append last modification date as query string
	 *
	 * @param string $name
	 * @return string
	 */
	function javascript_tag($name)
	{
		$path = "assets/js/{$name}.js";
		$file = public_path($path);

		if (File::exists($file))
		{
			return HTML::script($path.'?'.File::lastModified($file));
		}
	}
}

Assets compilation

I prefer to compile assets locally instead on remote machine during deployment.

You can adapt to anything you like. If you compile locally just run gulp --production before committing and pushing assets to remote.

Otherwise you can use .gitignore to avoid committing compiled assets completely and register deploy hook to run same command on server, just keep in mind this will require configured node on your server!