はじめに

Laravel で JavaScript を使うときのあれこれを調べた。

  • 機能やページ単位で JS ファイルを作成した場合、どのように取りまとめや読み込みを行う?
  • 本番環境向けのバージョニングはどうすればよい?

などなど。

TL;DR

  • Laravel Mix を使うと JS などのアセットを良い感じに扱える
  • webpack.mix.jsmix.js(), mix.version(), mix.browserSync() などを使う
  • Blade では mix('path/to/js') で読み込んだり、@push@stack で個別 JS を読み込むようにする
この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. Laravel Mix, webpack について
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ grep -i pretty /etc/os-release
PRETTY_NAME="Ubuntu 16.04.3 LTS"

$ php -v
PHP 7.2.22-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Sep 2 2019 12:54:12) ( NTS )

$ composer -V
Composer version 1.9.0 2019-08-02 20:55:32

$ composer info laravel/framework
name : laravel/framework
versions : * v5.7.28

$ npm v laravel-mix
laravel-mix@5.0.1 | MIT | deps: 38 | versions: 132

詳細

Laravel Mix, webpack について

まず前提として Laravel には Laravel Mix という JS や CSS(や SCSS/etc) を簡単に扱うための仕組みが用意されている。
参考: アセットのコンパイル(Mix) 5.7 Laravel

npm run dev, npm run watch, npm run prod などを実行すると、依存関係の解決やバンドルなど良きに計らってくれる。

Input/Output の設定

webpack.mix.js に Laravel Mix で処理して欲しいファイルや設定を記述する。JS の場合は mix.js() で指定する。
参考: JavaScriptの操作

1
2
3
4
5
6
7
8
9
// 以下に出力される
// resources/js/app.js -> public/js/app.js
// resources/js/asset/xxxx.js -> public/js/xxxx.js
// resources/js/asset/yyyy.js -> public/js/yyyy.js
// resources/js/asset/zzzz.js -> public/js/zzzz.js
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/asset/xxxx.js', 'public/js')
.js('resources/js/asset/yyyy.js', 'public/js')
.js('resources/js/asset/zzzz.js', 'public/js');

上記のように書くと、各ファイルの依存関係解決などした上で、第2引数のディレクトリにファイルが出力される。

バージョニング

本番環境向け(ブラウザキャッシュ対策)としてハッシュを付けるには mix.version() を実行すれば良い。以下のように編集する。読み込み側の話は後述。
参考: バージョン付け/キャッシュ対策

1
2
3
4
5
6
 mix.js('resources/js/app.js', 'public/js')
...

+if (mix.inProduction()) {
+ mix.version();
+}
ブラウザの自動リロード

開発環境で、ファイル編集したらブラウザの自動リロードが動作するようにしておくと良い。mix.browserSync() を設定すれば良い。ドメイン('localhost' の部分)は適宜設定。
参考: Browsersyncリロード

1
2
3
4
5
6
7
8
9
 mix.js('resources/js/app.js', 'public/js')
...

if (mix.inProduction()) {
mix.version();
-}
+} else {
+ mix.browserSync('localhost');
+}

mix.browserSync() を書いておくと、npm run watch でブラウザが起動するようになり、PHP や JS などを編集した場合に自動でリロードしてくれるようになる。

コンパイル済みアセットの読み込み(共通)

コンパイルされた JS などを読み込む場合は、Blade で mix('/path/to/file') を使う。

共通的なファイルは、レイアウトファイルにそのまま記述すれば OK。

1
2
3
4
5
6
7
8
...
<head>
...
<!-- head or body に記述 -->
<script src="{{ mix('/js/app.js') }}"></script>
...
</head>
...

開発環境(npm run devnpm run watch)は /js/app.js として、本番環境(npm run prod)は /js/app.js?id=1234abcd... として読み込んでくれる。

なお、?id=xxxx はブラウザのキャッシュ対策として付くハッシュ値。実際に出力されるファイルの名前は npm run dev でも npm run prod でも変わらない(public/js/app.1234abcd...js とかで出力されるわけではない)ので注意。
※勘違いしててしばらくハマった。

コンパイル済みアセットの読み込み(個別)

特定のページでしか動作させたくない JS を読み込みたい場合は、@push@stack を使う。
参考: スタック

まずは個別 view ファイルを編集、@push, @endpush 内で JS を読み込ませる。

1
2
3
4
5
6
<?php
...
@push('scripts')
<script src="{{ mix('/js/xxxx.js') }}"></script>
@endpush
...

@push('key') の内容は、@stack('key') で読み込まむことができる。レイアウトファイルに @stack('scripts') を記述することで、各 view に @push があれば読み込んでくれるようになる。

1
2
3
4
5
6
7
8
9
...
<head>
...
<!-- head or body に記述 -->
<script src="{{ mix('/js/app.js') }}"></script>
@stack('scripts') <!-- ***** 追加 ***** -- >
...
</head>
...
JS をひとまとめにする

先ほどの例では、依存関係の解決などは行うが、JS ファイル自体は複数にわかれる方式になっている。

app.js にひとまとめにしても問題ない(全てのページで JS が読み込まれても、他には影響を及ぼさない)のであれば、resources/js/app.jsrequireimport で読み込ませる形にすると良い。

1
2
3
require('./asset/xxxx');
require('./asset/yyyy');
...

その場合は webpack.mix.js には app.jsresources/js/app.js で読み込んでない分だけを記述

1
2
3
// xxxx, yyyy は resources/js/app.js で読み込ませているので、zzzz だけ記述
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/asset/zzzz.js', 'public/js');

なお「全てのページで JS が読み込まれても、他には影響を及ぼさない」の記述の通り、JS 側でガード処理がない場合は、他ページで意図しない挙動になるかもしれないので注意。

1
2
3
4
5
6
7
8
9
// NG
$(function () {
...
// 消えてほしくないものが消えるかも
if ($('#hoge').length > 0) {
$('#hoge').remove();
}
...
});
1
2
3
4
5
6
7
8
9
10
11
12
13
// OK (他にもっと良い方法あるかも)
$(function () {
...
// 「指定ページかどうか」を確認
const url = new URL(location);
const path = url.pathname;
if (path.startsWith('/some/path')) {
if ($('#hoge').length > 0) {
$('#hoge').remove();
}
}
...
});

まとめ

  • Laravel Mix を使うと JS などのアセットを良い感じに扱える
  • webpack.mix.jsmix.js(), mix.version(), mix.browserSync() などを使う
  • Blade では mix('path/to/js') で読み込んだり、@push@stack で個別 JS を読み込むようにする

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list