最近、Gulpが4.xにバージョンアップしましたね。そのタイミングで開発環境でもGulpをアップデートしてエラーに困っている声を聞いたりします。
僕自身もGulpを使っている環境で4.xにアップデートして、それまで使っていたライブラリからエラーが出て四苦八苦しました。その時、ふと思ったんです。「Gulpに依存してるなー」と。そして、「だったらnpm-scriptの方がいいかも」と思い、npm-scriptで開発環境を作る流れを書いてみようと思います。
今回作成したコードなどのソースはGitHubに掲載してあります。最下部にリンクが置いてあるので、お急ぎの方はそちらを参照してみてください。
タスクの流れ
- Sassの処理
- node-sassでコンパイル
- プリフィックス付与と圧縮処理
- ディレクトリを削除して新しくディレクトリを作る
- Sassの処理をまとめて一連のタスクを流して処理
- JavaScriptの処理
- バンドルする
- 圧縮する
- 一連のタスクを流して処理
- 画像の処理
- 画像圧縮の処理
- 画像圧縮の一連の流れのタスクを作る
- ファイルを監視する
- ブラウザシンクでサーバーを立ち上げる
- SCSS、JS、imagesを監視する
- HTMLの監視
- EJSの監視
- 常時監視用タスクを作る
このような流れで開発環境(タスクランナー)を作っていこうと思います。不要な部分は飛ばして読んでもらっても大丈夫だと思いますので、よしなに参照してください。
ディレクトリ構造
今回は静的ウェブサイトの構築を想定して開発環境を作ってみます。ディレクトリ構造は以下を想定して書いていますので、よしなに噛み砕いて活用してみてください。
package.json
-- dist
index.html
-- assets
-- css
-- js
-- images
-- src
-- assets
-- sass
style.scss
-- js
index.js
-- images
image.jpg
image.gif
image.png
image.svg
-- html
index.html
postcss.config.js
imagemin.js
rollup.config.js
下準備
npm-scriptを使うためには下準備が少し必要です。node.jsは入れておいてくださいね。プロジェクトのルートにターミナルで移動して、
$ npm init
を実行してください。そして、必要な情報を入力してください。そうすると、package.json
というファイルが自動的に作られると思うので、あとは以下を読み進めて色々と試して見てください。
Sassの処理
まずはSassの処理部分を作っていきましょう。
node-sassでscssファイルをコンパイル
scssファイルをコンパイルする処理を作ります。ここではnode-sass
を使います。
$ npm install node-sass --save-dev
これでnode-sass
のパッケージがインストールされます。
scripts
は以下のように書きます。
"css/sass": "node-sass src/assets/sass/style.scss -o dist/css --output-style expanded --source-map dist/assets/css"
-o | 出力するディレクトリを指定 |
–output-style | 書き出した後のスタイルを指定(nested | expanded | compact | compressed) |
–source-map | SourceMapの書き出し先ディレクトリを指定 |
これで完了です。試しにsrc/sass
内にstyle.scss
を作ってから、
$ npm run css/sass
これを実行するとdist/css
内にstyle.css
とstyle.css.map
が作られていることが確認できるはずです。
以下、コマンドの打ち方(ここで言う $npm run css/sass )は省略します。適時読み替えてください。
ベンダープレフィックス付与と圧縮処理
コンパイルしたCSSに対して、ベンダープレフィックスを自動的に付けさせ、その後CSSを圧縮させます。
ベンダープレフィックスを付与するためにautoprefixer
を、cssを圧縮するためにcssnano
を使います。そして、それらをPostCSSで処理するのでpostcss-cli
も入れます。
$ npm install postcss-cli cssnano autoprefixer --dave-dev
scripts
には以下のように書きます。
"css/postcss": "postcss dist/assets/css/style.css -o dist/assets/css/style.min.css"
そして、このスクリプトを実行すると、
You did not set any plugins, parser, or stringifier. Right now, PostCSS does nothing. Pick plugins for your case on https://www.postcss.parts/ and use them in postcss.config.js.
このようにエラーが出ます。postcss.config.js
を用意しなさい、というようなことですね。ですので、ルートに用意します。中身はこんな感じです。
module.exports = {
plugins: [
require('autoprefixer')({
browsers: ['last 2 versions'],
cascade: false
}),
require('cssnano')({
preset: 'default',
})
]
}
ベンダープレフィックスの付与だけの場合
cssの圧縮を行わない(必要としない)場合もあると思いますので、こちらのケースだけの場合を書いておきますね。
postcss-cli
とsutoprefixer
をインストールします。
$ npm install postcss-cli autoprefixer --save-dev
scripts
にはこう書きます。
"css/postcss/autoprefix": "postcss dist/assets/css/style.css -o dist/assets/css/style.css -c=postcss.config.js"
そして、postcss.config.js
には、
module.exports = {
plugins: [
require('autoprefixer')({
browsers: ['last 2 versions'],
cascade: true
})
]
}
というような感じで書いておきます。cascade
というのは、出力値を整列させるかどうか、という指定です。
body {
// cascade: false の場合
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
// cascade: true の場合
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
先ほどの流れでcascade: true
と記述していますが、デフォルトではcascade: true
なので、特に記述する必要はありません。
ディレクトリを削除して新しくディレクトリを作る
どんどん処理を重ねていくと、不要なファイルが存在するようになったりして、手動で対応しなくてはならなくなったりと面倒です。
ですので、毎回コンパイル〜ベンダープレフィックス付与〜圧縮を行う前にdist/css
ディレクトリを削除して、新たにdist/css
ディレクトリを作成するという処理を行います。
trash
を使ってディレクトリを削除することもできるのですが、こちらはディレクトリが存在しない場合などにエラーで処理が止まってしまうので微妙な感じです。ですので、ここではrimraf
を利用します。
こちらを使う際には特に何かしらインストールする必要はありません。
scripts
に以下の処理を加えます。
"clean/css": "rimraf dist/css && mkdir -p dist/css"
今後、他のディレクトリなどのcleanタスクを書くのでcssのディレクトリを削除・新規作成するタスクはこのように書きました。他にもjs、imagesなどでも同様の処理を行いますので覚えておきましょう。
スクリプトを実行すると、テストで書き出したdist/css
内のデータが消えていることが確認できます。これは、い一度dist/css
を削除して再度dist/css
を作成しているので、見た目では中のデータが消えたというように見えるということです。
Sassの処理をまとめて一連のタスクを流して処理
ここまで作ったタスクをまとめて1つのスクリプトで実行できるようにします。この考え方はnpm-scriptを利用して開発環境を作る上ではベースとなる考え方・作り方なのでよく覚えておきましょう。
流れとしては、
- ディレクトリをクリーンにする
- scssファイルをコンパイル
- ベンダープレフィックスを付与
- 圧縮
となります。
タスクを流れで処理するためにnpm-run-all
を利用します。
$ npm install npm-run-all --save-dev
スクリプトはこのように書きます。
"css": "npm run clean/css && npm-run-all -p css/*"
npm-run-all
にはこのようなオプションがあります。
-p | 並行処理 |
-s | 順次処理 |
ここでは、コンパイルしてからプリフィックス付与、圧縮と順次処理してほしいのでこのように設定しています。順次というのは、package.json
のscript
に書いてある順に、という意味です。
JavaScriptの処理
ここからはJavaScriptの処理について書いていきます。といっても、特に難しいことをするつもりはなく(あまり僕の環境でそこまで必要じゃないので)、ただバンドルして圧縮するだけです。
バンドルする
まずは複数あるjsファイルを1つのファイルにまとめます。ここではrollup
を利用します。
$ npm install rollup --save-dev
あと、付随するrollup
のプラグインも入れておきましょう。
$ npm install rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-babel --save-dev
そして、大元の@babel/core
も入れないとエラーが出ます。あと、@babel/preset-env
も。
$ npm install @babel/core @babel/preset-env --save-dev
そして、ルートにrollup.config.js
を用意して以下のように書いてみます。
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
export default {
output: {
format: 'iife',
dir: 'dist/assets/js'
},
plugins: [
resolve({ jsnext: true }),
commonjs(),
babel({
presets: [
[
"@babel/preset-env", {
"modules": false,
"targets": {
"browsers": ['last 2 versions']
}
}
]
],
babelrc: false
})
],
experimentalCodeSplitting: true
};
output:
の部分でformat
とdir
を設定しています。
format | 書き出すフォーマットを設定(amd, cjs, esm, iife, umd ) |
dir | 書き出し先を設定 |
詳しくはこちらを見てみるとオプションとか書いてあるのでわかりやすいです。
圧縮する
バンドルしたJavaScriptを圧縮します。ここではuglify-js
を利用します。
$ npm install uglify-js --save-dev
スクリプトにはこのように記述しています。
"js/uglifyjs": "uglifyjs dir/assets/js/index.js -o dir/assets/js/index.min.js"
一連のタスクを流して処理
JavaScriptに関する一連のタスクを流して処理を作ります。詳しくは上記のCSS部分を参照してください。ここでは同じような処理なので詳しい説明は割愛します。
まず、CSSの時と同じようにdist
ディレクトリを綺麗にして作り直すタスクを作ります。
"clean/js": "rimraf dist/assets/js && mkdir -p dist/assets/js"
そして、JavaScriptのバンドル→圧縮の処理をディレクトリを綺麗にした後に動作させます。
"js": "npm run clean/js && npm-run-all -s js/*"
画像の処理
画像の処理といってもそれほどやることは多くありません。画像の容量を最適化してdist
ディレクトリにコピーするくらいです。
画像圧縮の処理
ここでがちょっと多めのパッケージを使います。
imagemin | 画像を圧縮するパッケージの親玉みたいもの |
imagemin-keep-folder | ディレクトリ構造を保ったままにする |
imagemin-mozjpeg | JPEGの圧縮用 |
imagemin-pngquant | PNGの圧縮用 |
imagemin-gifsicle | GIFの圧縮用 |
imagemin-svgo | SVGの圧縮用 |
全て一緒にインストールしてあげましょう。
$ npm install imagemin imagemin-keep-folder imagemin-mozjpeg imagemin-pngquant imagemin-gifsicle imagemin-svgo --save-dev
そして、ルートにimagemin.js
という設定用ファイルを用意して、そちらをnodeで実行する形でタスクを実行します。imagemin.js
の記述はこのような感じです。
const imagemin = require('imagemin-keep-folder');
const imageminMozjpeg = require('imagemin-mozjpeg');
const imageminPngquant = require('imagemin-pngquant');
const imageminGifsicle = require('imagemin-gifsicle');
const imageminSvgo = require('imagemin-svgo');
imagemin(['src/assets/images/**/*.{jpg,png,gif,svg}'], {
plugins: [
imageminMozjpeg({ quality: 80 }),
imageminPngquant({ quality: '65-80' }),
imageminGifsicle(),
imageminSvgo()
],
replaceOutputDir: output => {
return output.replace(/images\//, '../../dist/assets/images/')
}
}).then(() => {
console.log('Images optimized');
});
スクリプトの方にはこのようなタスクを記述します。
"images/imagemin": "node imagemin.js"
これで圧縮させる部分の出来上がりです。
画像圧縮の一連の流れのタスクを作る
まずは恒例のディレクトリをクリーンにするタスクを作ります。
"clean/images": "rimraf dist/assets/images && midir -p dist/assets/images"
そして、画像圧縮のタスクをclean/images
のあとで処理させます。
"images": "npm run clean/images && npm-run-all -s images/*"
これで画像の圧縮から一連の流れが完成です。
ファイルを監視する
ここからは実際の開発を進めていく上で、効率よくコードがかけるようにするためのチップスになります。ファイルを監視するというタイトルになっていますが、読んで字のごとく、ファイルを更新したかどうかを常に監視する部分になります。
ブラウザシンクでサーバーを立ち上げる
まずはbrowser-sync
でサーバーを立ち上げます。まずはインストール。
$ npm install browser-sync --save-dev
そして、スクリプトには、
"watch/server": "browser-sync start -s dist -f 'src, **/*.html, !node_modules/**/*'"
ここでは、サーバーではdist
のデータを表示するようにしています。詳しくはこちらを読むと全てわかります。
SCSS、JS、imagesを監視する
ではまずSCSSファイルの監視から。watch
パッケージをインストールします。
$ npm install watch --save-dev
そして、SCSSファイルがあるsrc/assets/sass/
を監視させます。スクリプトにはこんな感じで書きました。
"watch/css": "watch 'npm run css' ./src/assets/sass"
./src/assets/sass
で変更があればnpm run css
を実行しろ、ということが書いてあります。
JavaScriptの監視もSCSSと同じ要領でOKです。
src/assets/js/
を監視させるので、
"watch/js": "watch 'npm run js' ./src/assets/js"
画像の監視にはonchange
を利用します。
$ npm install onchange --save-dev
そしてスクリプトには、
"watch/images": "onchange 'src/assets/images' -e '**/*.DS_Store' -- npm run images"
これで画像に変更を加えると、npm run images
が走るようになります。
HTMLの監視
おまけですが、テンプレートエンジンを使わずに直にHTMLファイルをsrc
ディレクトリ下で作成していく場合には、cpx
というパッケージを使って、dist
ディレクトリへコピーします。cpx
の良いところはディレクトリ構造を保持したままコピーしてくれるところです。
$ npm install cpx --save-dev
そして、スクリプトでこんな感じに書いています。
"html/plain": "cpx 'src/assets/html/**/*.html' 'dist/'",
"html": "npm-run-all html/*",
監視させる記述に関してはこのように書いてみました。
"watch/html": "watch 'npm run html' ./src/assets/html",
EJSの監視
EJSなどのテンプレートエンジンを使うこともあるかと思います(Jadeとかもやり方は同じような感じのはず)。ここではEJSのコンパイルを取り上げてみます。まずは、ejs-cli
パッケージをインストールします。
$ npm install ejs-cli --save-dev
スクリプトにはこのように書いてみました。
"html/ejscli": "ejs-cli --base-dir src/assets/ejs '**/*.ejs' --out dist"
これでsrc/assets/ejs
内の*.ejs
ファイルをコンパイルしてくれます。階層なども保持したままdist
に出力されます。
常時監視用タスクを作る
ここまで作ってきたタスクを1つにまとめて一括して実行できるようにすることでとても便利になります。
"watch": "npm-run-all -p watch/*"
こうすることで、開発を開始する際にはコマンドラインでnpm run watch
を打つだけで、サーバーが立ち上がり、プロジェクトのファイルを監視開始してくれます。
まとめ
このような流れで開発環境を作ることができます。最初は黒い画面に慣れていない方は、ちょっと腰が重くなってしまうかもしれませんが、失敗したら消しちゃえば良いんで安心してください。
GulpやGruntなどといったタスクランナーはnpmの上で動いています。ですので、大元のnpm scriptsで開発環境を作ることで、外枠(GulpやGruntなどのバージョンアップなど)の影響を受けにくいものを手に入れることができます。
どんどん失敗して、最適な開発環境を構築してみてください。
今日作ったものはこちらに置いておきますね。