タスクランナーを使わずに webpack だけでフロントエンド開発する方法

注意:この記事では Babel 5 を使っています。 Babel 6 を使用する場合は、このままだと動作しません。対応方法は、Quick guide: how to update Babel 5.x -> 6.x — Medium 等を参照して下さい。

GruntGulp などのタスクランナーを使わず、webpack だけでフロントエンドを開発する方法を調べてみました。

以下、実際に簡単なウェブアプリケーションを作ってみます。

環境

前提条件

  • JavaScriptは ECMAScript 6 で書けるようにします。但し、今回の記事内では ECMAScript 5の文法のみ使用しています。
  • CSSファイルは webpackで処理することにより、JavaScript のコードで表現されるようになります。これは webpackが生成する JavaScriptファイル内にまとめて出力されます。
    • Sassを使いたい場合は、sass-loader を使って下さい。
    • CSSファイルとして出力したい場合は、SEPARATE CSS BUNDLE にやり方が書いてあります。(今回の場合はそのまま公開ディレクトリに置けばよいのですが、Sassとか使う場合は参考になると思います)
  • 今回、画像ファイルは webpack で扱いません(そもそも今回は画像を使っていません)。
  • mochachai で単体テストしてみます。

今回のディレクトリ構成

project/
    ├─ public/
    │   ├─ js/
    │   │   ├─ app.js ・・・ webpackが出力するファイル
    │   │   └─ app.js.map ・・・ webpackが出力するファイル(ソースマップ)
    │   └─ index.html
    ├─ src/
    │   ├─ css/
    │   │   └─ entry.css ・・・ スタイルシートを書きます
    │   └─ js/
    │       ├─ entry.js ・・・ JavaScriptのエントリポイントです
    │       └─ foo.js ・・・ entry.jsから呼ばれます
    └─ test/
        ├─ entry.js ・・・ テストのエントリポイントです
        └─ foo.js ・・・ 上の test.js から呼ばれます

開発の流れ

1. プロジェクト用ディレクトリを作成

$ mkdir -p project/src/{css,js}
$ mkdir -p project/public/js
$ cd project

2. npm を使う準備

  • 以下のコマンドを実行して package.json を作成します。
$ npm init
  • いくつか質問されますが、Enterを押していけばよいです。

3. webpackと関連パッケージのインストール

$ npm install --global webpack webpack-dev-server
$ npm install --save-dev webpack style-loader css-loader eslint-loader babel-loader mocha mocha-loader chai
  • スタイルシートを webpack で扱うために、style-loadercss-loader をインストールします。
  • JavaScriptのコードをチェックするために eslint-loader をインストールします。
  • ECMAScript 6 で JavaScriptを書けるように babel-loader をインストールします。
  • テストで必要な mocha, mocha-loader, chai をインストールします。
  • 開発用ウェブサーバー且つファイル変更監視且つコンパイルを行うツールとして webpack-dev-server を使うのでインストールします。このツールはテストでも使います。

4. ESLint の設定ファイルを作成

  • ルートディレクトリ直下に .eslintrc ファイルを作成します。
$ vi .eslintrc
  • 以下の内容を記述します(あくまで例です)。
{
    "env": {
        "browser": true,
        "node": true,
        "es6": true
    },
    "ecmaFeatures": {
        "modules": true
    },
    "extends": "eslint:recommended",
    "rules": {
        "strict": [2, "function"],
        "no-undef": 2,
        "no-console": 0,
        "arrow-parens": [2, "always"]
    }
}

5. webpackの設定ファイルを作成

  • ルートディレクトリ直下に webpack.config.js ファイルを作成します。
$ vi webpack.config.js
  • 以下の内容を記述します。
