Laravel-mixを使ってみる

# 今までの認識と運用方法
なんかLaravel-mixというものがあるらしい。それはwebpackのラッパーらしい。webpackは複数のJavaScriptやCSSをいい感じにまとめるやつらしい。BabelがあるのでES2015の記法を使っても、ポンコツIEでも解釈できるようにトランスパイルしてくれる。

webpack……？　なにそれ？　依存関係……？？　今までみたいに`<script>`タグ連発してたらあかんのか……。どうやら調べてみると、生のJavaScriptを書くのではなく、"未来の"JavaScriptを書いて、それをwebpackとやらを通して、トランスパイルしてそれをブラウザに読み込ませるというのが今どきのやり方らしい。

今までは見様見真似でnpmを使ってインストールしたライブラリから、cssとjsファイルをぶっこ抜いて、`public/css`や`public/js`に配置してそれを`asset()`で読むという力技運用していました。でもなんかそれすごく恥ずかしいことしているような気がする……。

というわけで、意を決してlaravel-mixとやらを使ってみることにしました。筆者はwebpackとかフロントサイドに明るくないので、変なこと書いているかもしれません。

# 目標
webpackが一ミリも分からない状態で、laravel-mixを使ってjQueryとBootstrapとjQueryとBootstrapに依存するライブラリDatatablesを入れる

# プロジェクト作成
```
laravel new laravel-mix
```

# ビュー作成
まあ適当に。
resources/views/test.blade.php

```html
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
    <div class="alert-primary" id="element">あらーと</div>
    <table class="table-striped datatable">
        <tr>
            <td>ほげ</td>
            <td>1234</td>
        </tr>
        <tr>
            <td>ふが</td>
            <td>5678</td>
        </tr>
        <tr>
            <td>ぴよ</td>
            <td>7890</td>
        </tr>
        <tr>
            <td>ふー</td>
            <td>111</td>
        </tr>
        <tr>
            <td>ばー</td>
            <td>222</td>
        </tr>
    </table>
</body>
</html>
```

# ルーティング設定
routes/web.php

```php
Route::get('test', function () {
    return view('test');
});
```

# laravel-mixを使う
npmが使える環境にはしておいてください。

以下のコマンドを叩きます。

```
npm install
```

結構時間がかかります。なんか`node_modules`というフォルダができて大量のライブラリ群がインストールされているのが分かります。

# ライブラリのインストール
```
npm i jquery
npm i bootstrap
npm i datatables.net-bs
```
地味に罠なのが、datatablesにはノーマル版、bootstrap版などがあり、`npm i datatables`だけではうまくいかなかったです（思っていたのと違うやつが入る）。

なんか`node_modules`フォルダに上記のライブラリがインストールされていることが分かると思います。

# resourcesファイルの編集
## JavaScript
resources/js/app.js

```
require('./bootstrap');
require('jquery');
require('datatables.net-bs4')
```
Laravelのバージョンにもよるかもしれませんが、bootstrap.jsは初めから入っていました。

ここに`require('使いたいライブラリ名')`を追記します。

## CSS
resources/sass/app.scss

```
@import '~bootstrap/scss/bootstrap.scss';
@import '~datatables.net-bs4/css/dataTables.bootstrap.css';
```

スタイルを読み込ませたいCSSを`@import '~node_modules内のCSSへのパス'`の形式で追記します。~はnode_modulesフォルダって意味らしいです。

# コンパイルのための準備
jQueryはグローバル変数に`$`を置き、どこからでもガンガン使え、拡張もできるという性格のライブラリです。グローバルにガンガン変数を置いていこうぜという思想は、webpackとは相性が悪いみたいです。しかし、そんなことを言ったってjQueryに依存する大概のライブラリは、グローバルに`$`があることが前提のライブラリのため、何も設定をしないとうまく動きません。

そこで以下のように`webpack.mix.js`に追記します。これでjQueryは今までと同じように使うことができます。
webpack.mix.js

```js

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css')
    .autoload({
        jquery: ['$', 'window.jQuery']
    });
```

ちなみにjQueryをnpmでローカルに落としてから読み込むのでなく、CDNなど外部にある場合は以下のように書いてください。

webpack.mix.js

```js
mix.webpackConfig({
    externals: {
        "jquery": "jQuery"
    }
});
```

# いよいよコンパイル
以下のコマンドを叩きます。

```
npm run dev
```
すると、さまざまなライブラリが`public/js/app.js`と`public/css/app.css`にまとめられます。

# コンパイルされたファイル読み込む
ビューの`<head>`タグ内などに以下のように、`asset()`ヘルパー関数を使って、`public/js`と`public/css`に出力されたファイルを読み込みます。

resources/views/test.blade.php

```html
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<script src="{{ asset('js/app.js') }}"></script>
```

ブラウザからアクセスすると、ちゃんとあのBootstrap色になっているのが分かると思います。またデベロッパーツールで`$`を確認すると、`undefined`になっておらず、きちんとjQueryが読み込まれていることが分かると思います。

# 自作のJavaScript
JavaScriptを書いてみましょう。

resources/js/myscript.js

```js
const myFunc = () => alert('Hi!');

$(function () {
    $('.datatable').datatable();
    $('#element').on('click', function () {
        myFunc();
    })
})
```

これを`app.js`に読み込ませます。

resources/js/app.js

```js
require('./myscript');
```

`./`で同じフォルダ内というのを意味するみたいです。

再度`npm run dev`コマンドを叩きます。ちなみに、`npm run watch`コマンドを叩いてそのまま置いておくと、自動的にresourcesフォルダ内の変更を監視してコンパイルしてくれます。

ブラウザからアクセスすると、DataTableが適用され、elementをクリックするちゃんとアラートが出るのが確認できると思います。

さらに、コンパイルされたapp.jsを確認してみると……、
public/js/app.js

```js
/* WEBPACK VAR INJECTION */(function($) {var myFunc = function myFunc() {
  return alert('Hi!');
};
```

どこでも`$`が使えるようにinjectionされ、かつさっき書いたアロー関数がポンコツIEでも解釈できる`funtion`に書き換わっているのが分かると思います！

ちなみにwebpackを使うと、JavaScriptでglobalな変数は作れません。なので、HTMLの`<script>`内でその変数を参照しようとするとundefinedになります。明示的にglobalな変数を作りたければ`window.myGlobal = myGlobal;`とでも書くといいと思います。

# 自作のスタイルシート
最後にCSSも書きましょう。

resources/sass/mystyle.css

```css
#element{
    width: 50%;
}
```

resources/sass/app.scss

```scss
@import './mystyle';
```

あとは同様。`npm run dev`してください。