Laravel Mixがどのような役割をするのかわからない人向けにWEB開発入門者にもわかる簡単なコードだけを使いLaravel Mixの説明を行っています。Laravel Mixと名前がついていますが、Laravelがない環境でも動作します。今回は、Laravelがインストールされていない環境で動作確認を行っています。

Laravelと分けることでLaravel Mixがどのようなものかより明確にすることを目的としています。単独でしっかり理解できれば、実際にLaravelを設定・運用の際に不具合が発生した場合の切り分けにも役にたつはずです。

Laravel Mixとは

Laravel mixを理解するためには、まずwebpackというツールの存在を知っておく必要があります。webpackについては入門者向けに記事を作成済みですのでwebpackがわからない人は下記を参考にしてください。

入門者にとってwebpackを理解し、使いこなすのは簡単ではありません。一般的なサイトで使用されているwebpackの設定を事前に行い、できるだけ簡単にwebpackを扱えるようにと開発されたのがLaravel Mixです。Laravel Mixはwebpackのwrapper(ラッパー)です。Laravel Mixという名前がついているので、webpackとは別のものの上、Laravelとの結びつきが強くLaravel環境でしか使うことができない印象を受けますが、Laravelがなくても使用することが可能です。Laravelとは別のツールなので、Lravel Mix単独の公式のサイトも存在します。

Laravel Mixサイトページ
Laravel Mixサイトページ
wrapper(ラッパー)とはwrap(ラップ)包むという意味を持ち、webpackの周りをLaravel Mixで包みこむようなイメージを浮かべてください。外から見るとLaravel Mixですが、内側はwebpackなので、実際はwebpackを操作していることになります。

Laravel Mixのインストールと初期設定

動作確認を行う環境を構築するためにlaravel mixテスト用のフォルダを作成します。


$ mkdir learning-mix-laravel
$ cd learning-mix-laravel/

npm initでpackage.jsonファイルの作成を行います。


 $ npm init -y

npmがわからない人は以下を読むことをお勧めします。

npm installでLaravel Mixのインストールを行います。その後、Laravel Mixの設定ファイルであるwebpack.mix.jsのコピーを行います。


$ npm install laravel-mix --save-dev
$ cp node_modules/laravel-mix/setup/webpack.mix.js ./

インストール後は、learning-mix-laravelディレクトリの構成は下記となります。


$ ls
node_modules		package.json
package-lock.json	webpack.mix.js

Laravel Mixの設定はwebpack.mix.jsファイルを中心に行い、このファイルを更新することでさまざまな設定を行うことができます。

setPublicPath(‘dist’)を下記のように追加します。追加設定することで後ほどVersioningのところで出てくるmix-manifest.jsonファイルがdistフォルダに保存されます。


let mix = require('laravel-mix');

mix.js('src/app.js', 'dist/').sass('src/app.scss', 'dist/').setPublicPath('dist');

上記の設定では、srcディレクトリにあるJavaScriptファイルであるapp.jsがwebpackの中でビルドされdistディレクトリ以下に保存されます。またSassで記述されたスタイルシートapp.scssがwebpackを通してcssに変換され、distディレクトリに保存されます。app.jsファイルはこの処理の中でBabelの処理も行われます。

Babelは、ECMAScript2015+で記述したコードをまだサポートできてないブラウザがあるため、そのコードをサポートしている形にコード変換を行つツールです。ECMAScript2015+は最近使えるようになった記述方法や機能を備えたJavaScriptです。

たった一行の設定ですがwebpackを自力で設定する場合は、LoaderやPluginなどのインストール、各処理の細かな設定を行う必要があります。

SassではなくLESSやStylusを使いたい場合は、sass()の部分をless()もしくはstylus()に変更することでCSSのプリプロセッサも変更することができます。

srcディレクトリを作成し、その中にapp.jsとapp.scssを作成します。


$ mkdir src && touch src/app.{js,scss}

Laravel Mixによりビルドが行われるか確認するために下記のコマンドを実行してください。最初の1回は、依存関係により追加のパッケージがインストールされるので、1回目完了後、再度実行してください。最初は、下記のコマンドを合計2回実行する必要があります。


 $ node_modules/webpack/bin/webpack.js --config=node_modules/laravel-mix/setup/webpack.config.js

 DONE  Compiled successfully in 553ms                                   22:38:23

       Asset      Size     Chunks             Chunk Names
/dist/app.js  4.36 KiB  /dist/app  [emitted]  /dist/app
dist/app.css   0 bytes  /dist/app  [emitted]  /dist/app

実行後、自動的にwebpack.mix.jsファイルで記述したdistディレクトリが作成され、下記の3つのファイルが作成されます。


 $ ls dist/
app.css			app.js			mix-manifest.json

