webpack-dev-server

このサイトは作成途中のものを公開しています。 また、Webpackのバージョンが1.13.0の頃に作成されたものですが、2017年2月現在Webpackは1系を非推奨として2の使用を勧めています。

webpack-dev-serverは小さなnode.jsのExpressサーバーで、 webpack-dev-middlewareを使用してwebpackのバンドルを提供します。

これは小さなランタイムも持ち、Socket.IOを介してサーバーへ接続されます。 サーバーはイベントに反応して、クライアントへコンパイル状態についての情報を発行します。 これは必要に応じた異なるモードを選択することが可能です。

下記の設定ファイル(webpack.config.js)があるとしましょう。

var path = require("path");
module.exports = {
  entry: {
    app: ["./app/main.js"]
  },
  output: {
    path: path.resolve(__dirname, "build"),
    publicPath: "/assets/",
    filename: "bundle.js"
  }
};

appフォルダの中に初回のエントリポイントがあり、 webpackはbuildフォルダの中にbundle.jsファイルをバンドルします。

Content Base

webpack-dev-serverは、特定のContent Base(--content-base)を設定しない場合は、 現在のディレクトリ内のファイルをWebサーバーのファイルとして提供とします。

$ webpack-dev-server --content-base build/

上記のwebpack-dev-serverの設定を使用すると、buildフォルダの静的ファイルがWebサーバーのファイルとして提供されます。 これはソース・ファイルの変更の監視を行い、変更があればバンドルを再コンパイルします。

この再コンパイルされたバンドルは、publicPathで指定された相対パスのメモリーから提供され、 あなたが設定した出力先のディレクトリに書き込まれません。 同じURLのパスに既にバンドルが存在している場合、メモリ内のバンドルが優先されます。(デフォルト)

例えば上記の設定で、バンドルがlocalhost:8080/assets/bundle.jsで利用されているとします。

バンドルされたファイルを読み込むために、 静的ファイルをWebサーバーから提供する設定(--content-baseオプション)をしたbuildフォルダ内に、 index.htmlファイルを作成する必要があります。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script src="assets/bundle.js"></script>
</body>
</html>

デフォルトでは、localhost:8080/でアプリケーションが起動します。 上記の設定であれば、publicPathlocalhost:8080/assets/になります。

自動再読み込み

webpack-dev-serverはページの自動再読み込みに、複数のモードをサポートしています。

  • Iframeモード (ページはiframe内に埋め込まれる)
  • Inlineモード (変更によってページを再読み込みする小さなwebpack-dev-serverクライアントのエントリが、バンドルに追加される)

また、どちらのモードもHot Module Replacementをサポートし、これによりページ全体をリロードする代わりに、変更が発生したことがバンドルに伝えられます。 Hot Module Replacementのランタイムは更新されたモジュールを読み込み、実行中のアプリケーションに注入することがあるかもしれません。

Iframeモード

iframeモードを使用する場合、設定の追加は必要ありません。 単に、ブラウザでhttp://<host>:<port>/webpack-dev-server/<path>にアクセスするだけです。 上記の設定であれば、http://localhost:8080/webpack-dev-server/index.htmlになります。

  • 設定の変更が不要
  • アプリケーションの上部のバーに便利な情報が提供されます。
  • アプリケーションのURL変更がブラウザのURLバーに反映されません。

Inlineモード

Inlineモードを使用するには、コマンドライン上で--inlineを指定します。(設定で指定することは出来ません) URLの変更はありません。 http://<host>:<port>にアクセスするだけです。 例えば上記の設定であれば、http://localhost:8080/index.htmlになります。

  • コマンドラインのフラグが必要です。
  • ブラウザのログに、ステータス情報が提供されます。
  • アプリケーション内のURLの変更は、ブラウザのURLバーに反映されます。
node.jsのAPIを使用したインラインモード

webpack-dev-serverの設定にはinline: trueのフラグが存在しません。 これは、webpack-dev-serverのモジュールがwebpackの設定へのアクセスを持たないためです。 その代わりに、ユーザーはwebpack-dev-serverのクライアントのエントリーポイントを、設定に追加しなければなりません。

これを行うには、webpack-dev-server/client?http://<path>:<port>/</code>を(全ての)エントリーポイントへ追加します。 例えば、上記の設定の場合は、下記のようにします。

