2016/12/13更新

[フロントエンド] ビルドツールのWebpackに入門する

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
最近はWebpackというフロントエンドのビルドツールを使う機会が増えてきて、やっとしっくり来る感じで理解できました。今回はWebpackについて、どのプロジェクトでも使う基本的なことを纏めてみたいと思います。

画像

目次




Webpackとは

Webpackとはフロントエンドにおけるビルドツールの1つです。フロントエンドのビルドツールでは他にGulpGruntがありますが、それらの仲間といった感じです。Webpackは主にJavaScript用のビルドツールです。CSSもJSに埋め込む事もできますが、仕事ではCSSはgulpなどで別にコンパイルすることが多いです(高速化の観点からCSSとJSは別にした方が良いことが多い)。

Webpackの要点をまとめてみると、
  • 主にJavaScriptをビルドするために使う
  • entryでコンパイル元を指定して、outputで出力先を指定する
  • Loaderという仕組みがあり、それでES6やReactをコンパイルできる
  • Pluginという仕組みがあり、それでUglifyなど圧縮処理などができる
  • WebpackDevServerという便利な開発ツールがある(次回以降のブログで扱いたい)
  • 大規模プロジェクトだとちょっと動作が重たい場合がある(→キャッシュオプションを活用する)
といった感じでしょうか。
それではWebpackの使い方を見ていきたいと思います。



Webpackを使う準備

Webpackを使うためには、いくつかの準備が必要です。

Webpackライブラリの入手

まず始めに、npmを用いてwebpackをインストールします。プロジェクトにpackage.jsonがない場合には、事前にnpm initコマンドで作成しておきましょう(依存モジュールの管理やスクリプトの起動に用います)。

package.jsonがある状態で、以下のコマンドでwebpackをインストールします。
$ npm install --save-dev webpack
-gオプションを付けてグローバルにインストールすることもできますが、Node界隈は(Ruby界隈も)1年も経つと使えなくなるモジュールも多いので、ローカルインストールすることをお勧めします。

また、webpackを動かすためにはwebpack.config.jsというファイルが必要です。空で良いので作成しておきます。
$ touch webpack.config.js
また、webpackを起動するためにpackage.jsonscriptsに起動処理を記述しておきます。
// package.json
/*...省略...*/
"scripts": {
  "build": "webpack"
}
/*...省略...*/
これで以下のコマンドで実行できるかを確認します。
$ npm run build
とりあえずなんか動けばOKです。現時点だとwebpack.config.jsの中身が空っぽなのでエラーになります。



最小構成でWebpackを動かしてみる

Webpackが難しいなーと感じたポイントして、色々と設定できる項目が多いというところでした。参戦したプロジェクトで使われているWebpackの設定ファイルをみると、もうチンプンカンプンでした(笑)。ということで、ここでは最小構成で動くものを作ってみたいと思います。
まずはコンパイル対象の以下のファイルを作成します。
// main.js
console.log('ハロー from main.js');
そしてこれをWebpackで読み込み、main.bundle.jsという名前で出力する設定をwebpack.config.jsに記載します。
// webpack.config.js
module.exports = {
    entry : './main.js',
    output : {
        filename : 'main.bundle.js'
    }
};
最も基本的なことは上記の設定です。「entryから読み込んでoutputへ出力する」がWebpackの基本的な流れです(それ以外は全てオプション項目)。これについてビルドを実行してみましょう。
$ npm run build

> 009-webpack@1.0.0 build /Users/munesadayohei/git/frontend-playground/009-webpack
> webpack

Hash: 9ba27b3a2407ff10054b
Version: webpack 1.13.3
Time: 47ms
         Asset     Size  Chunks             Chunk Names
main.bundle.js  1.43 kB       0  [emitted]  main
   [0] ./main.js 43 bytes {0} [built]
実行された結果ちゃんとmain.bundle.jsが生成されたことがわかります。今時点での過程では何もコンパイルしていないのでWebpackする意味はありませんが、ただこれが基本的な動きとなります。



LoaderとPluginについて

Webpackが便利と言われる所以はローダー(Loader)とプラグイン(Plugin)で、これらを用いることで様々なコンパイルを行うことができます。Webpackの処理の流れとしては、
  1. entryに指定されたファイルを読み込む
  2. 読み込む際にLoaderを通して変換する(例:BabelLoaderでES6をES5に変換する)
  3. 処理の前後でプラグインが実行される(実行タイミングなどはプラグインごとに違う)
  4. output先にビルド結果を出力する

つまり、entry〜outputまでの間に色々と処理を行うための仕組みとして、LoaderとPluginが用意されています。具体的にはそれぞれを以降の章で見てみたいと思います。



Loaderを使う

