Introduction
Laravel Elixir provides a clean, fluent API for defining basic Gulp tasks for your Laravel application. Elixir supports several common CSS and JavaScript pre-processors, and even testing tools. Using method chaining, Elixir allows you to fluently define your asset pipeline. For example:
elixir(function(mix) {
mix.sass('app.scss')
.coffee('app.coffee');
});
If you've ever been confused about how to get started with Gulp and asset compilation, you will love Laravel Elixir. However, you are not required to use it while developing your application. You are free to use any asset pipeline tool you wish, or even none at all.
Installation & Setup
Installing Node
Before triggering Elixir, you must first ensure that Node.js is installed on your machine.
node -v
By default, Laravel Homestead includes everything you need; however, if you aren't using Vagrant, then you can easily install Node by visiting their download page.
Gulp
Next, you'll want to pull in Gulp as a global NPM package:
npm install --global gulp
If you use a version control system, you may wish to run
the npm shrinkwrap
to lock your NPM
requirements:
npm shrinkwrap
Once you have run this command, feel free to commit the npm-shrinkwrap.json into source control.
Laravel Elixir
The only remaining step is to install Elixir! Within a
fresh installation of Laravel, you'll find a
package.json
file in the root. Think of
this like your composer.json
file, except
it defines Node dependencies instead of PHP. You may
install the dependencies it references by running:
npm install
If you are developing on a Windows system or you are
running your VM on a Windows host system, you may need
to run the npm install
command with the
--no-bin-links
switch enabled:
npm install --no-bin-links
Running Elixir
Elixir is built on top of Gulp, so to run your
Elixir tasks you only need to run the gulp
command in your terminal. Adding the
--production
flag to the command will
instruct Elixir to minify your CSS and JavaScript
files:
// Run all tasks...
gulp
// Run all tasks and minify all CSS and JavaScript...
gulp --production
Watching Assets For Changes
Since it is inconvenient to run the gulp
command on your terminal after every change to your
assets, you may use the gulp watch
command.
This command will continue running in your terminal and
watch your assets for any changes. When changes occur,
new files will automatically be compiled:
gulp watch
Working With Stylesheets
The gulpfile.js
file in your project's root
directory contains all of your Elixir tasks. Elixir
tasks can be chained together to define exactly how your
assets should be compiled.
Less
To compile Less into
CSS, you may use the less
method. The
less
method assumes that your Less files
are stored in resources/assets/less
. By
default, the task will place the compiled CSS for this
example in public/css/app.css
:
elixir(function(mix) {
mix.less('app.less');
});
You may also combine multiple Less files into a single
CSS file. Again, the resulting CSS will be placed in
public/css/app.css
:
elixir(function(mix) {
mix.less([
'app.less',
'controllers.less'
]);
});
If you wish to customize the output location of the
compiled CSS, you may pass a second argument to the
less
method:
elixir(function(mix) {
mix.less('app.less', 'public/stylesheets');
});
// Specifying a specific output filename...
elixir(function(mix) {
mix.less('app.less', 'public/stylesheets/style.css');
});
Sass
The sass
method allows you to compile Sass into CSS.
Assuming your Sass files are stored at
resources/assets/sass
, you may use the
method like so:
elixir(function(mix) {
mix.sass('app.scss');
});
Again, like the less
method, you may compile
multiple Sass files into a single CSS file, and even
customize the output directory of the resulting CSS:
elixir(function(mix) {
mix.sass([
'app.scss',
'controllers.scss'
], 'public/assets/css');
});
Plain CSS
If you would just like to combine some plain CSS
stylesheets into a single file, you may use the
styles
method. Paths passed to this method
are relative to the resources/assets/css
directory and the resulting CSS will be placed in
public/css/all.css
:
elixir(function(mix) {
mix.styles([
'normalize.css',
'main.css'
]);
});
Of course, you may also output the resulting file to a
custom location by passing a second argument to the
styles
method:
elixir(function(mix) {
mix.styles([
'normalize.css',
'main.css'
], 'public/assets/css');
});
Source Maps
Source maps are enabled out of the box. So, for each file
that is compiled you will find a companion
*.css.map
file in the same directory. This
mapping allows you to trace your compiled stylesheet
selectors back to your original Sass or Less while
debugging in your browser.
If you do not want source maps generated for your CSS, you may disable them using a simple configuration option:
elixir.config.sourcemaps = false;
elixir(function(mix) {
mix.sass('app.scss');
});
Working With Scripts
Elixir also provides several functions to help you work with your JavaScript files, such as compiling ECMAScript 6, compiling CoffeeScript, Browserify, minification, and simply concatenating plain JavaScript files.
CoffeeScript
The coffee
method may be used to compile CoffeeScript
into plain JavaScript. The coffee
function
accepts a string or array of CoffeeScript files relative
to the resources/assets/coffee
directory
and generates a single app.js
file in the
public/js
directory:
elixir(function(mix) {
mix.coffee(['app.coffee', 'controllers.coffee']);
});
Browserify
Elixir also ships with a browserify
method,
which gives you all the benefits of requiring modules in
the browser and using ECMAScript 6 and JSX.
This task assumes that your scripts are stored in
resources/assets/js
and will place the
resulting file in public/js/main.js
. You
may pass a custom output location as an optional second
argument:
elixir(function(mix) {
mix.browserify('main.js');
});
// Specifying a specific output filename...
elixir(function(mix) {
mix.browserify('main.js', 'public/javascripts/main.js');
});
While Browserify ships with the Partialify and Babelify transformers, you're free to install and add more if you wish:
npm install aliasify --save-dev
elixir.config.js.browserify.transformers.push({
name: 'aliasify',
options: {}
});
elixir(function(mix) {
mix.browserify('main.js');
});
Babel
The babel
method may be used to compile ECMAScript
6 and 7 and JSX
into plain JavaScript. This function accepts an array of
files relative to the resources/assets/js
directory, and generates a single all.js
file in the public/js
directory:
elixir(function(mix) {
mix.babel([
'order.js',
'product.js',
'react-component.jsx'
]);
});
To choose a different output location, simply specify
your desired path as the second argument. The signature
and functionality of this method are identical to
mix.scripts()
, excluding the Babel
compilation.
Scripts
If you have multiple JavaScript files that you would like
to combine into a single file, you may use the
scripts
method.
The scripts
method assumes all paths are
relative to the resources/assets/js
directory, and will place the resulting JavaScript in
public/js/all.js
by default:
elixir(function(mix) {
mix.scripts([
'jquery.js',
'app.js'
]);
});
If you need to combine multiple sets of scripts into
different files, you may make multiple calls to the
scripts
method. The second argument given
to the method determines the resulting file name for
each concatenation:
elixir(function(mix) {
mix.scripts(['app.js', 'controllers.js'], 'public/js/app.js')
.scripts(['forum.js', 'threads.js'], 'public/js/forum.js');
});
If you need to combine all of the scripts in a given
directory, you may use the scriptsIn
method. The resulting JavaScript will be placed in
public/js/all.js
:
elixir(function(mix) {
mix.scriptsIn('public/js/some/directory');
});
Copying Files & Directories
The copy
method may be used to copy files
and directories to new locations. All operations are
relative to the project's root directory:
elixir(function(mix) {
mix.copy('vendor/foo/bar.css', 'public/css/bar.css');
});
elixir(function(mix) {
mix.copy('vendor/package/views', 'resources/views');
});
Versioning / Cache Busting
Many developers suffix their compiled assets with a
timestamp or unique token to force browsers to load the
fresh assets instead of serving stale copies of the
code. Elixir can handle this for you using the
version
method.
The version
method accepts a file name
relative to the public
directory, and will
append a unique hash to the filename, allowing for
cache-busting. For example, the generated file name will
look something like: all-16d570a7.css
:
elixir(function(mix) {
mix.version('css/all.css');
});
After generating the versioned file, you may use
Laravel's global elixir
PHP helper function
within your views to load the
appropriately hashed asset. The elixir
function will automatically determine the name of the
hashed file:
<link rel="stylesheet" href="{{ elixir('css/all.css') }}">
Versioning Multiple Files
You may pass an array to the version
method
to version multiple files:
elixir(function(mix) {
mix.version(['css/all.css', 'js/app.js']);
});
Once the files have been versioned, you may use the
elixir
helper function to generate links to
the proper hashed files. Remember, you only need to pass
the name of the un-hashed file to the
elixir
helper function. The helper will use
the un-hashed name to determine the current hashed
version of the file:
<link rel="stylesheet" href="{{ elixir('css/all.css') }}">
<script src="{{ elixir('js/app.js') }}"></script>
BrowserSync
BrowserSync automatically refreshes your web browser
after you make changes to your front-end resources. You
can use the browserSync
method to instruct
Elixir to start a BrowserSync server when you run the
gulp watch
command:
elixir(function(mix) {
mix.browserSync();
});
Once you run gulp watch
, access your web
application using port 3000 to enable browser syncing:
http://homestead.app:3000
. If you're using
a domain other than homestead.app
for local
development, you may pass an array of options
as the first argument to the browserSync
method:
elixir(function(mix) {
mix.browserSync({
proxy: 'project.app'
});
});
Calling Existing Gulp Tasks
If you need to call an existing Gulp task from Elixir,
you may use the task
method. As an example,
imagine that you have a Gulp task that simply speaks a
bit of text when called:
gulp.task('speak', function() {
var message = 'Tea...Earl Grey...Hot';
gulp.src('').pipe(shell('say ' message));
});
If you wish to call this task from Elixir, use the
mix.task
method and pass the name of the
task as the only argument to the method:
elixir(function(mix) {
mix.task('speak');
});
Custom Watchers
If you need to register a watcher to run your custom task
each time some files are modified, pass a regular
expression as the second argument to the
task
method:
elixir(function(mix) {
mix.task('speak', 'app/**/*.php');
});
Writing Elixir Extensions
If you need more flexibility than Elixir's
task
method can provide, you may create
custom Elixir extensions. Elixir extensions allow you to
pass arguments to your custom tasks. For example, you
could write an extension like so:
// File: elixir-extensions.js
var gulp = require('gulp');
var shell = require('gulp-shell');
var Elixir = require('laravel-elixir');
var Task = Elixir.Task;
Elixir.extend('speak', function(message) {
new Task('speak', function() {
return gulp.src('').pipe(shell('say ' message));
});
});
// mix.speak('Hello World');
That's it! Notice that your Gulp-specific logic should be
placed within the function passed as the second argument
to the Task
constructor. You may either
place this at the top of your Gulpfile, or instead
extract it to a custom tasks file. For example, if you
place your extensions in
elixir-extensions.js
, you may require the
file from your main Gulpfile
like so:
// File: Gulpfile.js
var elixir = require('laravel-elixir');
require('./elixir-extensions')
elixir(function(mix) {
mix.speak('Tea, Earl Grey, Hot');
});
Custom Watchers
If you would like your custom task to be re-triggered
while running gulp watch
, you may register
a watcher:
new Task('speak', function() {
return gulp.src('').pipe(shell('say ' message));
})
.watch('./app/**');