var config = require("./webpack.config.js");
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/");
var compiler = webpack(config);
var server = new WebpackDevServer(compiler, {...});
server.listen(8080);
HTMLでInlineモードを指定

また、webpack-dev-serverクライアント・スクリプトへの参照をHTMLページに追加するという選択肢もあります。

<script src="http://localhost:8080/webpack-dev-server.js"></script>

Hot Module Replacement

webpack-dev-serverで、Hot Module Replacementを有効にするには、コマンドライン上で--hotを指定します。 これはwebpackの設定に、HotModuleReplacementPluginを追加します。

webpack-dev-serverでHot Module Replacementを一番簡単に使う方法は、Inlineモードを使用することです。

CLI上のInlineモードでのHot Module Replacement

特別に何かを行う必要はありません。 --inline --hotは自動的に関する全ての作業を行います。 webpack-dev-serverのCLIは、自動的に特別なwebpack/hot/dev-serverエントリーポイントを、あなたの設定に追加します。

http://<host>:<port>/<path>にアクセスして、何が起こるのか確認してみましょう。 ブラウザのログで、下記のメッセージが確認できるはずです。

[HMR] Waiting for update signal from WDS...
[WDS] Hot Module Replacement enabled.

[HMR]が付くメッセージは、webpack/hot/dev-serverからのものです。 [WDS]が付くメッセージは、webpack-dev-serverクライアントからのものです。

正しくoutput.publicPathを指定することが重要になり、もし間違っているとHot Updateのチャンクの再読み込みが出来ません。

node.jsのAPIでのHot Module Replacement

Inlineモードと同じように、ユーザーはwebpackの設定を変更しなければいけません。 3箇所の変更が必要になります。

  • webpackの設定のエントリーポイントにwebpack/hot/dev-serverを追加。
  • webpackの設定にnew webpack.HotModuleReplacementPlugin()を追加。
  • webpack-dev-serverの設定に、サーバーでHMRを有効にするために、hot: trueを追加。

例えば、上記の設定であれば次のようになります。

var config = require("./webpack.config.js");
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server");
var compiler = webpack(config);
var server = new webpackDevServer(compiler, {
  hot: true
  ...
});
server.listen(8080);

"safe write"をサポートしているエディタ/IDEで使用する際の注意

多くのエディタは、開発サーバーがファイルを正しく監視することが出来なくなる"safe write"機能をサポートしており、 デフォルトでこれが有効になっています。 "safe write"は、元のファイルに変更が直接書き込まれない代わりに一時ファイルに書き込まれ、 保存処理が完全に成功した際に元のファイル名にリネームされ置き換えられます。

この挙動は、元のファイルが削除されてしまうため、ファイル監視がファイル見失うという事態を招きます。 この問題を避けるためには、エディタの"safe write"機能を無効にする必要があります。

  • vimの設定 - :set backupcopy=yes (参考: ドキュメント)
  • IntelliJ - Settings -> System Settings -> Synchronization -> disable "safe write" (各IntelliJのIDEで異なる可能性があります。その場合はsearch featureを使用してください。)

Proxy

webpackの開発用サーバー(dev server)は、node-http-proxyを使用することで、 バックエンドサーバー(外部へのリクエストも可能)へのproxyリクエストを好きなように振り分けることを可能にしてくれます。 設定例は下記のようになります。

proxy: {
  '/some/path*': {
    target: 'https://other-server.example.com',
    secure: false
  }
}

設定の詳細については、node-http-proxyのドキュメント(オプション)を参照してください。

一部のURLをプロキシすることは、様々な(開発)環境の構築において便利なことがあります。 一例として、JavaScriptファイルやその他の静的なファイル(資産)をローカルの開発サーバーから提供し、 APIのリクエストは外部のバックエンドの開発サーバーに送信するという設定が考えられます。

別の例として、バックエンドのサーバーへのリクエストを、 認証とアプリケーションのバックエンドの2つに分ける、ということも考えられます。

Proxyのバイパス(迂回)

