webpack-dev-serverがreact-routerからのエントリポイントを許可できるようにする方法


117

私は、react-routerとともに開発中のwebpack-dev-serverを使用するアプリを作成しています。

webpack-dev-serverは、パブリックエントリポイントが1か所(つまり "/")にあるとの想定に基づいて構築されているようですが、react-routerではエントリポイントの数に制限はありません。

webpack-dev-serverの利点、特に生産性に優れたホットリロード機能が欲しいのですが、react-routerで設定されたルートをロードできるようにしたいのです。

彼らが一緒に働くようにそれをどのように実装できますか?これを可能にするような方法で、webpack-dev-serverの前で高速サーバーを実行できますか?


私はここに何かの非常にハッキーなバージョンがありますが、それは壊れやすく、単純なルートのみが一致することを許可します:github.com/natew/react-base(make-webpack-configを参照)および(app / routes.js)
Nathan Wienert

この問題を解決することができましたか?もしそうなら?ここstackoverflow.com/questions/31091702/…で私の質問に答えてみてください。ありがとうございました..!
SudoPlz 2015年

回答:


69

私はこれを達成するためにプロキシを設定しました:

アセットルートの場合を除いて、任意のルートでindex.htmlを提供する通常のエクスプレスウェブサーバーがあります。アセットの場合、リクエストはweb-dev-serverにプロキシされます

ホットエントリーポイントは引き続きwebpack devサーバーを直接指すため、ホットリロードは引き続き機能します。

8081でwebpack-dev-serverを実行し、8080でプロキシを実行するとします。server.jsファイルは次のようになります。

"use strict";
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./make-webpack-config')('dev');

var express = require('express');
var proxy = require('proxy-middleware');
var url = require('url');

## --------your proxy----------------------
var app = express();
## proxy the request for static assets
app.use('/assets', proxy(url.parse('http://localhost:8081/assets')));

app.get('/*', function(req, res) {
    res.sendFile(__dirname + '/index.html');
});


# -----your-webpack-dev-server------------------
var server = new WebpackDevServer(webpack(config), {
    contentBase: __dirname,
    hot: true,
    quiet: false,
    noInfo: false,
    publicPath: "/assets/",

    stats: { colors: true }
});

## run the two servers
server.listen(8081, "localhost", function() {});
app.listen(8080);

次のように、webpack設定にエントリポイントを作成します。

 entry: [
     './src/main.js',
     'webpack/hot/dev-server',
     'webpack-dev-server/client?http://localhost:8081'
 ]

hotreloadのための8081への直接呼び出しに注意してください

また、output.publicPathオプションに絶対URLを渡してください。

 output: {
     publicPath: "http://localhost:8081/assets/",
     // ...
 }

1
ねえ、これは素晴らしいです。私は実際にこれの少し前にこのセットアップに到着し、答えを投稿するつもりでしたが、あなたはより良い仕事をしたと思います。
Nathan Wienert 2014年

1
質問は1つです。関係がないので、必要に応じて新しい質問を開くことができますが、webpack開発サーバーからのコンソール出力がストリーミングされないことに気づきました。以前は、それがコンパイルされるのを見て、パーセントが上がるのを確認できましたが、今はコンパイル後に出力をブロックするだけです。
Nathan Wienert 2014年

よくできました。これはまさにそれが行われるべき方法です。output.publicPathオプションに関するメモも追加しました。これは絶対URLでもかまいません。
Tobias K.

5
代わりに組み込みのWebpackプロキシを使用する方が簡単です。したがって、あなたは、サーバーを残して、サーバー自体には干渉しない純粋な。代わりに、webpack設定に少し(3〜5行)追加するだけです。おかげで、開発目的のために開発スクリプトのみを変更し、本番コード(server.js)を(バージョンとは異なり)安心して残し、適切な方法はimoにします。
jalooc 2015

3
この答えは少し古くなっていますが、まだ正しいです。より簡単な方法が利用できるようになりましたhistoryApiFallback
Eugene Kulabuhov

102

これを機能させるにhistoryApiFallbackWebpackDevServer、をtrueに設定する必要があります。以下は小さな例です(目的に合わせて調整してください):

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

var config = require('./webpack.config');


var port = 4000;
var ip = '0.0.0.0';
new WebpackDevServer(webpack(config), {
    publicPath: config.output.publicPath,
    historyApiFallback: true,
}).listen(port, ip, function (err) {
    if(err) {
        return console.log(err);
    }

    console.log('Listening at ' + ip + ':' + port);
});

index.htmlの上のステータスバーを見逃してしまいますが、これはうまく機能します:)
swennemen

7
これは受け入れられる答えになるはずです。webpack dev server docsから:「HTML5履歴APIを使用している場合、おそらく404応答の代わりにindex.htmlを提供する必要があります。これは、historyApiFallback:trueを設定することで実行できます」質問を正しく理解すれば、これで解決します問題。
セバスチャン

とてもシンプル...ありがとう!
smnbbrv 2016年