Webpackで最も重要な機能がLoaderです。Loaderを用いて様々なコンパイルを行うことができます。
例えば以下のようなECMAScript6で書かれたReactのコードがあったとします。
// react-app.js
import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
    render() {
        return <div>Hello</div>
    }
}
ReactDOM.render(<App/>, document.getElementById('app'));
このコードをブラウザで表示できるようにするためには、「ES6→ES5への変換」と「Reactコードの変換」の2つを行う必要があります。それをwebpackのloaderという仕組みを用いて行うことができます。
今回はローダーにbabel-loaderを利用します。必要なモジュールをインストールします。
# Reactをインストール
$ npm install --save react react-dom
# Babel-Loaderをインストール
$ npm install --save-dev babel-loader babel-core babel-preset-es2015 babel-preset-react
そしてWebpackを以下のように記述します。
// webpack.config.js
module.exports = {
    entry : './react-app.js',
    output : {
        filename : 'react-app.bundle.js'
    },
    module : {
        loaders : [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                  presets: ['react', 'es2015']
                }
            }
        ]        
    }
};
ここでのポイントはmodule > loadersの箇所で、ここでbabel-loaderを指定しています。このローダーを通してコンパイルが行われるのです。Webpackには様々なLoaderが用意されていて、JSONファイルを読み込んだり、Coffeeスクリプトをコンパイルするなど、色々とコンパイルを行うことができます。

ローダーについての更なる情報は以下を参照ください。

https://webpack.github.io/docs/loaders.html



Pluginを使う

プラグイン機能を用いることで、Webpackに様々な機能を追加することができます。例えばUglify.jsを適用する場合には以下のように記述します。
// webpack.config.js
let webpack = require('webpack');
module.exports = {
    entry : './main.js',
    output : {
        filename : 'main.bundle.js'
    },
    plugins : [
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        })
    ]
};
他にも、webpack-livereload-pluginを使ったりしています。この辺は色々と便利なものを集めて知見を貯められたらなーと思っています。

プラグインについての詳細は以下をご参照ください。

https://webpack.github.io/docs/using-plugins.html



ソースマップを表示する

Webpackを用いることで簡単にソースマップも作成することができます。SourceMapを用いることで、React→ES5へ変換されたコードについて不具合があった場合に、ブラウザのDevツールで変換前のReactコードで不具合箇所を確認することができます。Webpackでソースマップを出力するにはdevtoolを設定します。
// webpack.config.js
module.exports = {
    entry : './react-app.js',
    output : {
        filename : 'react-app.bundle.js'
    },
    module : {
        loaders : [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                  presets: ['react', 'es2015']
                }
            }
        ]        
    },
    //***************
    // devtoolで'source-map'を指定する
    //***************
    devtool : 'source-map'
};
そうすると以下のようにソースマップも作成されるようになります。
$ npm run build

> my-webpack@1.0.0 build /Users/munesadayohei//my-webpack
> webpack

Hash: 9ba27b3a2407ff10054b
Version: webpack 1.13.3
Time: 102ms
                  Asset    Size  Chunks             Chunk Names
    react-app.bundle.js  744 kB       0  [emitted]  main
react-app.bundle.js.map  863 kB       0  [emitted]  main
    + 178 hidden modules
あとはmain.bundle.jsと同じディレクトリにソースマップも置いておけば自動的にブラウザが読み取ってくれます。
ソースマップにはsource-map以外にも設定可能な項目があります。詳細は下記リンクをご参照ください。

https://webpack.github.io/docs/configuration.html#devtool



watchモードでキャッシュを活用する

Webpackは以下のように用いることで、watchモードで開発することができ、ソースコードを変更して保存すると自動的にビルド処理が行われます。
// package.json
/*省略*/
"scripts": {
  "watch": "webpack --watch"
},
/*省略*/
$ npm run watch
上記の場合に自動的にcacheモードが有効になり、2回目以降のビルド処理が高速化されます。ここで注意したいところは(担当プロジェクトで初期に陥った問題ですが)、Webpackをgulpなどから起動している場合には(gulpのwatchを使っている場合には)、このcacheオプションが有効にならないということです。そうするとビルドが非常に遅くなり開発が非効率になってしまうので注意が必要です。担当プロジェクトでは当初、ソースを変更するたびに1分間くらいWebpackのビルドが行われ、非常に開発スピードが遅くなっていました(笑)。

キャッシュに関する本家の説明はこちらです。
https://webpack.github.io/docs/configuration.html#cache



その他に

本家のチュートリアルページもすごくわかりやすいので、合わせてご覧ください。
https://webpack.github.io/docs/tutorials/getting-started/



最後に

Webpackは仕事でもプライベートでもよく使っているので、どのプロジェクトでも使う基本的なことをブログに書きたいと思って今回は書きました。まだまだいっぱい書きたいことがあるのですが、このブログだと長くなりすぎるので別にしたいと思います。

最後になりますが本ブログでは、フロントエンド・Python・Linux・開発関連・Swift・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSTwitterをフォローして頂けると幸いです ^ ^。

最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

[取り組み] フロントエンドでコーディングスピードをアップさせる6つの方法!と思って書いてたら30個も書いちゃった。
[フロントエンド] フロントエンドの入社試験99問!難しいですよ〜w。
[フロントエンド] Webページを表示するテストの際に、通信速度を3Gに制限して表示してみよう
[フロントエンド] スマホ実機でのデバッグ手段を増やす!Macのプロキシを利用して、通信内容を確認する。
[フロントエンド] Chrome 35 Beta の変更点。Touch制御、新しいJavaScript機能、プレフィックスなしのShadowDOM
[フロントエンド]複数アカウントでのテストには、Chromeのユーザー管理を使って、Cookieを切り替えると便利
[フロントエンド] Chrome36βが出た。変更点など。element.animate、HTML Imports、Object.observe、他。
RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。