Laravel9になり、デフォルトのビルドツールはLaravel MixからViteに変更になっています。これからLaravel9を学習する人はLaravel MixではなくViteの学習をしましょう。

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

Laravel Mixのバージョンが6になり、npx mixコマンドが追加されるなど変更が行われています。
fukidashi

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

Laravel Mixとは

Laravel MixはJavaScript、CSSなどのフロントエンドに関連するJavaScript, CSSファイルをビルド/コンパイルするためのツールです。LaravelではバックエンドはPHPで記述されているためLaravel本体とLaravel Mixを切り離して考えることができます。インタラクティブなUIが必要ではなくJavaScriptを利用しない場合はLaravel Mixは必要ではありません。JavaScriptを利用することが前提になっていることを理解しておいてください。またJavaScriptを使ってアプリケーションを構築する場合でもLaravel Mixは必須ではなく他のツールまたは自分でwebpackを利用して環境を構築しても問題はありません。

Laravel mixを理解するためにはwebpackというツールの存在と基礎的な知識が必要となります。webpackについては入門者向けに記事を作成済みですのでwebpackがわからない人は下記を参考にしてみてください。webpackにはさまざまなプラグインや設定がありwebpackの大変さが理解できればLaravel Mixの存在の価値をより感じることができます。

WEB開発者にとってwebpackを理解し使いこなすのは簡単ではありません。一般的なサイトで使用されている最適なwebpackの設定を事前に行い、できるだけ簡単にwebpackを扱えるようにと開発されたのがLaravel Mixです。Laravel Mixはwebpackのwrapper(ラッパー)です。Laravel Mixという名前がついているのでwebpackとは別のツールでLaravelとの結びつきが強くLaravel環境でしか使うことができない印象を受けますが、Laravelがなくても使用することが可能です。Laravelとは別のツールなので、Lravel Mix単独の公式サイトも存在していましたが2022年10月には確認できませんでした。Laravel Mixの情報はhttps://github.com/laravel-mix/laravel-mixで確認することができます。

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

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

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


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

npm init -yコマンドでpackage.jsonファイルの作成を行います。


 $ npm init -y

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

Laravel Mixのインストール

npm installでLaravel Mixのインストールを行います。その後、Laravel Mixの設定ファイルであるwebpack.mix.jsのコピーを行います。バージョンが6ではwebpack.mix.jsファイルは存在しないのでtouchコマンドでwebpack.mix.jsファイルを作成してください。


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

// Laravel Mixの場合はtouchコマンドで作成
$ touch wepack.mix.js

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


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

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

webpackを利用する場合はwebpack.config.jsが設定ファイルとなります。
fukidashi

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の処理も行われます。

ECMAScript2015+で記述したJavaScriptのコードがサポートできてないブラウザ(IEなど)が存在します。Babelを利用することでそれらのブラウザがサポートしている形にコード変換を行うことができます。ECMAScript2015+は効率的な記述方法や新たな機能を備えたJavaScriptです。Babelはトランスパイラと呼ばれアロー関数など新しい方法で記述したコードを以前の古い記述方法に変換してくれるツールです。
fukidashi

Laravel Mixではたった一行の設定ですがwebpackを自力で設定する場合はこの1行と同じ設定をするために複数のLoaderやPluginなどのインストール、各処理の細かな設定を行う必要があります。

SassではなくLESSやStylusを使いたい場合は、sass()の部分をless()もしくはstylus()に変更することでCSSのプリプロセッサも変更することができます。Sassの記述のままではブラウザが認識することができないためCSSのプリプロセッサでCSSの記述に変換を行います。
fukidashi

初めてのビルド(Ver.5まで)

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パッケージのインストールは必要ありません。パッケージをインストールしない場合は、package.jsonのscriptsからcross-envの文字列を削除する必要があります。もしcross-envインストールなしで実行するとsh: cross-env: command not foundのエラーが表示されます。
fukidashi

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

はじめてのビルド(Ver.6)

ドキュメントと合わせるためにwebpack.mix.jsファイルの内容を以下に更新してください。更新前のファイルの内容でエラーがでるわけではありません。


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

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

srcフォルダを作成して、app.jsファイルを作成してください。ファイルには以下を記述します。


alert('hello world');

作成が完了したらnpx mixコマンドを実行します。実行するとビルドが行われます。


 % npx mix
//略

   Laravel Mix v6.0.31   
                         

✔ Compiled Successfully in 216ms

実行後distフォルダが作成されるので中身を確認するとapp.js, mix-manifest.jsonファイルが作成されていることが確認できます。


 % ls
app.js                  mix-manifest.json

バージョン5まではpackage.jsonファイルのscriptsにコマンドを記述していましたがバージョン6でscriptへ追加する必要がありません。そのかわりにnpx mixコマンドのオプションによって開発、本番用のビルドを行えるようになっています。


//Development
 % npx mix

// Production
 % npm mix --production

// watch
 % npx mix watch

//Hot Module Replacemen
 % npx mix watch --hot

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

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;
}

Ver.5までの場合

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


$ npm run dev

Ver.6の場合

先程ビルドする際にwebpack.mix.jsファイルのsassの1行を削除したためapp.scssの変換が行われないため追加します。


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

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

npx mixコマンドを実行します。実行するとsassに関する追加パッケージのメッセージが表示されるので再度npm mixコマンドを実行する必要があります。


 % npx mix
        Additional dependencies must be installed. This will only take a moment.
 
        Running: npm install sass-loader@^12.1.0 sass resolve-url-loader@^4.0.0 --save-dev --legacy-peer-deps
 
        Finished. Please run Mix again.

再度npx mixコマンドを実行するとビルドが完了します。


$ npm mix

distフォルダの中にjs, cssフォルダが作成されmす。jsにはapp.js, cssにはapp.cssファイルが保存されるのでindex.htmlファイルのパスを設定します。


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

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

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

表示される内容(共通)

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

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

追加したscriptsのコマンドの確認(Ver.5)

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
 

モードによる動作の違い

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

バージョン6の場合は実行するコマンドがnpx mixかnpx mix –productionの違いになります。

development設定でのapp.css

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

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


$red: #FF0000;

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

npm run devコマンドを実行してビルドを行います。(Ver.5まで)


 $ npm run dev
 

npm mixコマンドを実行してビルドを行います。(Ver.6)


 $ npx mix
 

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


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

production設定でのapp.css

productionモードのnpm run prodを実行してビルドを行います。(Ver.5まで)


 $ npm run prod
 

npx mix –productionを実行してビルドを行います。(Ver.6)


 $ npx mix --production
 

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


.first-header{background-color:red}

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

watchによる変更の監視(Ver.5まで)

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ファイルの更新を行うと自動でビルドを行ってくれます。

watchオプションによる変更の監視(Ver.6)

JavaScriptファイル、Sassファイルを更新する度にnpx mixコマンドを実行するのは非効率なため、webpackはファイル変更を監視する機能を備えています。Laravel Mixもその機能を活用することができ、npx mixコマンドにオプションのwatchを追加します。


 % npx mix watch

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


$ npm run watch

                         
   Laravel Mix v6.0.31   
                         

✔ Compiled Successfully in 717ms

ebpack compiled successfully
 

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

ブラウザとの同期(BrowserSync)

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

ローカルサーバの起動

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


$ php -S 127.0.0.1:8080

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

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から削除しました。
fukidashi

また、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コマンドを一度停止し再度実行してください。
fukidashi

ここまでの設定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を読み込むプログラムを自作する必要があります。