Laravel 6 で Bootstrap File Input を使う(Font Awesome 5 のインストールも)

Bootstrap 4 の <input type="file"> にプレビューの機能などを追加していい感じにしてくれる Bootstrap File Input を Laravel 6(というか、Laravel Mix)で使うのに、割と悪戦苦闘したので、まとめておきます。

Bootstrap File Input の説明ページにも書いてありますが、Bootstrap 4 には Glyphicons が同梱されていないので、デフォルトの状態だとアイコンが表示されません。Bootstrap File Input には Font Awesome 5 に対応したテーマも同梱されているので、Font Awesome 5 もあわせてインストールします。

Bootstrap File Input と Font Awesome 5 のインストールには、npm を利用します。

npm install bootstrap-fileinput --save
npm install @fortawesome/fontawesome-free --save

次に、これを Laravel Mix で Laravel から使えるように設定していきます。まず、resources/js/bootstrap.js に以下の内容を追記します。

window._ = require('lodash')
try {
  window.Popper = require('popper.js').default
  window.$ = window.jQuery = require('jquery')

  // 以下を追記
  require('bootstrap')
  require('bootstrap-fileinput')
  require('bootstrap-fileinput/themes/fas/theme.min')
  require('bootstrap-fileinput/js/locales/ja')
} catch (e) {}

bootstrap-fileinput/themes/fas/theme.min が Font Awesome 5 用のテーマ、bootstrap-fileinput/js/locales/ja は日本語の言語設定です。

次に、resources/sass/app.scss を編集します。

@import '~bootstrap/scss/bootstrap';
@import '~bootstrap-fileinput/scss/fileinput';

@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';

ここで割とハマっていたのですが、@import '~@fortawesome/fontawesome-free/scss/fontawesome'; だけでは Font Awesome 5 は有効になりません。fontawesome.scss を見てみるとわかるのですが、fontawesome.scss(とそこから import される sass)には、@font-facefont-family の設定が入っていないのです。bootstrap-fileinput/themes/fas/theme.min では、fas クラスを使っているので、~@fortawesome/fontawesome-free/scss/solid をあわせてインポートする必要があります。

その後、以下を実行してアセットのコンパイルを行います。

npm run production

Laravel Mix を利用した Font Awesome 5 のインストールについて検索していると、webpack.mix.js

.copy(
        'node_modules/@fortawesome/fontawesome-free/webfonts',
        'public/webfonts'
    )

を追加するように書かれているものが割と見つかりますが、追記しなくても Laravel Mix がコンパイル時にファイルのコピーもしてくれるので、必要ありません。

あとは、Blade の中でこんな感じで使います。

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Bootstrap File Input のテスト</title>

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

  <!-- Styles -->
  <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
</head>
<body>
<form method="POST" action="{{ route('user.update', [$user->id]) }}" enctype="multipart/form-data">
  @method('PUT')
  @csrf
  <div class="form-group row">
    <label for="images" class="col-md-3 col-form-label text-md-right">画像</label>
    <div class="col-md-7">
      <div class="custom-file">
        <input type="file" class="custom-file-input" id="images" name="images[]" multiple>
        <label class="custom-file-label" for="images">ファイルを選択してください(複数可)</label>
      </div>
      <input id="images" name="images[]" type="file" class="file" multiple
             data-show-upload="false" data-show-caption="true" data-msg-placeholder="ファイルを選択してください(複数可)"
             data-browse-on-zone-click="true">
    </div>
  </div>
</form>

<script type="module">
  $('#images').fileinput({
    theme: 'fas',
    language: 'ja',
  })
</script>
</body>
</html>

設定できるオプションは Bootstrap File Input のサイトを確認してほしいのですが、もう一つハマったのは、<script type="module"> の部分。<script> のままだと、ReferenceError: $ is not defined のエラーが出て動きません。

原因は、<script src="{{ mix('/js/app.js') }}" defer> の部分で、defer の指定がされているため。<script> のままだと、jQuery が読み込まれる前にインラインスクリプトが実行されてしまうのです。

このあたりについては、インラインscript(ララジャパン)で詳しく説明されているので、そちらをご覧ください。

この記事を書いた人

グッドネイバー

“ Webに悩むお客さまの「よき隣人」でありたい ” をモットーに、Web システム開発(主に Laravel)、Web マーケティング支援の仕事をしています。詳しい業務内容はこちら。お仕事のご依頼・ご相談はこちらからお気軽にどうぞ。