はじめに
フロントでTypeScriptやSass、テンプレートエンジンなどをコンパイルするときgulpやwebpackがよく使われます。
個人的な印象ですが、両者とも記述が複雑化しやすく長文化しやすく管理が大変そうです。
loaderの順番を気にしたり設定オプションも盛りだくさんで、時間をかけて理解しないといけないので積極的に進めたくはありません。
そこでおすすめしたいのがlaravel-mixです。
ざっくり言うとlaravel-mixはwebpackを簡単に書けるようにしたものです。
webpackを使いやすくしてくれるので当然webpackのバンドルやコンパイルなどの機能を持っています。
その名の通り「Laravel」使うんじゃないの?と思われるかもしれませんが、Laravelを使わなくてもlaravel-mixは使えます!
Laravel知らないよって人でも大丈夫です。
本記事ではlaravel-mixを使ってTypeScriptとSassをコンパイルするような環境を作っていきます。
環境を作ろう
準備
まずは練習用のディレクトリを作ってlaravel-mixのファイルを編集できるところまでやってみます。
mix-practice
というディレクトリを作ってnpm init -y
でpackage.josn
ファイルを作成します。
mkdir mix-practice
cd mix-practice
npm init -y
これでlaravel-mixをインストールできるようになりました。
いざインストール!
npm install laravel-mix --save-dev
インストールは開発環境だけでよいので--save-dev
をお忘れなく。
インストールできたらlaravel-mixを記述するファイルを作ります。
webpackのファイル名がwebpack.config.js
であるように
laravel-mixのファイル名はwebpack.mix.js
です。
touch webpack.mix.js
ではこのファイルの先頭で先ほどインストールしたlaravel-mixを読み込ませておきます。
const mix = require('laravel-mix');
ここまででディレクトリ構成はこうなってます。
mix-practice
├─ node_modules/
├─ package-lock.json
├─ package.json
└─ webpack.mix.js
laravel-mix編集(TypeScript)
次は実際にlaravel-mixの記述をしてみてwebpackとの違いを体験してみましょう。
ではwebpack.mix.jsに書いていきましょう。
まずはTypeScriptです。
const mix = require('laravel-mix');
mix.setPublicPath('dist');
mix.ts('src/ts/index.ts', 'dist/js');
とりあえずこれだけです。一瞬すぎる…
.setPublicPath()
でコンパイル先(公開するディレクトリ)を指定します。
.ts()
の第一引数にはコンパイル元を指定します。
バンドルしたいときは配列で指定します。
mix.ts(['src/ts/index.ts', 'src/ts/sample.ts'], 'dist/js')
第二引数には出力先を指定します。
src/ts/index.ts
をコンパイルしてdist/js
に出力しなさいということですね。
それではwebpack.mix.js
を実行させるためにpackage.json
のscripts
を書き換えましょう。
"scripts": {
"build": "mix",
"watch": "mix watch",
"production": "mix --production"
},
これでひとまずTypeScriptをコンパイルできるところまできましたが
肝心のtypescriptやts-loaderをインストールしてません。
手動で
npm install typescript ts-loader --save-dev
としてもいいのですがlaravel-mixに任せるとwebpack.mix.js
の内容読んで依存解決して自動にインストールまでしてくれます。
ということで先のスクリプトを実行してみます。
npm run build
実行後に以下のように出力されて
Additional dependencies must be installed. This will only take a moment.
Running: npm install ts-loader typescript --save-dev --legacy-peer-deps
Finished. Please run Mix again.
package.json
にts-loaderとtypescriptが追加されています。
ちなみにここでPlease run Mix again.
の指示通りもう一回npm run build
としてもsrc/ts/index.ts
がないのでエラーになります。
それではtsconfig.json
とindex.ts
を作りましょう。
まずtsconfig.json
を作成します。
tsc --init
tsconfig.json
の設定は触り始めたらキリがない(嘘、勉強不足で把握しきれてない)ので設定しておけば良さげなところだけをピックアップしておきます。
{
"compilerOptions": {
"target": "es2015",
"lib": ["DOM", "ESNext"],
"module": "ES2015",
"sourceMap": true,
"strict": true,
}
}
次にコンパイル元のディレクトリsrc/ts/
とファイルindex.ts
を作成します。
mix-practice
├─ node_modules/
├─ src
│ └─ ts
│ └─ index.ts
├─ package-lock.json
├─ package.json
└─ webpack.mix.js
const greet = (text: string) => {
console.log(text);
}
greet('hello, world');
それではコンパイルしてみます。
npm run build
下記が表示されれば成功です。
webpack compiled successfully
dist/js/index.js
ができていることを確認しましょう。
mix-practice
├─ dist
│ ├─ js
│ │ └─ index.js
│ └─ mix-manifest.json
├─ node_modules/
├─ src
│ └─ ts
│ └─ index.ts
├─ package-lock.json
├─ package.json
└─ webpack.mix.js
laravel-mix編集(Sass)
次はSassです。
これも一瞬です。
const mix = require('laravel-mix');
mix.setPublicPath('dist');
mix.ts('src/ts/index.ts', 'dist/js');
mix.sass('src/scss/style.scss', 'dist/css/style.css')
.options({
processCssUrls: false
});
options({processCssUrls: false})
はcssで使うbackground-image: url()
などのurl()
に関する設定です。
scssのコンパイル元と出力先は別の場所です。
そのため以下のようなディレクトリ構成で
root
├─ dist
│ └─ css
│ └─ style.css
└─ src
├─ img
│ └─ sample.png
└─ scss
└─ style.scss
scssディレクトリからの相対パス記述で
background-image: url('../img/sample.png');
のようにしてしまうとコンパイル後に
background-image: url('../images/sample.png?3a0834378861f9a4523f166fed2c0be9');
のように書き変わってしまい画像をうまく読み込めません。
そこでprocessCssUrls: false
にしておくとurl()
の中身はscssに記述したままでコンパイルされます。
そのため画像はdist/img
の方にコピーするようにしましょう。
手動でコピーするのは面倒なのでこれもlaravel-mixにやってもらいます。
const mix = require('laravel-mix');
mix.setPublicPath('dist');
mix.ts('src/ts/index.ts', 'dist/js');
mix.sass('src/scss/style.scss', 'dist/css/style.css')
.options({
processCssUrls: false
});
mix.copy('src/img', 'dist/img');
これでimgディレクトリごとdistにコピーしてくれます。
あとは適当にscssファイルと画像ファイルを用意します。
h1 {
color: red;
&.color-blue {
color: blue;
}
}
div {
width: 100%;
height: 250px;
background-image: url('../img/sample.png');
}
mix-practice
├─ dist
│ ├─ js
│ │ └─ index.js
│ └─ mix-manifest.json
├─ node_modules/
├─ src
│ ├─ img
│ │ └─ sample.png
│ ├─ scss
│ │ └─ style.scss
│ └─ ts
│ └─ index.ts
├─ package-lock.json
├─ package.json
└─ webpack.mix.js
これでbuildしてみましょう。
npm run build
最初はTypeScriptの時と同じように(未インストールの場合)sassとsass-loaderがインストールされます。
必要なパッケージが揃えばbuildができます。
コンパイルが成功すれば以下のようなディレクトリ構成になります。
mix-practice
├─ dist
│ ├─ css
│ │ └─ style.css
│ ├─ img
│ │ └─ sample.png
│ ├─ js
│ │ └─ index.js
│ └─ mix-manifest.json
├─ node_modules/
├─ src
│ ├─ img
│ │ └─ sample.png
│ ├─ scss
│ │ └─ style.scss
│ └─ ts
│ └─ index.ts
├─ package-lock.json
├─ package.json
└─ webpack.mix.js
確認のためにdist直下にindex.html
を入れます。
確認だけなので最低限だけ書いてます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css">
<title>Document</title>
</head>
<body>
<h1>赤です</h1>
<h1 class="color-blue">青です</h1>
<div></div>
<script src="js/index.js"></script>
</body>
</html>
ブラウザで確認して下記OKなら完了です!お疲れ様です!
- 「赤です」が赤
- 「青です」が青
- 画像が表示
- デベロッパーツールのコンソールに「hello, world」が表示
mix-manifest.jsonについて
いつの間にかしれっとmix-manifest.json
というファイルが出力されています。
これはファイルを変更してもキャッシュが効いてしまって反映されないというのを防ぐキャッシュ回避用のファイルです。
Laravelを使うとscriptファイル呼び出し時のmix()
関数でクエリパラメータを生成してキャッシュ回避してくれるようですが
今回のようにLaravelを使わない環境だとあまり意味がない(mix-manifest.json
内のファイルにクエリパラメータを追加するプログラムを作るなどしないと)ので出力自体をさせないか、gitignoreなどで対処するのがよいでしょう。
ちなみに私は出力させないように以下のような設定をしています。
const fs = require('fs');
mix.then(() => {
fs.unlinkSync('dist/mix-manifest.json')
});
さいごに
larave-mixだと簡単に書けそうな感じがしたでしょうか?
今回はwebpack.mix.js
の中で記述を分けて書きましたがメソッドチェーンにして一気に書くこともできます。
const mix = require('laravel-mix');
const fs = require('fs');
mix.setPublicPath('dist')
.ts('src/ts/index.ts', 'dist/js')
.sass('src/scss/style.scss', 'dist/css/style.css')
.options({
processCssUrls: false
})
.copy('src/img', 'dist/img');
mix.then(() => {
fs.unlinkSync('dist/mix-manifest.json')
});
laravel-mixでは他にもVueやReactなどといったフロントフレームワーク、ライブラリの他、EJSやNunjucksなどのテンプレートエンジン、ファイルの変更を監視してブラウザをホットリロードする機能(BrowserSync)、sourceMapなど色々追加できます。
これで面倒なwebpackやgulpから解放されましょう。
参照