(v1.13.0で追加) proxyは関数から返される情報を基にして、任意にバイパスすることが可能です。 この関数は与えられたproxyオプションによって、HTTPリクエスト・レスポンスに割り込みます。 戻り値としてfalse、またはプロキシのリクエストに代わるURLのパスを返さなければいけません。

例えば下記の設定は、ブラウザからの本来のHTTPリクエストに対して、プロキシを行いません。 これはhistoryApiFallbackのオプションと同じように、ブラウザのリクエストは通常のHTMLファイルとして受け取りますが、 APIリクエストはバックエンドサーバーにproxyされます。

proxy: {
  '/some/path*': {
    target: 'https://other-server.example.com',
    secure: false,
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf('html') !== -1) {
        console.log('Skipping proxy for browser request.');
        return '/index.html';
    }
  }
}
proxyリクエストのURLを書き換え

(v???で追加) proxyへのリクエストは、提供された関数で任意に書き換えることが可能です。 この関数はHTTPリクエストへの割り込みと変更を行います。

例えば、下記の設定はURLの先頭の/api部分を削除して、HTTPリクエストを書き換えます。

proxy: {
  '/api/*': {
    target: 'https://other-server.example.com',
    rewrite: function(req) {
      req.url = req.url.replace(/^\/api/, '');
    }
  }
}

webpack-dev-server CLI

$ webpack-dev-server <entry>

全てのwebpackのCLIオプションは、webpack-dev-serverのCLIにも有効ですが、 デフォルトの引数の<output>は存在しません。 webpack.config.js(または、--configによるファイルの受け渡し)によるwebpack-dev-serverのCLIのための設定が、 同様に受け入れられます。

webpack-dev-server用に追加されるオプションは下記のとおりです。

オプション 説明
--content-base <file/directory/url/port> コンテンツのベースとなるパスです。
--quiet コンソールに何も出力しません。
--no-info 冗長な情報の出力を抑制します。
--colors 出力情報の色付けを行います。
--no-colors 出力情報に色付けを行いません。
--compress gzip圧縮を使用します。
--host <hostname/ip> ホスト名、またはIPアドレスを指定します。0.0.0.0のIPアドレスは、全てのホストにバインドします。
--port <number> ポート番号を指定します。
--inline バンドルへwebpack-dev-serverのランタイムを埋め込みます。
--hot HotModuleReplacementPluginを追加し、サーバーをhotモードに切り替えます。
注意: HotModuleReplacementPluginが重複して追加されないようにしてください。
--hot --inline webpack/hot/dev-serverエントリーも追加します。
--lazy no watching, compiles on request (cannot be combined with --hot). (--hotとの連携は出来ません)
--https webpack-dev-serverがHTTPSプロトコルでサーバーを提供します。 リクエストを処理する際の、自己署名の証明書を含みます。
--cert--cacert--key 証明書ファイルのパスを指定します。
--open ブラウザが開くデフォルトURLです。
(webpack-dev-server versions > 2.0)
--history-api-fallback history APIのフォールバックのサポートを有効にします。
設定オプションの拡張

CLIを使用する場合、設定ファイルのdevServerキー配下に、webpack-dev-serverのオプションを持たせることが可能です。 CLIの引数で渡されたオプションは、設定ファイルのオプションを上書きします。 devServerキー配下のオプションについては、次のセクションを参照してください。

module.exports = {
  // ...
  devServer: {
    hot: true
  }
}

API

var WebpackDevServer = require("webpack-dev-server");
var webpack = require("webpack");

var compiler = webpack({
  // configuration
});
var server = new WebpackDevServer(compiler, {
  // webpack-dev-server options

  contentBase: "/path/to/directory",
  // or: contentBase: "http://localhost/",

  hot: true,
  // Enable special support for Hot Module Replacement
  // Page is no longer updated, but a "webpackHotUpdate" message is send to the content
  // Use "webpack/hot/dev-server" as additional module in your entry point
  // Note: this does _not_ add the `HotModuleReplacementPlugin` like the CLI option does. 

  // Set this as true if you want to access dev server from arbitrary url.
  // This is handy if you are using a html5 router.
  historyApiFallback: false,

  // Set this if you want to enable gzip compression for assets
  compress: true,

  // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server.
  // Use "*" to proxy all paths to the specified server.
  // This is useful if you want to get rid of 'http://localhost:8080/' in script[src],
  // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ).
  proxy: {
    "*": "http://localhost:9090"
  },

  // pass [static options](http://expressjs.com/en/4x/api.html#express.static) to inner express server
  staticOptions: {
  },

  // webpack-dev-middleware options
  quiet: false,
  noInfo: false,
  lazy: true,
  filename: "bundle.js",
  watchOptions: {
    aggregateTimeout: 300,
    poll: 1000
  },
  publicPath: "/assets/",
  headers: { "X-Custom-Header": "yes" },
  stats: { colors: true }
});
server.listen(8080, "localhost", function() {});
// server.close();

