16
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

はじめてのLaravel Mix

Last updated at Posted at 2019-10-11

はじめに

この記事はLaravel Mix初導入に挑戦した際、勉強したことをまとめたものです。
webpackやNode.jsに関する知識などが少ないひよっ子ですので、間違いなどありましたらご教示頂けるとうれしいです:bow:

1. Laravel Mixとは

SassやES6のコンパイルなどが簡単にできる便利なビルドツール。
webpackのラッパーAPI。(="webpackを操作しやすくしたもの"というイメージ

Laravel Mixという名前から勘違いしてましたが、Laravel無しでも使えるんですね。
↓こちらでの説明がとてもわかりやすかったです。
初めてのLaravel Mix | アールエフェクト

2. やりたいこと

  • Sassのコンパイル
  • Pugの導入、コンパイル
  • ES6+からES5へのコンパイル、バンドル、IE11対応
  • ファイル変更を監視してブラウザをオートリロード

3. いざ導入

開発環境

  • Mac OS Mojave 10.14.6
  • Node.js 10.16.3
  • npm 6.9.0

ディレクトリ構造
以下のように、コンパイル前のファイル(src)とコンパイル後のファイル(dist)に分けていきます。

project root
├── dist
└── src

3-1. Laravel Mixのインストール

今回はyarnを使ってインストールしました。

// プロジェクトのルートディレクトリで
$ yarn
$ yarn add laravel-mix --dev

// npmの場合
$ npm init -y
$ npm i laravel-mix -D

インストールできたら、laravel-mixの設定ファイルの雛形をプロジェクトのルート直下にコピーしてきます。

$ cp node_modules/laravel-mix/setup/webpack.mix.js ./

 
webpack.mix.jsの中身を覗いてみると、、

webpack.mix.js
let mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for your application, as well as bundling up your JS files.
 |
 */

mix.js('src/app.js', 'dist/').sass('src/app.scss', 'dist/');

// Full API
// mix.js(src, output);
// mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation.
// mix.preact(src, output); <-- Identical to mix.js(), but registers Preact compilation.
// mix.coffee(src, output); <-- Identical to mix.js(), but registers CoffeeScript compilation.
// mix.ts(src, output); <-- TypeScript support. Requires tsconfig.json to exist in the same folder as webpack.mix.js
// mix.extract(vendorLibs);
// mix.sass(src, output);
// ~以下省略~

チュートリアル的にシンプルな設定がされている状態です。
この設定ファイルをカスタマイズしていきます。

3-2. 基本設定

NPM Scriptの追加

まずはNPM scriptをpackage.jsonに追加しておきます。
:bulb: Laravelをインストールした場合、このスクリプトはあらかじめ記述された状態になっています。今回はLaravel Mix単体でインストールしているので手動でスクリプトを追加します。

package.json
"scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "npm run development -- --watch",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
}

上記スクリプトでは様々な環境に対応できるようcross-envを利用しているそうなので、cross-envをインストールします。

terminal
yarn add cross-env --dev

// npmの場合
npm i cross-env -D

ワイルドカードを使えるようにする

PugやSassファイルのコンパイル時に、『ファイル名が_から始まるものは全て除外する』といった条件を付けたいので、それができるようにglobをインストールします。
:warning: デフォルトだとワイルドカードは使えません。

terminal
yarn add glob --dev
webpack.mix.js
const mix = require('laravel-mix');
const glob = require('glob'); // <- 追加する。

publicpathの設定

Laravel Mix単体使用の場合、mix.setPublicPath()で公開用ディレクトリを指定する必要があります。
:warning: これを忘れると上手くビルド出来ません…!
今回の場合だとdistディレクトリがこれにあたりますので設定します。

webpack.mix.js
const mix = require('laravel-mix');
const glob = require('glob');

