イントロダクション
Laravel Elixir(エリクサー:万能薬)は、Laravelアプリケーションのための基本的なGulpタスクを定義しており、きれいでスラスラかけるAPIを提供しています。Elixirは人気のあるCSSとJavascriptプリプロセッサー、それにテストツールもサポートしています。メソッドのチェーンを使用し、Elixirでアセットパイプラインを流暢に定義できます。例を見てください。
elixir(function(mix) {
mix.sass('app.scss')
.coffee('app.coffee');
});
Gulpやアセットのコンパイルを始めようとして、頭がこんがらがっているようならLaravel Elixirを気に入ってもらえるでしょう。しかしながらアプリケーションの開発時に必要だというわけではありません。どんなアセットパイプラインツールを使用してもかまいませんし、使わなくても良いのです。
インストールと準備
Nodeのインストール
Elixirを始める前、最初にNode.jsを開発機にインストール済みであることを確認してください。
node -v
Laravel Homesteadならデフォルトのままでも必要なものが全部そろっています。しかしVagrantを使っていなくてもNodeのダウンロードページを読めば、簡単にインストールできます。
Gulp
次にGulpをグローバルNPMパッケージとしてインストールします。
npm install --global gulp-cli
バージョン管理システムを使用している場合、NPMのコンポーネントを固定するため、npm shrinkwrap
を実行することもできます。
npm shrinkwrap
このコマンド実行後、npm-shrinkwrap.jsonをソースコントロールへコミットするか自由に決めてください。
Laravel Elixir
残っているステップはElixirのインストールだけです。新しくLaravelをインストールすると、ルートディレクトリにpackage.json
があることに気づくでしょう。PHPの代わりにNodeの依存パッケージが定義されている所が異なりますが、composer.json
ファイルと同じようなものだと考えてください。以下のコマンドで、依存パッケージをインストールしてください。
npm install
Windowsシステムで開発を行っている場合、もしくはWindowsをホストとして仮想マシンを実行しているときは、--no-bin-links
を有効にしてnpm install
コマンドを実行してください。
npm install --no-bin-links
Elixirの実行
ElixirはGulp上に構築されていますので、端末でgulp
コマンドを実行するだけでElixirタスクを走らせることができます。コマンドに--production
フラッグを付けることで、ElixirにCSSとJavaScriptファイルを圧縮するように指示できます。
// 全タスク実行
gulp
// 全タスクを実行し、全CSSとJavaScriptを圧縮
gulp --production
アセットの変更監視
アセットを変更するごとに端末でgulp
コマンドを実行するのは不便ですので、gulp watch
コマンドを使用できます。このコマンドは端末で動き続けてアセットの変更を監視します。変化が起きると変更があるファイルは自動的にコンパイルされます。
gulp watch
スタイルシート操作
プロジェクトルートにあるgulpfile.js
ファイルに全Elixirタスクを構成します。Elixirタスクはアセットをどのようにコンパイルするか実際に定義するためにチェーンでつなげます。
Less
LessをCSSへコンパイルするにはless
メソッドを使用します。less
メソッドはLessファイルがresources/assets/less
に保存されていることを想定しています。コンパイルされたCSSはデフォルトでpublic/css/app.css
へ保存されます。
elixir(function(mix) {
mix.less('app.less');
});
さらに複数のLessファイルを一つのCSSファイルへ結合できます。この結果のCSSもpublic/css/app.css
に保存されます。
elixir(function(mix) {
mix.less([
'app.less',
'controllers.less'
]);
});
コンパイル済みのCSSの出力先をカスタマイズしたい場合は、less
メソッドに第2引数で指定します。
elixir(function(mix) {
mix.less('app.less', 'public/stylesheets');
});
// 出力ファイル名を指定する…
elixir(function(mix) {
mix.less('app.less', 'public/stylesheets/style.css');
});
Sass
sass
メソッドはSassをCSSへコンパイルします。Sassファイルはresources/assets/sass
へ保存されていると想定します。このメソッドは次のように使用します。
elixir(function(mix) {
mix.sass('app.scss');
});
less
メソッドと同様に複数のSassファイルを一つのCSSファイルへまとめることができ、結果のCSSを出力するディレクトリもカスタマイズできます。
elixir(function(mix) {
mix.sass([
'app.scss',
'controllers.scss'
], 'public/assets/css');
});
通常のCSS
通常のCSSスタイルシートを一つのファイルに結合したい場合は、styles
メソッドを使います。このメソッドに渡すパスはresources/assets/css
からの相対位置で、結果のCSSはpublic/css/all.css
に保存されます。
elixir(function(mix) {
mix.styles([
'normalize.css',
'main.css'
]);
});
もちろんstyles
メソッドの第2引数を指定すれば、結果の出力ファイルをカスタマイズできます。
elixir(function(mix) {
mix.styles([
'normalize.css',
'main.css'
], 'public/assets/css');
});
ソースマップ
ソースマップ生成はデフォルトで有効になっています。各ファイルをコンパイルするごとに、*.css.map
ファイルが同じディレクトリに生成されます。このマッピングはデバッグの時にブラウザ上でコンパイル済みのスタイルシートセレクターからオリジナルのSassやLess定義を見つけるのに役立ちます
CSSのためにソースマップを生成したくなければ、設定オプションで無効にしてください。
elixir.config.sourcemaps = false;
elixir(function(mix) {
mix.sass('app.scss');
});
スクリプト操作
ElixirはECMAScript 6のコンパイル、CoffeeScriptのコンパイル、Browserify、圧縮、JavaScriptファイルの結合などのJavaScript操作を手助けする多くの機能も提供しています。
CoffeeScript
coffee
メソッドはCoffeeScriptをJavaScriptへコンパイルするために使用します。coffee
関数はresources/assets/coffee
ディレクトリからの相対パスの文字列か配列を引数に受け取り、public/js
ディレクトリにapp.js
ファイルを生成します。
elixir(function(mix) {
mix.coffee(['app.coffee', 'controllers.coffee']);
});
Browserify
Elixirはbrowserify
メソッドも用意しており、ブラウザーとECMAScript
6、JSXを使用するためにモジュールをrequireする全ての利点を享受できます。
このタスクはスクリプトがresources/assets/js
へ設置されており、結果をpublic/js/main.js
ファイルへ書き出すと想定しています。
elixir(function(mix) {
mix.browserify('main.js');
});
// 出力ファイル名を指定する…
elixir(function(mix) {
mix.browserify('main.js', 'public/javascripts/main.js');
});
Browserifyは最初からPartialifyとBabelifyトランスフォーマーを含んでいますが、お望みならvueifyをインストールし追加することもできます。
npm install aliasify --save-dev
elixir.config.js.browserify.transformers.push({
name: 'aliasify',
options: {}
});
elixir(function(mix) {
mix.browserify('main.js');
});
Babel
babel
メソッドは、ECMAScript 6と7とJSXをJavaScriptへコンパイルするために使用します。この関数はresources/assets/js
ディレクトリからの相対ファイルパスの配列を引数に受け取り、public/jsディレクトリのall.jsファイルを生成します。
elixir(function(mix) {
mix.babel([
'order.js',
'product.js',
'react-component.jsx'
]);
});
別の場所へ出力したい場合は、希望するパスを第2引数に指定してください。このメソッドの使い方と機能はmix.scripts()
と同じで、Babelのコンパイルを行う点のみ異なります。
JavaScript
複数のJavaScriptファイルを一つのファイルへまとめたい場合は、scripts
メソッドを使用します。
scripts
メソッドは全パスをresources/assets/js
からの相対位置であると想定し、結果をデフォルトでpublic/js/all.js
に置きます。
elixir(function(mix) {
mix.scripts([
'jquery.js',
'app.js'
]);
});
複数のスクリプトを別々のファイルにまとめたい場合は、scripts
メソッドを複数回呼び出してください。メソッドの第2引数でそれぞれの結合ファイル名を指定します。
elixir(function(mix) {
mix.scripts(['app.js', 'controllers.js'], 'public/js/app.js')
.scripts(['forum.js', 'threads.js'], 'public/js/forum.js');
});
指定したディレクトリの全スクリプトを結合するには、scriptsIn
メソッドを使います。結果のJavaScriptはpublic/js/all.js
に設置されます。
elixir(function(mix) {
mix.scriptsIn('public/js/some/directory');
});
ファイルとディレクトリのコピー
copy
メソッドはファイルとディレクトリを新しい場所へコピーするために使用できます。全操作はプロジェクトルートディレクトリからの相対位置で指定します。
elixir(function(mix) {
mix.copy('vendor/foo/bar.css', 'public/css/bar.css');
});
elixir(function(mix) {
mix.copy('vendor/package/views', 'resources/views');
});
バージョン付け/キャッシュ破壊
多くの開発者がコンパイルしたアセットにタイムスタンプや一意なトークンをサフィックスとして付加し、保存されている古いコードの代わりに真新しいアセットを強制的にロードさせています。Elixirはこれをversion
メソッドで処理します。
version
メソッドはpublic
ディレクトリからの相対パスファイル名を受け取り、ファイル名に一意なハッシュを付けることでキャッシュを破壊します。たとえば生成されたファイル名はall-16d570a7.css
のような名前になります。
elixir(function(mix) {
mix.version('css/all.css');
});
バージョンが付いたファイルを生成した後、ビューの中からLaravelのグローバルelixir
PHPヘルパ関数を使い、ハッシュが付いたアセットをロードすることができます。elixir
関数はハッシュをつけたファイル名を自動的に決定します。
<link rel="stylesheet" href="{{ elixir('css/all.css') }}">
複数ファイルのバージョン付け
version
メソッドへ配列で複数ファイルを渡すこともできます。
elixir(function(mix) {
mix.version(['css/all.css', 'js/app.js']);
});
ファイルにバージョンが付けられたら、elixir
ヘルパ関数でハッシュが付いた実際のファイルへリンクを生成することができます。elixir
ヘルパ関数にはハッシュをつけていないファイル名を渡す必要があることを覚えておきましょう。
<link rel="stylesheet" href="{{ elixir('css/all.css') }}">
<script src="{{ elixir('js/app.js') }}"></script>
BrowserSync
BrowserSyncはフロントエンドのリソースに変更が起きたときに、Webブラウザを自動的に再読込します。gulp watch
コマンド実行時にBrowserSyncサーバーを起動するようにElixirへ指示するため、browserSync
メソッドが利用できます。
elixir(function(mix) {
mix.browserSync();
});
gulp watch
を実行したら、ブラウザ同期を利用するにはhttp://homestead.app:3000
でWebアプリケーションにアクセスしてください。ローカル開発にhomestead.app
以外のドメインを使用しているなら、browserSync
メソッドの最初の引数としてオプションの配列を渡してください。
elixir(function(mix) {
mix.browserSync({
proxy: 'project.app'
});
});
既存Gulpタスクの呼び出し
既存のGulpタスクをElixirから呼び出すにはtask
メソッドを使用します。たとえば呼びだされた時にただちょっとしたテキストを話すGulpタスクを考えてみてください。
gulp.task('speak', function() {
var message = 'Tea...Earl Grey...Hot';
gulp.src('').pipe(shell('say ' + message));
});
このタスクをElixirから呼び出すにはmix.task
メソッドを使い、メソッドの唯一の引数にタスク名を指定してください。
elixir(function(mix) {
mix.task('speak');
});
カスタムタスク監視
カスタムタスクを実行するための監視対象ファイルを登録するには、task
メソッドの第2引数に正規表現で指定してください。
elixir(function(mix) {
mix.task('speak', 'app/**/*.php');
});
Elixir拡張の定義
Elixirのtask
メソッドが提供しているより、さらに柔軟性が求められる場合は、カスタムElixir拡張を作成してください。Elixir拡張でカスタムタスクへ引数を引き渡せます。たとえば以下のような拡張を書いたとしましょう。
// ファイル: 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');
これだけです! Gulp限定のロジックはTask
コンストラクターの第2引数として渡している関数に設置しなくてはならない点に注目です。これをGulpfileの先頭に設置するか、代わりにカスタムタスクファイルとして外部ファイルにします。たとえば拡張をelixir-extensions.js
ファイルに設置し、次のようにメインのGulpfile
から読み込みます。
// ファイル: Gulpfile.js
var elixir = require('laravel-elixir');
require('./elixir-extensions')
elixir(function(mix) {
mix.speak('Tea, Earl Grey, Hot');
});
カスタムタスク監視
gulp watch
が実行されている間にカスタムタスクを再起動したい場合は、監視タスクを登録します。
new Task('speak', function() {
return gulp.src('').pipe(shell('say ' + message));
})
.watch('./app/**');