Skip to content

Latest commit

 

History

History
436 lines (309 loc) · 14.7 KB

elixir.md

File metadata and controls

436 lines (309 loc) · 14.7 KB

Laravel Elixir

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/**');