初めてのWebpack
今回はWebpackについて紹介したいと思います。
私自身は今回初めて使ったのですが、小規模なプロジェクトの途中から導入していて、
使ってみて結構良い感じなので記事にしてみました。
Webpackとは
Node.jsでサーバーサイドで動かすモジュールバンドラーツールになります。
Node.jsでモジュールという単語を聞くと、「npmやbowerとかと何が違うの?」みたいな印象を持たれる方もいるかもしれませんが、基本的にはそれらとはまた違った役割をもっています。
npmやbowerはJSライブラリのバージョン管理などの目的としてよく利用されますが、WebpackはJSファイルのコーディングの部分で開発者の手助けをしてくれるのです。
Webpackの基本的な役割
5枚ほど図を書いてみましたので、画像とともに紹介していきます。
今回出てくるライブラリたちの紹介
今回使うライブラリは下記のような構成にしてみます。
・npm : Node.js側のライブラリ(開発ツール)の管理
・Bower : フロントエンド側のライブラリの管理
・Gulp : タスクランナー
・Webpack : モジュールバンドラー。フロントエンドのJSファイル生成。
※ Bowerとnpmでフロントエンド側と開発ツール側のソース管理を分けた理由については後述
各ライブラリの役割について
npm は Node.js側のライブラリの管理
npmはNode.js側のライブラリのインストールしたり、package.jsonファイルで
ライブラリのバージョンを指定して管理をすることが出来ます。
今回はWebpackの紹介なので特にnpmについては紹介しません。
Bower は フロントエンド側のライブラリの管理に特化
npmでも実はjQueryとかAngularとかは用意できます。
ただ今回は、フロントエンドのライブラリに特化したBowerを導入して、
フロントエンド側のライブラリとNode.js側のライブラリの管理を分けています。
またメリットはただ管理を分けるところだけではなく、Webpackでフロントエンドの
ライブラリだけ取り扱いたいときにBowerを指定するだけになり、かなり楽になるメリットが有ります。
だんだんとファイルが増えてきて、HTMLのheaderにCSSとJSの読み込みの記述も増えてきて、管理が大変になってきました。
ここでWebpackの登場ですが、WebpackもLessやSassのコンパイルツールみたいなものなので、Gulpによるタスクの管理をしたいと思います。
Gulp は 変換系の『タスク』を管理
GulpはLESSやSCSS、ReactのJSXなど、ES2015でかかれたJSなど変換する必要があるファイルを
どういう処理で変換し、変換したファイルをどこに出力するか『タスク』として管理してくれます。
今回は新たにWebpackでモジュール管理をするためのタスクをGulpで追加します。
Webpack は JS、CSSを一つのファイルにまとめ上げます
Webpackは自分で書いたJSとライブラリとして読み込んでいるJSを一つのJSファイルに
まとめてくれます。
また、JSライブラリで読み込む必要があるCSSファイルたちもJSにまとめてくれます。(私達が書くCSSもまとめることが可能です。)
そして、それらのCSSで読み込む画像ファイルもDataURI(Base64形式)に変換してJSファイルに
まとめてくれます。
つまり、JS、CSS、画像ファイルを一つのJSファイルにまとめてくれます。
※ ちょっと誤解を招きそうなのですが、ここで出てきている画像ファイルはWebpackで扱う主に『CSSで読み込まれる画像』を想定して書きました。また、DataURIにしているのはこちらがそうなるように設定している(npm の url-loaderを利用している)だけで、通常のファイル読み込みのままにすることも出来ます。
Webpack を使った実際のコーディングはどんな感じ?
『Webpack は JS、CSSを一つのファイルにまとめ上げます』というところにはもう一つ意味があって、
『JSファイルを細かく分けて管理することが可能になる』という意味にもなります。
webpackの基本的な使い方は以下のようになります。
var mymodule = require('./mymodule');
mymodule('こんにちは');
module.exports = function(str) {
alert(str);
};
ここでは単純に関数の例を出しましたが下記のように1クラスの1ファイルのような管理も可能です。
var roadedMymodule = require('./mymodule');
var Mymodule = new roadedMymodule();
Mymodule.myfunction('Qiitaさん');
function myclass() {
this.alertString = 'こんにちは ';
};
myclass.prototype.myfunction = function(name) {
alert(this.alertString + name);
};
module.exports = myclass;
※ ここででてくるrequire()関数はWebpackで変換され、webで読み込まれるJSの記述としては残らないので、
require()関数が定義されておらずエラーが発生するなんてことはありません。
基本的には1ファイル、1クラスの書き方になるのかなと思っています。(module.exportsとrequireの関係から)
また、コンパイル後のファイルを見ていただくとわかると思うのですが(ここでは紹介していません)、
変数をglobalとしてvar aaa = ... と定義しているものが基本的にglobal領域ではなくなったり…。
なので、既存のプロジェクトをこちらに移す場合はここで結構骨が折れそうです。
出力されるJSはどんな感じ?
実際に生成されるJSは下記のような内容になります。
・私が書いたJS
・利用しているJSライブラリ(Bower)
・JSライブラリで使用されているCSS(Bower)
・デザイナーさんが書いたLESS
・CSS類から利用されるImage(今回はDataURIへ変換)
が記述されており、それらが一つのファイルにまとまっています。
HTML側から呼ぶファイルも、もちろん1つだけ
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>サイトのタイトル</title>
<!-- metaタグの記述 中略 -->
<script src="./js/bundle.js"></script>
</head>
他のCSSやJSの読み込みの記述は一切いりません。bundle.jsにすべて記述されているからです。
どうでしょう。いわゆる今風な感じのヘッダーな感じがしますよね。
また静的のファイルでよく悩まされるのが『ブラウザキャシュで古い静的ファイルが読み込まれてしまう』問題かと思いますが、今回のような場合、生成されたbundle.jsを新しく読み込ませればすべての静的ファイルが更新できます。
<script src="./js/bundle.js?20160915000000"></script>
また、GulpでWebpackでファイル生成するときにHTMLの上記の記述のパラメータを更新するようにすれば、私達がわざわざGetパラメータの記述を書き換えて更新する必要もありません。
まとめ
Webpackはモジュールバンドラーであり、利用しているJSファイルを一つのJSファイルにまとめる事ができます。
JSだけでなく、CSSの管理もできて、それも同じようにJSファイルにまとめることができます。
(ただし、ファイルの読み込みの記述がJS側に移りますのでデザイナーさんが変更しづらくなる可能性もあるので、エンジニアとデザイナーの2人で仕事をしている場合には工夫する必要があるかと思います。最悪、WebpackにCSSを含めないことも選択可能です。)
既存のプロジェクトでRequire.jsなどを使っていない場合には移行は難しそうですが、利用できる環境であれば積極的に使っていきたいですね。