はじめに
この記事はLaravel Mix
初導入に挑戦した際、勉強したことをまとめたものです。
webpackやNode.jsに関する知識などが少ないひよっ子ですので、間違いなどありましたらご教示頂けるとうれしいです
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
の中身を覗いてみると、、
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
に追加しておきます。
Laravelをインストールした場合、このスクリプトはあらかじめ記述された状態になっています。今回はLaravel Mix単体でインストールしているので手動でスクリプトを追加します。
"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
をインストールします。
yarn add cross-env --dev
// npmの場合
npm i cross-env -D
ワイルドカードを使えるようにする
PugやSassファイルのコンパイル時に、『ファイル名が_
から始まるものは全て除外する』といった条件を付けたいので、それができるようにglob
をインストールします。
デフォルトだとワイルドカードは使えません。
yarn add glob --dev
const mix = require('laravel-mix');
const glob = require('glob'); // <- 追加する。
publicpathの設定
Laravel Mix単体使用の場合、mix.setPublicPath()
で公開用ディレクトリを指定する必要があります。
これを忘れると上手くビルド出来ません…!
今回の場合だとdistディレクトリがこれにあたりますので設定します。
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の設定をします。
mix
.setPublicPath(distDir)
.browserSync({
files: 'dist/**/*',
server: 'dist/',
proxy: false
})
3-3. JavaScript(ES5へのコンパイル、バンドル、IE11対応)
今回はIE11対応にしたいのでpolyfillをインストールします。
$ yarn add laravel-mix-polyfill --dev
インストール出来たら、設定を書いていきます。
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
// 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()
で指定してあげます。
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を使えるようにするためにインストールします。
$ yarn add laravel-mix-pug --dev
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()
で設定できます。
mix
.setPublicPath(distDir)
.browserSync({
files: 'dist/**/*',
server: 'dist/',
proxy: false
})
.disableSuccessNotifications() // <- エラー時のみデスクトップ通知を表示
.pug = require('laravel-mix-pug');
3-7. 完成!
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()
});
一通りの設定ができました!早速ビルドしてみます。
$ yarn dev
# ファイル変更監視する場合は
$ yarn watch
この時に必要なモジュールがあれば自動でインストールされ、もう一回runするように言われるので、
その場合は再度yarn dev(watch)
すればOKです
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()
});
これでコンパイルしようとすると…
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. おわりに
つまづいたポイントもありましたが、初心者の私でも無事に環境構築することができました!
今後も分かったことなどあったら更新していきます。