module.exports = {
  // webpackが読み込むファイルを指定します。
  entry: {
    // 下の output.filename で使用されている[name]には、"app" がセットされます。
    app: "./src/js/entry.js"
  },
  output: {
    path: './public/js',
    // publicPath は webpack-dev-server で自動コンパイルするために必要(URLにおけるJSファイルへのパスを書く)
    publicPath: '/js/',
    filename: "[name].js"
  },
  module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "eslint-loader"
      }
    ],
    loaders: [
      {
        test: /\.css$/,
        loader: "style!css"
      },
      {
         test: /\.jsx?$/,
         exclude: /(node_modules|bower_components)/,
         loader: 'babel-loader'
      }
    ]
  },
  resolve: {
    // require()する時に拡張子を省略可能にします。
    extensions: ['', '.js', '.css']
  },
  eslint: {
    configFile: './.eslintrc'
  }
};
  • loader で指定する文字列は、末尾の “-loader” を省略することができます。

    You may reference loaders by its full (actual) name (e.g. json-loader), or by its shorthand name (e.g. json).

6. webpack-dev-server で開発用ウェブサーバーの起動 + ファイルの変更を監視 + 自動コンパイル

  • webpack-dev-server を起動した時にエラーが出ないように、先に public/index.html と src/js/entry.js ファイルだけ作成しておきます。

src/js/entry.js を作成します。

$ touch src/js/entry.js
  • この時点では、entry.js の中身は空で構いません。

index.html を作成します。

$ vi public/index.html
  • 以下を記述します。
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <script type="text/javascript" src="js/app.js" charset="utf-8"></script>
</body>
</html>

webpack-dev-server を起動します。

  • 開発用ウェブサーバーを稼働させると同時に、ファイルを監視させて変化があれば自動的に webpack がコンパイルするようにします。
    • 今回の場合、src/js/entry.js が読み込まれ、public/js/app.js が生成されます(CSSファイルの内容もJavaScriptになってまとめられます)。
  • 別のターミナルを開いてプロジェクトのディレクトリに移動し、以下のコマンドを実行します。
