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
- Ensure you have
node
andnpm
on your development machine. - Install Gulp globally:
npm install gulp -g
. - Run
npm init
to preparepackage.json
file. - Install
laravel-elixir
withnpm 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 createbower.json
with desired configuration - Now you can install frontend dependencies, eg.:
node_modules/.bin/bowewr install angular --save
- Run
-
Create
elixir.json
file and set root assets and public paths. Something like this:{ "assetsPath": "app/assets", "publicPath": "public/assets" }
-
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) ; });
-
Now you can run gulp tasks from your project, eg.:
gulp
- compile assetsgulp --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!