【Laravel】 Mixを使用して様々なスクリプトやSassなどをビルドする
Laravel Mixは、webpackビルド手順を定義するAPIを提供するものです。Webpackを用いるよりもより手軽に書くことができます。
目次
環境構築
まずは、Laravel Mixを使ってビルドできる状態にしましょう。内部ではwebpackが使用されているため、Node.jsが必要です。
Node.js及びnpmの導入は下の記事で説明しています。
Laravel Sailなどで導入すると、最初からビルドに必要な依存がpackage.jsonで定義されているので、package.jsonから適当に導入します。
# package.jsonにある全ての依存をインストール npm i
webpack.mix.js
にはすでに最小限の定義が書かれているので、インストールしたら早速npm run dev
しましょう。webpack compiled successfully
のようなメッセージが出れば完了です。
開発初期によくあるのですが、動かないと思ったらビルドだけしてビューで読み込んでいないことがあるので、気をつけましょう。
とりあえずビルド
初期設定では、webpack.mix.js
が
mix.js('resources/js/app.js', 'public/js') .postCss('resources/css/app.css', 'public/css');
のようになっています。ビルドすると、public/js/app.js
とpublic/css/app.css
が作成されます。ブラウザでこれらを読み込む際は、
<html lang="ja"> <head> <link rel="stylesheet" href="{{ asset('css/app.css') }}"> <title>{{ $title }}</title> </head> <body> {{ $slot }} <script src="{{ asset('js/app.js') }}"></script> </body> </html>
のように、asset
を使用することをおすすめします。asset
は、public
内のファイルを参照できるようにURLを自動的に組んでくれるものです。
よくあるビルド
ビルドに関する設定は、webpack.mix.js
に書かれています。
const mix = require('laravel-mix'); /* ... */ mix.js('resources/js/app.js', 'public/js') .postCss('resources/css/app.css', 'public/css', [ // ]);
なんとなくresources/js/app.js
とresources/css/app.css
がビルドの起点で、それぞれ出力先が指定されているなあ、ということはわかると思います。
sassをビルドする
しばしばcssではなくSassを使用することがあると思います。その場合、postCss
の代わりにsass
します。
mix.js('resources/js/app.js', 'public/js') .sass('resources/css/app.scss', 'public/css') ;
.hoge { .fuga { color: red; } }
まずは何も導入せずにnpm run dev
します。そうすると不足しているパッケージを導入するためのコマンドが表示されるので、表示されたら再度npm run dev
してください。
Additional dependencies must be installed. This will only take a moment. Running: npm install sass-loader@^12.1.0 sass resolve-url-loader@^5.0.0 --save-dev --legacy-peer-deps Finished. Please run Mix again.
npm run dev
あとはpublic
ディレクトリにファイルが出力されているか確認して実際に表示してみましょう。public
ディレクトリ内のファイルのURLは、asset
関数を用いることを推奨します。
<head> <!-- asset関数でpublicディレクトリからのURLを取得 --> <link rel="stylesheet" href="{{ asset('css/app.css') }}"> <title>{{ $title }}</title> </head>
Vueの導入とビルド
laravel/uiの導入
app.jsなどの一部のファイルが書き換わるため、すでに開発進行している場合は省略して大丈夫です。
Laravelでのvueの導入は、直接npm i vue
等をしてもよいのですが、laravel/ui
を経由すると、最小限のサンプルも入っているため楽に導入できます。
# laravel/uiの導入 composer require laravel/ui # vue を有効化 php artisan ui vue
最後にPlease run "npm install && ..."
と表示されれば、それを実行してVueの導入は完了です。これと同時にpackage.json
への依存の追加や、webpack.mix.js
に.vue()
の追加が行われています。
npm run dev
すると、おそらく追加のパッケージの導入が行われるので、その際は再度npm run dev
します。
この手法ではvue2が導入されます。vue3を使用する場合は、npm i vue@latest
する必要があります。
vue-loader
やvue-template-compiler
も古いバージョンなので、npm i vue-loader@latest
等で更新しておきましょう。
ビルドする
webpack.mix.js
で、ビルド対象となるjsに.vue()
を追加します。laravel/uiを使用した場合は既についていると思いますが、手動で導入した場合やエントリを追加する場合は付け忘れないようにしましょう。
mix.js('resources/js/app.js', 'public/js') .vue();
続いて、laravel/uiで導入した場合のapp.js
を見ると、コードが追加されています。
window.Vue = require('vue').default; /** ... */ // const files = require.context('./', true, /\.vue$/i) // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)) Vue.component('example-component', require('./components/ExampleComponent.vue').default); /** ... */ const app = new Vue({ el: '#app', });
コメントアウトされたコードが追加されています。これを利用すると全てのコンポーネントを読み込め、自動的に適切な名前をつけて使えるようにますよ、と言っています。スクリプトは1エントリないし数エントリで済ませ、SPAでなくても複数のページ分のコンポーネントを全部読み込みといったことは実際にあるため、その場合はこれを利用するのはありです。
vueコンポーネントを読み込んだら、
<div id="app"> <example-component></example-component> </div>
をビューに書いて、npm run dev
でスクリプトをビルドして表示できるか試してみましょう。
laravel/uiを使用していない場合かつ必要なパッケージが入っていない場合、裏で自動的に必要なパッケージが導入されます。その場合は再度npm run dev
が必要です。
vue3の場合、require等を書き換える必要があります。
const { createApp } = require('vue'); const ExampleComponent = require('./components/ExampleComponent.vue').default; const app = createApp({ components: { ExampleComponent } }).mount("#app");
Reactの導入とビルド
laravel/uiの導入
app.jsなどの一部のファイルが書き換わるため、すでに開発進行している場合は省略して大丈夫です。
Laravelでのvueの導入は、直接npm i react
等をしてもよいのですが、laravel/ui
を経由すると、最小限のサンプルも入っているため楽に導入できます。
# laravel/uiの導入 composer require laravel/ui # react を有効化 php artisan ui react
最後にPlease run "npm install && ..."
と表示されれば、それを実行してReactの導入は完了です。これと同時にpackage.json
への依存の追加や、webpack.mix.js
に.react()
の追加などが行われています。
npm run dev
すると、おそらく追加のパッケージの導入が行われるので、その際は再度npm run dev
します。
最新に近いバージョンが導入されると思いますが、ベータ版などを使用したい場合、react
、react-dom
、@babel/preset-react
それぞれnpm i react@beta
などで更新してください。
ビルド
webpack.mix.js
で、ビルド対象となるjsに.react()
を追加します。laravel/uiを使用した場合は既についていると思いますが、エントリを追加する場合は付け忘れないようにしましょう。
mix.js('resources/js/app.js', 'public/js') .react();
あとはnpm run dev
でビルドし、<div id="example"></div>
をビューに追加して表示できるか試してみましょう。
Typescriptでビルド
Typescriptを使用したい場合、.ts()
を付けるだけです。
mix.ts('resources/js/app.ts', 'public/js') .react();
ここでnpm run dev
すると必要なパッケージが自動でインストールされます。
続いて、tsconfig.json
を用意する必要があります。Laravelが入っているディレクトリで、
npx tsc --init
を実行するとtsconfig.json
が作成されます。この状態で改めてnpm run dev
するとビルドできます。
URLの処理
CSSをコンパイルする際に、url('...')
で相対パスで書かれているものは、resources
から自動的に該当の画像をpublic
にコピーし、URLの末尾にはキャッシュ対策としてランダムな文字列が付け加えられます。
.hoge { .fuga { background-image: url("../img/hoge.png"); } }
.hoge .fuga { background-image: url(/images/hoge.png?faad03f50cf898542b5471e8e972d0ed); }
url("/hoge/fuga.jpg")
のように絶対パスの場合は書き換わらず、かつ画像のコピーもされません。https://.../hoge/fuga.png
が直接参照されます。
もしこのURLが自動的に書き換わるのと画像が自動でコピーされる挙動を無効化する場合、webpack.mix.js
でoptions
にprocessCssUrls: false
を付けて無効化します。
mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css') .options({ processCssUrls: false });
ソースマップ
ソースマップを有効化することで、デバッグ実行時にビルドされたスクリプトとビルド前のスクリプトのコードの対応を紐付けてくれます。これにより、ステップ実行をビルド前のスクリプトを使用して可能になるなど、デバッグ効率が格段に上がります。
ソースマップを有効化するには
mix.js('resources/js/app.js', 'public/js') .sourceMaps();
のように.sourceMaps()
を付けるだけです。npm run watch
し直したら、動作しているかブラウザで試してみましょう。

もしソースマップのスタイルを変更したい場合、sourceMaps
のメソッドの引数に設定します。第1引数はProduction環境の場合にソースマップを作成するかどうか、第2引数はDevelop環境でのソースマップスタイル、第3引数はProduction環境でのソースマップスタイルです。
// prodでもソースマップを作成し、devではeval-source-mapを、prodではsource-mapを使用するように設定 mix.js('resources/js/app.js', 'public/js') .sourceMaps(true, 'eval-source-map', 'source-map');
ソースマップのスタイル一覧はWebpack公式のページを参照するのが手っ取り早いです。
Webpackの設定をオーバーライド
mix.webpackConfig
を使用して、普通にWebpackの設定を記述することもできます。ここに書くと、設定がオーバーライド (書いた部分だけ上書きや追加) されます。
mix.ts('resources/js/app.ts', 'public/js') .webpackConfig({ resolve: { alias: { "@": __dirname + "/resources/js" }, extensions: ["tsx", "jsx"] } });
aliasはmix.alias({/* ... */})
でも同じ書き方で可能です。
mix.ts('resources/js/app.ts', 'public/js') .alias({ "@": __dirname + "/resources/js" });
バージョニング
普通にビルドすると、普通のファイル名で出力されます。何が問題かというと、そのままではキャッシュが破棄されるまでブラウザやCDNのキャッシュが更新されず、古いスクリプトを利用してしまうことです。
これを回避するには、.version()
をつけて、バージョン番号を付与するように構築します。
mix.ts('resources/js/app.ts', 'public/js') .sass('resources/sass/app.scss', 'public/css') .version();
バージョニングを有効化してもファイル名自体はそのままですが、asset
関数ではなくmix
関数を使用することで、ランダム文字列を付与したURLを使用されます。ビルドするたびに変化するため、キャッシュ対策になります。
<head> <link rel="stylesheet" href="{{ mix('css/app.css') }}"> </head> <body> <script src="{{ mix('js/app.js') }}"></script> </body> </html>
この時生成されるファイルのURLを変更したい場合 (例えばCDNのurlを指すなど)、config/app.php
にmix_url
を追加します。
use Illuminate\Support\Facades\Facade; return [ // ... 'mix_url' => env('MIX_ASSET_URL', null), ];
実際の値は.env
に
MIX_ASSET_URL="https://cdn.example.com"
のように書きます。
保存時に自動ビルドする
ビルド対象のファイルを保存した際に自動的にビルドし直す事ができます。
# 保存時に自動的にビルド npm run watch
これだけで保存時に自動的にビルドされます。
これをホットリロードといいます。
もしdocker内でビルドしている場合、うまくホットリロードが効かない場合があります。その場合、watch-poll
します。
npm run watch-poll
ここで、ビルド対象のファイルに変更が加わると自動的にビルドし直されますが、webpack.mix.js
は変更してもビルドし直されません。改めてnpm run watch
する必要があります。
Browsersync
Browsersyncを使用すると、watch
で再ビルドされると同時に、ブラウザで自動でリロードされます。
まずはwebpack.mix.js
で有効化しましょう。
mix.browserSync('laravel.test');
が、docker内などで構築している場合はこれだけではうまく行かないので、他にも設定を入れる必要があります。
最低限、host
、proxy
、watchOptions
の3つが必要でした。
mix.browserSync({ host: 'localhost', proxy: { target: "http://localhost", ws: true }, watchOptions: { usePolling: true, interval: 100 }, });
次に、dockerで環境構築している場合は、laravelが入っているコンテナで3000、3001、3002ポートを開放します。
laravel.test: // ... ports: - '${APP_PORT:-80}:80' - '3000:3000' - '3001:3001' - '3002:3002'
書いたら、コンテナを立ち上げ直し、npm run watch
かwatch-poll
をします。
済んだら、http://localhost:3000
にアクセスしてページを表示し、適当なビルド対象のファイルを書き換えてみましょう。ブラウザのページが自動的にリロードされるはずです。
もしviewやcontrollerなどのファイルの変更も検知したい場合、files
にパス一覧を書きます。
mix.browserSync({ // ... files: [ './resources/**/*', './app/**/*' ], // ... });
この場合はかなりのファイル数が検知対象となって重い可能性があるので、もう少し対象を絞っても良いかもしれません。
管理画面
http://localhost:3001
か3002
にアクセスすると、Browsersyncの管理画面を表示できます。とはいえ、そこまでたいした設定は並んでいないのでそこまで使用しないと思います。
CSSのグリッドレイアウトのアウトラインなど、一部使えそうなものはありますが、ブラウザでF12する方が情報も多くて楽です。
まとめ
Laravel Mixを使用すると、今まではwebpackで長々と設定を書いていたのを、簡単に書くことができるようになります。ReactやVueも複雑な設定を書かずに済むため、積極的にAPIを使用していきましょう。