const srcDir = './src';
const distDir = './dist';
const paths = {
  html: {
    src: `${srcDir}/templates/`,
    dist: `${distDir}/`,
  },
  css: {
    src: `${srcDir}/styles/`,
    dist: `${distDir}/styles/`,
  },
  js: {
    src: `${srcDir}/scripts/`,
    dist: `${distDir}/scripts/`,
  },
};

mix
  .setPublicPath(distDir) // <- Laravel Mix単体で使用する場合必要。

3-3. BrowserSync(ファイル変更監視+ブラウザオートリロード)

ファイルの変更を監視してブラウザを更新してくれるBrowsesrSyncの設定をします。

webpack.mix.js
mix
  .setPublicPath(distDir)
  .browserSync({
    files: 'dist/**/*',
    server: 'dist/',
    proxy: false
  })

3-3. JavaScript(ES5へのコンパイル、バンドル、IE11対応)

今回はIE11対応にしたいのでpolyfillをインストールします。

terminal
$ yarn add laravel-mix-polyfill --dev

インストール出来たら、設定を書いていきます。

webpack.mix.js
require('laravel-mix-polyfill');

glob.sync(`${paths.js.src}*.js`).map(file => {
  mix.js(file, `${paths.js.dist}bundle.js`)
    .polyfill({
      enabled: true,
      useBuiltIns: "usage",
      targets: {
        "firefox": "50",
        "ie": 11
      }
    })
    .sourceMaps();
});

src/scpripts内の全てのJSファイルをbundle.jsとしてまとめて、dist/scriptsへ吐き出すようになっています。

3-4. Sass

webpack.mix.js
// Sassの設定
glob.sync(`${paths.css.src}*.scss`, {ignore: `${paths.css.src}_*.scss`}).map((file) => {
  mix
    .sass(file, paths.css.dist, {})
    .sourceMaps()
});

頭に_が付くscssファイルはコンパイルしないようにしています。
Laravel Mixでは、特に何も指定せずともデフォルトでautoprefixerが機能してくれます。
細かい設定が必要な場合はoptions()で指定してあげます。

webpack.mix.js
glob.sync(`${paths.css.src}*.scss`, {ignore: `${paths.css.src}_*.scss`}).map((file) => {
  mix
    .sass(file, paths.css.dist, {})
    // 細かい設定をしたい場合
    .options({
      autoprefixer: {
        options: {
          browsers: [
            'last 6 versions',
          ]
        }
      }
    })
    .sourceMaps()
});

参考:https://laravel-mix.com/docs/5.0/css-preprocessors#postcss-plugins

3-5. Pug

まずはPugを使えるようにするためにインストールします。

terminal
$ yarn add laravel-mix-pug --dev
webpack.mix.js
mix
  .setPublicPath(distDir)
  .browserSync({
    files: 'dist/**/*',
    server: 'dist/',
    proxy: false
  })
  .pug = require('laravel-mix-pug'); // <- 読み込みを追加

// 以下Pugの設定
glob.sync(`${paths.html.src}*.pug`, {ignore: `${paths.html.src}_*.pug`}).map((file) => {
  mix.pug(file, path.relative(paths.html.src, paths.html.dist), {
    pug: {
      pretty: true
    }
  })
  .sourceMaps()
});

scssファイル同様、_から始まるpugファイルはコンパイルしないようにしています。

3-6. おまけ

ビルドやコンパイルエラー発生時にだけデスクトップ通知を有効にする

mix.disableSuccessNotifications()で設定できます。

webpack.mix.js
mix
  .setPublicPath(distDir)
  .browserSync({
    files: 'dist/**/*',
    server: 'dist/',
    proxy: false
  })
  .disableSuccessNotifications() // <- エラー時のみデスクトップ通知を表示
  .pug = require('laravel-mix-pug');

3-7. 完成!

webpack.mix.js
const mix = require('laravel-mix');
const glob = require('glob');
require('laravel-mix-polyfill');

