Webpack vol.1 とりあえず試してみる

/

導入

普段フロントエンドの開発ツールはタスクランナーのgulpを使っているのですが、webpackも結構良くて人気があるという話が聞こえて来ていたので前から気になってはいました。

本当に人気があるのか試しにGoogleトレンドで調べてみたところ、webpackは最近になるにつれてスコアを伸ばしてきておりgulp,gruntに肉薄しています(2016/12月現在)。
Google Trends [webpack, gulp, grunt]
Googleトレンドで調べただけではソフトウェアのシェアに関して正確な所はわからないですが、参考程度に考慮してみればwebpackは競争の激化するフロントエンド開発ツール戦国時代(?)の中でも特に勢いのある存在のようです。

そんなwebpackですがReactの開発環境としても推されているようで、CreatReactAppを触ったのきっかけに本格的に気になりだしたので今回基本的な使い方を試してみました。

webpack

webpackはキャッチコピーがModlue bundlerという事で静的サイトやWebAppに必要なjs,css,imgなどのリソースを最適化して一つ(もしくは複数)のファイルにまとめくれるツールです。

異なる形式のファイルを一本化する事によって実際にアップロードするファイルの構成をを非常にシンプルにする事が出来ます。

webpackのイメージ

https://webpack.js.org/
https://webpack.github.io/

Vesrion

webpackのバージョンは現在1.xと2.x系統がリリースされています。
当然新しいのは2.x系統なのですが、2.x系統の最新版は 2.2.0-rc.2 (rc = release candidate)という事でbetaではないようですがプレリリース版という事らしいので、今回は安定版である1.14.0を使用しました。

もし2.x系統を使いたい場合には、インストール時にwebpackの後ろに@[version]をつける事でバージョンを指定してダウンロードする事が出来ます。

$ npm install --save-dev webpack@[version]
$ npm install --save-dev webpack@2.1.0-beta.27

インストール

webpackはnpmを利用してインストールします。

$ npm install webpack --save-dev
$ webpack
webpack 1.13.3
...

USAGE – webpack

Build

エントリポイント

webpackを利用するためにはまずエントリポイントを作成します。
エントリポイントはwebpackの入り口となるJSファイルで、このファイルを起点にwebpackは各ファイルをモジュールとして読み込んでいきます。

具体的には例えば以下のようなスクリプトを書いたJSファイルを作成します。

var log = console.log('Hello webpack');
module.exports = log;
var log = console.log('Goodbye webpack');
module.exports = log;

次にこれ等のファイルをエントリポイントに追加してからwebpackコマンドを実行します。

require('./modules/script1.js');
require('./modules/script2.js');
# webpack [entry_file][outpt_file]
$ webpack entry.js bundle.js

ビルドが実行されると指定した名前でデプロイ用のJSファイルが作成されます。

ビルドされたJSファイル(bundle.js)にはエントリポイントを通じてscript1.jsとscript2.jsの2つのファイルが取り込まれているので、HTMLで読みこんでブラウザのコンソールから確認すると以下の文字が表示されます。

Hello webpack
Goodbye webpack
bundle.js
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
</body>
</html>

このようにwebpackを利用すると細かく分けられたファイルを最終的に一つのJSファイルにまとめる事が出来るので、Appのデプロイ時の姿を気にせずに純粋に開発の必要に合わせたディレクトリ構成で開発を進める事が出来ます。

webpackの設定

webpackでのビルドの際にファイル同士の関係が先程のように単純であればコマンドに引数を渡して実行する形でも問題ないですが、Appが大きくなりwebpackに実行させたい処理が増えていった場合には設定ファイルを利用したほうが便利です。

webpack.config.js

webapckの設定はwebpack.config.jsを作成しその中に記述していきます。
例えば以下のようにエントリポイントとビルド後のファイル名を指定しておけば、webpackと打つだけで自動的に設定を読み込んでビルドを実行してくれます。

module.exports = {
  entry: './entry.js',
  output: {
    path: __dirname,
    filename: 'bundle.js'
  }
};
# webpackだけでビルドが実行される
$ webpack

CONFIGURATION – webpack.github.io

外部ライブラリの取り込み

JavaScriptを用いた開発ではnpmを通じてライブラリを取り込むことが多いので、外部ライブラリを利用したJavaScriptのビルドも試してみます。
今回はページ内の移動をスクロールアニメーションで実行してくれるライブラリを追加してみました。

smoothscrool

smoothScroll – github

$ npm install --save smoothscroll

インストールしたライブラリを利用した新たなJSファイルを作成し、エントリポイントに追加します。