1
@smnbbrv問題ありません。実際にはその下でconnect-history-api-fallbackを使用し、必要に応じてミドルウェア固有のオプションを使用してオブジェクトを渡すことができますtrue
JuhoVepsäläinen2016年

1
または、CLIを使用している場合webpack-dev-server --history-api-fallback
Levi

27

まだこの答えを探している可能性のある他の人のために。手間をかけずにこれを実現する単純なプロキシバイパスをまとめ、構成はwebpack.config.jsに入れます

正規表現を使用してローカルコンテンツをテストするはるかに洗練された方法があると確信していますが、これは私のニーズに適しています。

devServer: {
  proxy: { 
    '/**': {  //catch all requests
      target: '/index.html',  //default target
      secure: false,
      bypass: function(req, res, opt){
        //your custom code to check for any exceptions
        //console.log('bypass check', {req: req, res:res, opt: opt});
        if(req.path.indexOf('/img/') !== -1 || req.path.indexOf('/public/') !== -1){
          return '/'
        }

        if (req.headers.accept.indexOf('html') !== -1) {
          return '/index.html';
        }
      }
    }
  }
} 

私のためにうまくいった
Nath

うまくいきました!..ありがとう!
Dhrumil Bhankhar、2016年

これは完璧な答えであり、素早く簡単です。
ドミノ

12

CLIを使用してwebpack-dev-serverを実行している場合は、devServerオブジェクトを渡してwebpack.config.jsで構成できます。

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js"
  },
  devServer: {
    historyApiFallback: true
  }
}

これにより、404が検出されるたびにindex.htmlにリダイレクトされます。

注:publicPathを使用している場合は、それもdevServerに渡す必要があります。

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js",
    publicPath: "admin/dashboard"
  },
  devServer: {
    historyApiFallback: {
      index: "admin/dashboard"
    }
  }
}

出力の最初の数行を見れば、すべてが正しく設定されていることを確認できます(「404がフォールバックするパス:」の部分)。

ここに画像の説明を入力してください


11

より最近の答えは、現在のバージョンのwebpack(4.1.1)のwebpack.config.jsで次のように設定するだけです。

const webpack = require('webpack');

module.exports = {
    entry: [
      'react-hot-loader/patch',
      './src/index.js'
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ['style-loader','css-loader']
            }
        ]
    },
    resolve: {
      extensions: ['*', '.js', '.jsx']  
    },
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: 'bundle.js'
    },
    plugins: [
      new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
      contentBase: './dist',
      hot: true,
      historyApiFallback: true
    }
  };

重要な部分はhistoryApiFallback: trueです。カスタムサーバーを実行する必要はありません。cliを使用するだけです。

"scripts": {
    "start": "webpack-dev-server --config ./webpack.config.js --mode development"
  },

2

同形のアプリを実行する(つまり、Reactコンポーネントをサーバー側でレンダリングする)場合の答えを追加したいと思います。

この場合、Reactコンポーネントの1つを変更したときにサーバーを自動的に再ロードすることもできます。これはpipingパッケージで行います。あなたがしなければならないすべてはそれをインストールし、require("piping")({hook: true})あなたのserver.jsの最初のどこかに追加することです。それでおしまい。サーバーが使用するコンポーネントを変更すると、サーバーが再起動します。

ただし、これは別の問題を引き起こします-エクスプレスサーバーと同じプロセスからWebpackサーバーを実行すると(上記の受け入れられた回答のように)、Webpackサーバーも再起動し、毎回バンドルを再コンパイルします。これを回避するには、メインサーバーとWebpackサーバーを異なるプロセスで実行して、パイピングがExpressサーバーのみを再起動し、Webpackに触れないようにする必要があります。あなたはこれを行うことができますconcurrentlyパッケージでます。この例は、react-isomorphic-starterkitにあります。でpackage.json彼が持っています:

"scripts": {
    ...
    "watch": "node ./node_modules/concurrently/src/main.js --kill-others 'npm run watch-client' 'npm run start'"
  },

両方のサーバーを同時に実行しますが、別々のプロセスで実行します。


これは、一部のファイルが2回監視されていることを意味しますか?共有同形/ユニバーサルファイルなど
David Sinclair

1

historyApiFallback ルートを含むブール値の代わりにオブジェクトにすることもできます。

historyApiFallback: navData && {
  rewrites: [
      { from: /route-1-regex/, to: 'route-1-example.html' }
  ]
}


-1

これは私にとってうまくいきました:最初に単にwebpackミドルウェアを追加し、 app.get('*'... index.htmlリゾルバを

:そう要求のWebPACKによって提供されるルートの1つに一致する場合、最初の(同様にチェックする発現/dist/bundle.jsまたは/__webpack_hmr_そうでない場合、それはに移動します)index.html*リゾルバます。

つまり:

app.use(require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
}))
app.use(require('webpack-hot-middleware')(compiler))
app.get('*', function(req, res) {
  sendSomeHtml(res)
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.