// paths
const srcDir = './src';
const distDir = './dist';
const paths = {
  html: {
    src: `${srcDir}/templates/`,
    dist: `${distDir}/`,
  },
  css: {
    src: `${srcDir}/styles/`,
    dist: `${distDir}/styles/`,
  },
  js: {
    src: `${srcDir}/scripts/`,
    dist: `${distDir}/scripts/`,
  },
};

mix
  .setPublicPath(distDir)
  .browserSync({
    files: 'dist/**/*',
    server: 'dist/',
    proxy: false
  })
  .disableSuccessNotifications()
  .pug = require('laravel-mix-pug');

// JS
glob.sync(`${paths.js.src}*.js`).map(file => {
  mix.js(file, `${paths.js.dist}bundle.js`)
    .polyfill({
      enabled: true,
      useBuiltIns: "usage",
      targets: {
        "firefox": "50",
        "ie": 11
      }
    })
    .sourceMaps();
});

// Sass
glob.sync(`${paths.css.src}*.scss`, {ignore: `${paths.css.src}_*.scss`}).map((file) => {
  mix.sass(file, paths.css.dist, {})
  .sourceMaps();
});

// Pug
glob.sync(`${paths.html.src}*.pug`, {ignore: `${paths.html.src}_*.pug`}).map((file) => {
  mix.pug(file, path.relative(paths.html.src, paths.html.dist), {
    pug: {
      pretty: true
    }
  })
  .sourceMaps()
});

一通りの設定ができました!早速ビルドしてみます。

terminal
$ yarn dev

# ファイル変更監視する場合は
$ yarn watch

この時に必要なモジュールがあれば自動でインストールされ、もう一回runするように言われるので、
その場合は再度yarn dev(watch)すればOKです:thumbsup:

4. つまづいたこと

pugファイルの出力先がおかしい

なぜかpugファイルの出力先はwebpack.mix.jsファイルからの相対ではなく、ソースとなるpugファイルからの相対パスになっているようで、何も考えずmix.sassやmix.jsと同じノリで設定するとエラーになります。

ダメな例
const srcDir = './src';
const distDir = './dist';
const paths = {
  html: {
    src: `${srcDir}/templates/`,
    dist: `${distDir}/`,
  },
  css: {
    src: `${srcDir}/styles/`,
    dist: `${distDir}/styles/`,
  },
  js: {
    src: `${srcDir}/scripts/`,
    dist: `${distDir}/scripts/`,
  },
};

glob.sync(`${paths.html.src}*.pug`, {ignore: `${paths.html.src}_*.pug`}).map((file) => {
  // これだとエラーになる
  mix.pug(file, paths.html.dist, {})
  .sourceMaps()
});

これでコンパイルしようとすると…

terminal
Pug Compilation Failed!

Error: ENOENT: no such file or directory, open 'project/src/templates/dist/index.html'

project/distに出力したいのに、project/src/templates/distなんて無いよと怒られてしまいます。

出力先を../../${paths.html.dist}に変えればいいのですが、もう少しスマートに対処したい!と思い調べたところ、Githubのissuesでpath.relative()を使う方法で無事に解決できました。

成功例
glob.sync(`${paths.html.src}*.pug`, {ignore: `${paths.html.src}_*.pug`}).map((file) => {
  mix.pug(file, path.relative(paths.html.src, paths.html.dist), {})
  .sourceMaps()
});

参考:https://github.com/matejsvajger/laravel-mix-pug/issues/7#issuecomment-401573734

5. 課題・疑問

  • setPublicPath()の役割がいまいち理解できていない。mix-manifest.jsonは何のためのファイルなのか?
  • develop環境時のみにソースマップを表示するように設定を変えてみる。
  • JSについてはほとんど検証できていないので、別途babelの設定が必要かもしれない。

6. おわりに

つまづいたポイントもありましたが、初心者の私でも無事に環境構築することができました!
今後も分かったことなどあったら更新していきます。

公式ドキュメント

16
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?