Laravel Mixを実行するためにはモードの設定、設定ファイルの指定等コマンドに複数のオプションをつける必要があるため長いコマンドになります。複雑なコマンドを簡単に実行できるためにエイリアス(ショートカット)を設定します。エイリアスはpackage.jsonのscriptsに追加を行います。この情報も公式サイトに記載されているのでそのままコピー&ペーストを行ってください。


  "scripts": {
      "dev": "npm run development",
      "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
      "watch": "npm run development -- --watch",
      "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
      "prod": "npm run production",
      "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },

OSが異なる環境でも上記スクリプトが動作するためにcross-envパッケージもnpmでインストールしておきます。


$ npm install cross-env --save-dev
今回MAC環境で実行しているためcross-envパッケージのインストールは必要ありません。パッケージをインストールしない場合は、scriptsからcross-envの文字列を削除する必要があります。もしcross-envインストールなしで実行するとsh: cross-env: command not foundのエラーが表示されます。

上記の設定により、Laravel Mixの初期設定は完了です。

初めてのプログラムの動作

index.htmlファイルを作成して、Laravel Mixで生成したファイルが正常に動作するのか確認します。JavaScript用のscriptタグには、distの下に生成されるapp.js、スタイルシート用のlinkタグには、app.cssを指定してください。どちらもsrcディレクトリの下のファイルを指定するのではないので間違えないようにしてください。


<!DOCTYPE html>
<html lang="ja">
<head>
<title>Laravel Mix</title>
<link rel="stylesheet" href="dist/app.css">

</head>
<body>
<h1 class="first-header">初めてのLaravel Mix</h1>

<script src="dist/app.js"></script>	
</body>
</html>

srcディレクトリのapp.jsには、console.logコマンドを記述します。


console.log('Hello World');

srcディレクトリのapp.scssに下記を記述します。index.htmlのh1タグのfirst-headerクラスを通して背景の色を変更させます。


$red: #FF0000;

.first-header{
	background-color: $red;
}

作成が完了したら下記のコマンドを実行してください。webpackのビルドが行われます。npm runコマンドの後ろのdevがpackage.jsonのScriptsで設定したエイリアスのdevに対応します。


$ npm run dev

index.htmlをブラウザでプログラム通りに表示されるか確認します。ブラウザの開発モードのConsoleにHello Worldが表示され文字の背景が赤になっていれば、webpackはビルド処理は正常に動作しています。

ブラウザによる動作確認
ブラウザによる動作確認

追加したscriptsのコマンドの確認

package.jsonのscriptsに追加した行を見ながらnpm run devコマンドにはどのようなオプションが設定されているか確認していきます。

npm run devを実行すると実際には、以下のコマンドが実行されます。


"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
  • –progress:ビルドの進捗状況を表示させるオプション
  • –hide-modules:モジュールについての情報を非表示にするオプション
  • –config:Laravel Mixで利用するwebpack.config.jsの読み込み
  • cross-env:環境依存を解消するためにインストールしたパッケージ

オプションを除くとパスの設定があるので長いですが下記のようにシンプルなコマンドになります。このコマンドだけでもビルド処理を行うことができます。


 $ node_modules/webpack/bin/webpack.js --config=node_modules/laravel-mix/setup/webpack.config.js
 

モードによる動作の違い

package.jsonにscriptsに複数のコマンドのエイリアスを追加しましたが、NODE_MODEの設定により大きく2つにわけることができます。developmentとproductionです。developmentは開発用、productionは本番用のビルドを行う際に実行します。ビルドによって生成されるapp.cssを見ればすぐに違いがわかります。

development設定でのapp.css

developmentモードであるnpm run devで実行するとsrc/app.cssがどのように生成されるのかを確認します。

ビルドする前のsrcディレクトリの下のapp.scssファイルです。


$red: #FF0000;

.first-header{
	background-color: $red;
}

npm run devコマンドを実行してビルドを行います。


 $ npm run dev
 

実行後のdist/app.cssファイルの中身です。変数$redが展開されているが確認できます。


.first-header {
  background-color: #FF0000;
}

production設定でのapp.css

productionモードのnpm run prodを実行してビルドを行います。


 $ npm run prod
 

developmentモードとは異なり、app.cssが空白が埋められ最小化されていることが確認できます。


.first-header{background-color:red}

ここでは省略しますが、app.jsファイルも同様に最小化されています。生成されるファイルの中身を確認することでモードの違いを理解することができます。

watchによる変更の監視

JavaScriptファイル、Sassファイルを更新する度にnpm run devコマンドを実行するのは非効率なため、webpackはファイル変更を監視する機能を備えています。Laravel Mixもその機能を活用することができ、すでにpackage.jsonにはそのコマンドwatchが追加されています。


"watch": "npm run development -- --watch",

npm run watchを実行するとビルドが行われ、ファイル監視状態に入ります。


$ npm run watch

DONE  Compiled successfully in 11901ms

   Asset      Size  Chunks             Chunk Names
/app.css  48 bytes    /app  [emitted]  /app
 /app.js  4.39 KiB    /app  [emitted]  /app
 

npm run watchコマンドを実行したコンソールを開いたままJavaScriptファイルの更新を行うと自動でビルドを行ってくれます。

ブラウザとの同期(BrowserSync)

watchにより、ファイルの変更を監視できることがわかりました。変更を即座にブラウザに反映させることができればさらなる開発の効率化に繋がります。即座にブラウザに反映させるためBrowserSyncというパッケージを利用しますLarave MixではBrowserSyncも簡単に設定を行うことができます。

ローカルサーバの起動

learning-mix-laravelディレクトリからPHPを利用してローカルサーバーを起動します。


$ php -S 127.0.0.1:8080

本文書はMAC環境で動作確認を行っています。それぞれの環境にあった方法でサーバを起動してください。Laravelを使用している場合はphp artisan serveコマンドを利用すればローカルサーバを起動することができます。

webpack.mix.jsへのbrowserSync設定

browserSyncの設定は、webpack.mix.jsで行います。proxyには、起動させたローカルサーバの情報を入力してください。filesには、変更が行われるファイルを記述してください。

filesにファイルの指定を行わなければ、browserSyncでの同期は行われませんでした。


mix.js('src/app.js', 'dist/')
   .sass('src/app.scss', 'dist/')
   .setPublicPath('dist')
   .browserSync({
		proxy: 'http://127.0.0.1:8080/',
		files: [
	        "index.html",
	        "dist/*.*"
	    ],
		}
	);

npm run watchの実行

npm run watchを実行することで変更のファイル監視を行い、BrowserSyncを通して変更した内容を即座にブラウザに反映させることができます。

npm run watchを実行すると1回目は、npm install browser-sync browser-sync-webpack-plugin@2.0.1 –save-dev –production=falseが実行されるので、2回npm run watchを実行してください。ビルドの完了とBrowsersyncがファイルの監視(Watching files…)をしていることが確認できます。

BrowserSyncインストール後、npm run watchを実行するとcross-envに関してエラーが出力されたので、cross-envをpackage.jsonのscriptsから削除しました。

また、npm run watchが正常に完了するとURLにhttp://localhost:3000が入った状態でブラウザが自動起動します。ブラウザを閉じてもhttp://localhost:3000でアクセスすれば、browserSync Connectedとブラウザの右上上部に一時的に表示されます。


 DONE  Compiled successfully in 5199ms

   Asset      Size  Chunks             Chunk Names
/app.css  48 bytes    /app  [emitted]  /app
 /app.js   279 KiB    /app  [emitted]  /app
[Browsersync] Proxying: http://127.0.0.1:8080
[Browsersync] Access URLs:
 --------------------------------------
       Local: http://localhost:3000
    External: http://192.168.2.180:3000
 --------------------------------------
          UI: http://localhost:3001
 UI External: http://localhost:3001
 --------------------------------------
[Browsersync] Watching files...

BrowserSync
BrowserSync

npm run watch実行後、app.jsとapp.scssを更新するとビルドが行われ、ブラウザに反映されます。index.htmlの場合は更新するとビルドは行われませんがブラウザには自動で反映されます。

JavaScriptライブラリ

jQueryをAutoloadingで動作させる

Laravel MixのドキュメントでAutoloadingによるjQueryの設定方法の記述を見つけたので動作するのか確認を行います。

jQueryを使用するためには、npmでインストールを行う必要があります。


 $ npm install jquery

Autoloadingの機能を利用するためにwebpack.mix.jsにautoloadを下記のように追加します。


mix.js('src/app.js', 'dist/')
   .sass('src/app.scss', 'dist/')
   .setPublicPath('dist')
   .autoload({
    jquery: ['$', 'window.jQuery']
	})
   .browserSync({
		proxy: 'http://127.0.0.1:8080/',
		files: [
	        "index.html",
	        "dist/*.*"
	    ],
		}
	);
webpack.mix.jsファイルを更新したら、rpm run watchコマンドを一度停止し再度実行してください。

ここまでの設定jQueryのautoloadの設定は完了です。jQueryを使用してindex.htmlにあるfirst-headerのクラスを使ってh1タグの中の文字列を変更します。変更は、src/app.jsファイルで行います。


console.log('Hello World');

$(function(){
    $('.first-header').html('jQueryで変更を行いました');
});

npm run watchを実行していない場合は、手動でビルドを行いブラウザでindex.htmlファイルを確認してください。”jQueryで変更を行いました”の文字列がブラウザに表示されれば、jQueryの動作確認は完了です。

生成されたdistディレクトリのapp.jsの中にjquery.jsのコードの中身が含まれていることも確認してください。

コード分割(Library Code Splitting)について

jQueryをautoloadした後にビルドが完了するとjQueryの中身も生成されるapp.jsに含まれることがわかりました。jQueryを含め、ライブラリの情報のみ別ファイルに分けることも可能です。

webpack.mix.jsにextract()を追加するだけで分割が可能です。


mix.js('src/app.js', 'dist/')
   .sass('src/app.scss', 'dist/')
   .setPublicPath('dist')
   .autoload({
    jquery: ['$', 'window.jQuery']
	})
   .browserSync({
		proxy: 'http://127.0.0.1:8080/',
		files: [
	        "index.html",
	        "dist/*.*"
	    ],
		}
	)
   .extract();

ビルドを行うとdistディレクトリにvendor.jsとmanifest.jsファイルが作成されます。これまではindex.htmlではscriptタグでapp.jsのみ指定していましたが、分割後は追加で生成されたvendor.jsとmanifest.jsも指定する必要があります。


<!DOCTYPE html>
<html lang="ja">
<head>
<title>Laravel Mix</title>
<link rel="stylesheet" href="dist/app.css">

</head>
<body>

	<h1 class="first-header">初めてのLaravel Mixです</h1>

<script src="dist/manifest.js"></script>
<script src="dist/vendor.js"></script>
<script src="dist/app.js"></script>	
</body>
</html>

分割前と同じ結果がブラウザに表示されます。

特定のライブラリのファイルのみ分割することも可能です。下記のようにパッケージ名を入力することで実現することができます。


mix.extract(['vue', 'jquery']);

Vueのimport

vue.jsを利用したい場合はnpm installコマンドでvueのライブラリをインストールして、importを行います。


$ npm install vue

app.jsファイルを開いてvueのimportを行います。


import Vue from 'vue'

console.log('Hello World');

const vue = new Vue({
  el: '#app',
  data:{
    message : 'laravel-mixでvueを使う',
  }
})

index.htmlに<div id=”app”></div>を追加する必要があります。


<!DOCTYPE html>
<html lang="ja">
<head>
<title>Laravel Mix</title>
<link rel="stylesheet" href="dist/app.css">

</head>
<body>
<h1 class="first-header">初めてのLaravel Mixを</h1>

<div id="app">
  <h2>{{ message }}</h2>

</div>

<script src="dist/app.js"></script> 
</body>
</html>

ブラウザで確認するとデータバインディングによって”laravel-mixでvueを使う”が画面上に表示されます。

vueを使って文字列を表示
vueを使って文字列を表示

バージョン管理(Versioning)

パフォーマンスを上げるためブラウザには、ダウンロードしたファイルをキャッシュに保存する機能を持っています。サーバ側でファイルの中身を更新してもブラウザがキャッシュの中のデータを使うとサーバ側でのファイルの更新が伝わりません。この問題を解決する方法をcache-busting(キャッシュバスティング)と呼びます。

Laravel Mixでは更新したファイルにid(app.js?id=0d0349b9ba3726452937)を振ることで対応します。idは変更を行う度に更新されます。

webpack.mix.jsファイルにversion()を加えるとその機能を使うことができます。


mix.js('src/app.js', 'dist/')
   .sass('src/app.scss', 'dist/')
   .setPublicPath('dist')
   .version()
   .autoload({
    jquery: ['$', 'window.jQuery']
	})
   .browserSync({
		proxy: 'http://127.0.0.1:8080/',
		files: [
	        "index.html",
	        "dist/*.*"
	    ],
		}
	)
   .extract();

vesrion()を追加後にビルドを行うとdistディレクトリの中にmix-manifest.jsonファイルが作成されます。このファイルには、idの付与されたものと付与されていないファイル名の対がJSONで保存されています。


{
    "/app.js": "/app.js?id=0d0349b9ba3726452937",
    "/app.css": "/app.css?id=c2814d718c41f4325942",
    "/manifest.js": "/manifest.js?id=615471e7b4e5caeb45c5",
    "/vendor.js": "/vendor.js?id=1e1c705930acf6911bfe"
}

Laravelを使っているとmix関数が準備されているので、下記のように記述するとこのmix-manifest.jsonファイルから情報を読み取り、scriptタグ、linkタグにidの入ったファイル名を挿入することができます。

<script src="{{ mix('js/app.js') }}"></script>

Laravelを使用していない環境ではこの関数はないので、mix-manifest.jsonファイルに入ったJSONを読み込むプログラムを自作する必要があります。