var smoothScroll = require('smoothscroll');
var scroolTop = document.getElementById('scrool_top');

var handleClick = function(event) {
  event.preventDefault();
  smoothScroll(0);
};

scroolTop.addEventListener('click', handleClick);
require('./modules/scroll.js');

スクリプトの実行をテストするためにHTMLも修正します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <h1>Webpack Index</h1>
  <button id="scrool_top" style="margin-top: 2000px">scroll</button>
  <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
</body>
</html>

再度webpackのビルドを実行し、ページ内のボタンをクリックすればページ先頭までのスクロールが実行されます。

JS以外のファイル

webpackではJavaScript以外にもWebAppに必要なCSSや画像などのリソースを全てモジュールとして扱いファイルにまとめて組み込む事が出来ます。

Loader

JavaScript以外のファイルを取り扱う場合にはそれぞれの形式に対応したloaderを追加します。
LOADER CONVENTIONS

css

JavaScript以外のファイルとしてCSSの読み込みを実行してみます。

CSSを扱うためにstyle-loadercss-loaderをインストールします。

それぞれの解説によればstyle-loaderはJavaScriptからStylesheetをrequireをするのに必要で、css-loaderは@importやurlでもStyleSheetを取り込む事が出来るようにしてれるようですが、webpackでCSSを扱う場合には両方を組み合わせて使うのが推奨されているので2つともインストールしておきます。

インストール

$ npm install style-loader css-loader --save-dev

loaderの設定

webpack.config.jsにCSS用のloaderの設定をします。

module: {
  loaders: [
    {
      test: /\.css$/,
      loader: 'style!css' 
    }
  ]
}

loaders:に設定した内容により、text:の正規表現とマッチするファイルにloader:で指定した各loaderが実行されます。
loader:に設定した各loaderは!によって区切られ、右側から順番に評価されていきます。
module.loader – webpack

この状態でHTMLに適用するCSSを作成し

'''
h1 {
  color: #2d2d2d;
  text-align: center;
}
<html>
...
  <body>
    <h1>Webpack Index</h1>
    ...
 <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
  </body>
</html>

エントリポイントから読み込んでビルド実行するとCSSを取り込んだbundle.jsが出力されます。

require('./modules/style.css');
$ webpack

ビルド後のファイルは一見CSSを読み込んでいるようには見えませんが、bunlde.jsにCSSの内容が組み込まれているためHTMLをブラウザから開くとCSSが適用されている事が確認出来ます。

CSSの取り込み

Image

次にwebackを通して画像を取り込んでみます。
画像を取り込むためのローダーはurl-loaderfile-loaderがあります。

$ npm install url-loader file-loader --save-dev

url-loader

url-loaderを利用して画像を取り込む場合には設定ファイル内でlimitを設定する事が可能で、画像のサイズが設定した上限未満であれば画像はdata-uriとして扱われ、上限を超える場合には通常のファイルとして取り扱われます。

#limitを設定することで容量の上限によって扱いが切り替わる
#8kb以下はdata-uriとして扱われる
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
body {
 /* limit未満 */
  background: url(
    data:image/png;base64,iVBORw0KGgoAAA( 中略 )TZ/MAAAAASUVORK5CYII=
  );

  /* limit以上 */
  /* プロジェクト内にファイルが配置される */
  background: url(891758bcfc117851b2888111279907f7.png);

  background-repeat: no-repeat;
}

file-loader

file-loaderを利用する場合には取り込まれた画像はファイルとして取り扱われますが、配置されるファイルのパスや名前を指定することが可能です。

webpack.config.js内でfile-loaderをloaderとして指定だけではファイルはハッシュ値を元にした前でプロジェクトのルートディレクトリに配置されますが、file-loaderのnameパラメーターにpathやファイル名を指定することで任意のパスとファイル名で配置する事が出来ます。

loaders: [
  //loaderの指定のみ
  { test: /\.(png|jpg)$/, loader: 'file-loader' }

  //pathやファイル名などを指定
 { test: /\.(png|jpg)$/, loader: 'file-loader?name=[path][name].[ext]' }
]
# { test: /\.(png|jpg)$/, loader: 'file-loader' }
app/891758bcfc117851b2888111279907f7.png

# { test: /\.(png|jpg)$/, loader: 'file-loader?name=[path][name].[ext]' }
app/modules/img.png

それぞれ挙動は違いますがloaderを設定する事でwebpackで画像の参照が出来るようになります。

body {
  background: url("./img.png");
  background-repeat: no-repeat;
}