$ webpack-dev-server --content-base public/ -d
  • ブラウザで localhost:8080/webpack-dev-server/ にアクセスすると、開発中のページにアクセスすることができます。
    • ファイルが変更されると自動でリロードしてくれるようです。(ただ、–hot オプションも指定していませんし、webpack dev server に書いてあることと違うような気もします。。。)
    • ブラウザで localhost:8080 にアクセスすることもできます(こちらの場合、ファイルを変更しても自動でリロードしてくれません)。
    • 参照:webpack dev server
  • -d オプションを指定することにより、ソースマップを出力してくれます。
    • 今回の場合 public/js/app.js.map というファイルも出力されるようになり、ブラウザの開発者ツールで元のファイルの内容を見ることができます(Chromeの場合、「Sources」のところを見ると「webpack://」というドメイン項目が追加され、ここから見れます)。
  • (注意) このように webpack-dev-server を使う場合、コンパイルされた結果は全てメモリ上で生成されて使用されます。ですので、実際にコンパイル結果のファイルを生成したい場合は、webpackコマンドを使う必要があります(以下の補足を参照)。

補足

  • 単独で webpack コマンドを使ってコンパイルする場合は、以下を実行します。
$ webpack -d
  • webpack-dev-server を使わず、代わりに http-server などのウェブサーバーを使う場合は、webpack コマンドに –watch オプションを指定すればよいでしょう。そうすれば、ファイルを監視してくれて変化があれば webpack が自動でコンパイルしてくれます。
  • この場合、webpack.config.js 内の output.publicPath の設定はいらなくなります(他で必要になるようなことをしていなかったらですが)。
$ webpack -d --watch

7. テストファイルの変更を監視 + テスト自動実行(on ブラウザ)

  • この後のコマンドでエラーにならないよう、先に test/entry.js ファイルだけ作成しておきます。
$ touch test/entry.js
  • テストファイル(test/entry.js)を監視して、変化があれば自動的に テストが実行されるようにします。
  • 別のターミナルを開いてプロジェクトのディレクトリに移動し、以下のコマンドを実行します。
$ webpack-dev-server 'mocha!./test/entry.js' --port 8081 --output-file test.js
  • ブラウザで localhost:8081/webpack-dev-server/js/test にアクセスするとテストが実行されます。
    • このURL末尾の “js/test” というパスは、webpack.config.js 内で指定した output.publicPath のパス文字列 に、–output-file test.js というオプションで指定したファイル名から拡張子部分を除いた文字列を加えたものになるようです。(output.publicPath の値は、–output-public-pathオプションで上書きできます)
    • test/entry.js ファイルやそこから読み込んでいるファイルの内容が変更されると、その結果が即座に反映されます。
  • このコマンドにより、test/entry.js は webpack でコンパイルされ、更にそれを読み込む HTMLファイルも内部で自動生成されて、ブラウザでアクセスできるようにしてくれます。
  • 手順6 で実行した webpack-dev-server とポート番号が被らないように、別のポート番号を明示的に指定しています。
  • 手順6 と合わせて webpack-dev-server を2つ起動していることになります。1つで済む方法があればよいのですが、分かりませんでした。

8. 開発を行う

  • 各ファイルの内容を変更して保存する度に webpack が public/js/app.js ファイルを更新してくれます。

CSSファイルを作成します。

$ vi src/css/entry.css
  • 以下を記述します。
body {
    background-color: green;
}

src/foo.js を作成します。

$ vi src/js/foo.js
  • 以下を記述します。
module.exports = {
  hello: function() {
    return 'Hello!';
  }
};

test/foo.js を作成します。

$ vi test/foo.js
  • 以下を記述します。
/*global describe*/
/*global it*/
var expect = require('chai').expect,
    foo = require('../src/js/foo');

describe('foo module', function(){
  it ('should get right value', function() {
    expect(foo.hello()).to.equal('Hello!');
  });
});

test/entry.js を作成します。

$ vi test/entry.js
  • 以下を記述します。
require('./foo');
  • ブラウザで localhost:8081 にアクセスすると、テストの結果が確認できます。

src/entry.js を編集して完成させます。

$ vi src/js/entry.js
  • 以下を記述します。
// CSSファイルを取り込む
require('../css/entry');

// foo.jsを利用する
var foo = require('./foo');
console.log( foo.hello() );

9. プロダクション用のファイルを出力する

  • 開発が終了したら、手順6 で実行していた webpack-dev-server コマンドを終了させ、プロダクション用の public/js/app.js を出力させます。(もちろんテストのために動かしていた webpack-dev-server コマンドも終了させて構いません)
  • 以下のコマンドを実行します。
$ webpack -p
  • -p オプションを指定することで、ミニファイされた public/js/app.js が出力されます。
    • 但し、「*!」でコメントされている部分は削除されないので、ライセンス関連のコメントはだいたい残るようになっています。
    • 内部で webpack.optimize.UglifyJsPlugin が使用されます。

今回は以上になります。webpackに頼りすぎることに不安を感じないわけではありませんが、その代わりシンプルな構成で開発できるので良い方法だと思いました。

今回作成したファイルは、レポジトリにして GitHubに置いてあります。

その他

複数の出力ファイルがある場合に、共通処理を1ファイルにまとめる

必要な時に必要なコードを読み込んで実行させる(非同期ローディング)

  • petehunt/webpack-howtoの「9. Async loading」に載っています。
  • 例えば、setTimeout() の中で require() するコードを書けば、その require した先のコードは勝手に非同期読み込みしてくれるようになり、その時読み込むJSファイルもwebpackが出力してくれます。なのでこの追加で出力してくれたファイルもウェブサーバーにアップロードする必要があります。(これ、かなりすごい機能なのではないでしょうか?)
  • この場合、設定ファイルで output.publicPath を設定する必要があります。
    • この設定値には、ドキュメントルートから見た JavaScriptファイルの置いてあるディレクトリまでのパスを記述します。
    • 参照:output.publicPath – configuration

参照

最終更新日: 2015-08-26

Pocket

2 thoughts on “タスクランナーを使わずに webpack だけでフロントエンド開発する方法

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*