ミドルウェア(middleware)のオプションについては、webpack-dev-middleware を参照してください。

webpackの設定はWebpackDevServerのAPIに渡されないことに注意してください。 そのため、webpack設定内のdevServerオプションは、このケースでは使用されません。 また、WebpackDevServerのAPIにInlineモードは存在しません。 <script src="http://localhost:8080/webpack-dev-server.js"></script>が、手動でHTMLページに挿入される必要があります。

historyApiFallbackオプション

もしHTML5のヒストリーAPIを使用している場合、404レスポンスの際にindex.htmlを返す必要があるかもしれません。 これは、historyApiFallback: trueに設定することで行うことが出来ます。 ただし、もしwebpackの設定でoutput.publicPathを変更している場合、 リダイレクト先のURLを指定する必要があります。 これは、historyApiFallback.indexオプションを使用して行うことが出来ます。

// output.publicPath: '/foo-app/'
historyApiFallback: {
  index: '/foo-app/'
}

既存サーバーとの連携

あなたは開発用に、バックエンドサーバーまたはそのモックを動かしたいと考えているかもしれません。 ただし、バックエンドとしてwebpack-dev-serverを使用しないべきです。 webpack-dev-serverは静的な(webpackで出力された)ファイルのみを扱う目的で作られています。

webpack-dev-serverとあなたのバックエンドサーバーの2つを、連携して動かすことが可能です。

このケースでは、バックエンドサーバーによってHTMLページの送信が行われている場合でも、 webpackで出力されたファイルはwebpack-dev-serverにリクエストさせるように指定する必要があります。 一方でバックエンドサーバーに、生成されるHTMLページに含まれるscriptタグが、 webpack-dev-serverのファイルを対象とするように指定する必要があります。

加えて、webpack-dev-serverとwebpack-dev-serverのランタイム間を、 再コンパイルで再読み込みがトリガされるように繋げる必要があります。

webpack-dev-serverへリクエスト(チャンク読み込み、またはHMRのために)するようにwebpackに伝えるには、 output.publicPath完全なURLを提供する必要があります。

webpack-dev-serverとそのランタイムを繋げる最良の方法は、--inlineを付けてInlineモードを使用することです。 webpack-dev-serverのCLIは自動的にWebSocket接続を設置するエントリーポイントを含めます。 (また、webpack-dev-serverの--content-baseをバックエンドサーバーに指定している場合は、Iframeモードを使用することも可能です。)

もし、あなたのバックエンドサーバーにWebsocket接続をする必要がある場合、iFrameモードを使用する必要があります。

インラインモードを使用する場合は、ブラウザでバックエンドのサーバーのURLを開くだけです。 (もし、IFrameモードを使用している場合は、webpack-dev-serverのURLの先頭に/webpack-dev-server/を付けて開きます。)

下記に具体例を示します。

  • webpack-dev-serverのポートは8080とします。
  • バックエンドサーバーのポートは9090とします。
  • <script src="http://localhost:8080/assets/bundle.js"></script>を含んだ生成されたHTMLがあるとします。
  • webpackの設定で、output.publicPath = "http://localhost:8080/assets/"を指定します。
  • production用のファイルのコンパイルを行う際に、--output-public-path /assets/を使用します。
  • Inlineモードの場合:
    • --inline
    • http://localhost:9090を開きます。
  • Iframeモードの場合:
    • webpack-dev-serverで、contentBase = "http://localhost:9090/"(--content-base)を設定。
    • http://localhost:8080/webpack-dev-server/を開きます。

もしくは、Proxyのオプションを使用します。

 Back to top

© 2010 - 2017 STUDIO KINGDOM