laravel-mixの続きです。まだ続きそうなので、連載ものにしました。右にリストされているCATEGORIESのフロントエンドの開発です。
今回は、laravel-mixで作成されたjsやcssのファイルがどのようにbladeで参照されているかにフォーカスします。
asset()
再びレイアウトのbladeファイルの中身を以下に掲載します。
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- CSRF Token --> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>{{ config('app.name', 'Laravel') }}</title> <!-- Scripts --> <script src="{{ asset('js/app.js') }}" defer></script> <!-- Fonts --> <link rel="dns-prefetch" href="//fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet"> <!-- Styles --> <link href="{{ asset('css/app.css') }}" rel="stylesheet"> </head> <body> ...
上の中の以下に注目してください。
... <script src="{{ asset('js/app.js') }}" defer></script> ... <link href="{{ asset('css/app.css') }}" rel="stylesheet"> ...
asset()
は、app.jsなどのファイルが存在するURLを生成するヘルパーです。与えた引数の値をURLにしてくれます。
$ php artisan tinker Psy Shell v0.9.9 (PHP 7.2.16 — cli) by Justin Hileman >>> asset('js/app.js') => "http://localhost/js/app.js"
という具合です。
URLのサイトやディレクトリを変えたければ、.envを編集します。
$ cat .env ... ASSET_URL=https://example.com/assets
と設定すれば、
>>> asset('js/app.js') => "https://example.com/assets/js/app.js"
となります。
また、先のレイアウトの出力は、
... <script src="https://example.com/assets/js/app.js" defer></script> ... <link href="https://example.com/assets/css/app.css" rel="stylesheet">
となります。
ブラウザのキャッシュをバスト
通常のブラウザでは、HTMLで参照されるファイル名が同じであるとブラウザにキャッシュされます。キャッシュされること自体は転送時間を節約する意味で素晴らしいのですが、app.jsの中身が更新されたときはブラウザにキャッシュされているものを使用してもらいたくありません。
そのようなときに(つまりキャッシュをバストしたいとき)によく使われるのは、URLにPHP関数のtime()
をURLに追加することです。
例えば、
<script src="{{ asset('js/app.js').'?'.time() }}" defer></script>
は、
<script src="https://example.com/assets/js/app.js?1570143025" defer></script>
となります。
毎回毎回アクセスする度に、time()
の値は変わるのでapp.jsはキャッシュされず、ブラウザはファイルをサーバーから毎回毎回取得します。
しかし、これだと困ります。app.jsが更新されるまではキャッシュして欲しいのです。
そこで登場するのが、larave-mixのバージョン機能です。
まず、webpack.mix.jsを編集します。
const mix = require('laravel-mix'); mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css'); if (mix.inProduction()) { mix.version(); }
追加したのは最後の3行です。プロダクションの実行のときにバージョン化を行う指定です。
次に、
$ npm run prod
を実行します。app.cssやapp.jsのファイルを生成するとともに、mix-manifest.jsonのファイルをpublicのディレクトリに作成します。
そのファイルの中身には、必要なファイルのバージョン化のためのマップが定義されています。
{ "/js/app.js": "/js/app.js?id=d1c6ff581391a0e168f2", "/css/app.css": "/css/app.css?id=33e746eff21c53ed136b" }
この情報を使用するには、mix()
を使いレイアウトを以下のように編集します。
... <script src="{{ asset(mix('js/app.js')) }}" defer></script> ... <link href="{{ asset(mix('css/app.css')) }}" rel="stylesheet"> ...
出力は以下となります。
... <script src="https://example.com/assets/js/app.js?id=d1c6ff581391a0e168f2" defer></script> ... <link href="https://example.com/assets/css/app.css?id=33e746eff21c53ed136b" rel="stylesheet"> ...
先のtime()
とは違って、更新されたときのみにidの値が変わり、それまではブラウザにキャッシュされてもOKとなります。