120

我正在创建一个在开发中使用 webpack-dev-server 和 react-router 的应用程序。

似乎 webpack-dev-server 是围绕您将在一个地方(即“/”)拥有公共入口点的假设构建的,而 react-router 允许无限数量的入口点。

我想要 webpack-dev-server 的好处,尤其是对生产力非常有用的热重载功能,但我仍然希望能够加载 react-router 中设置的路由。

如何实现它以使它们一起工作?你能在 webpack-dev-server 前面运行一个快速服务器以允许这样做吗?

4

9 回答 9

105

您应该设置historyApiFallbackWebpackDevServertrue 才能正常工作。这是一个小例子(根据您的目的进行调整):

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);
});
于 2015-02-20T07:27:10.420 回答
70

我设置了一个代理来实现这一点:

您有一个常规的快速网络服务器,可以在任何路由上为 index.html 提供服务,除非它是资产路由。如果它是资产,则请求被代理到 web-dev-server

您的 react hot 入口点仍将直接指向 webpack 开发服务器,因此热重载仍然有效。

假设您在 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'
 ]

注意直接调用 8081 进行 hotreload

还要确保将绝对 url 传递给output.publicPath选项:

 output: {
     publicPath: "http://localhost:8081/assets/",
     // ...
 }
于 2014-10-06T14:14:10.797 回答
28

对于可能仍在寻找此答案的其他任何人。我整理了一个简单的代理绕过,它可以轻松实现这一点,并且配置进入 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';
        }
      }
    }
  }
} 
于 2016-09-10T04:48:02.773 回答
13

如果你使用 CLI 运行 webpack-dev-server,你可以通过 webpack.config.js 传递 devServer 对象来配置它:

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"
    }
  }
}

您可以通过查看输出的前几行来验证所有设置是否正确(带有“404s 的部分将回退到:路径”)。

在此处输入图像描述

于 2017-05-29T13:43:47.777 回答
12

对于更新的答案,当前版本的 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"
  },
于 2018-03-27T01:59:09.287 回答
2

当您运行同构应用程序(即在服务器端渲染 React 组件)时,我想补充一下答案。

在这种情况下,您可能还希望在更改其中一个 React 组件时自动重新加载服务器。你用这个piping包做这个。您所要做的就是安装它并在server.jsrequire("piping")({hook: true})开头的某个位置添加。而已。更改服务器使用的任何组件后,服务器将重新启动。

但是,这会引发另一个问题 - 如果您从与 express 服务器相同的进程运行 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'"
  },

它同时运行两台服务器,但在不同的进程中。

于 2015-05-19T12:55:19.560 回答
1

historyApiFallback也可以是包含路由的对象而不是布尔值。

historyApiFallback: navData && {
  rewrites: [
      { from: /route-1-regex/, to: 'route-1-example.html' }
  ]
}
于 2017-06-27T21:15:44.243 回答
1

可能并非在所有情况下,但似乎publicPath: '/'devServer 中的选项是修复深度路由问题的最简单解决方案,请参阅:https ://github.com/ReactTraining/react-router/issues/676

于 2017-10-16T13:04:03.423 回答
-1

这对我有用:只需先添加 webpack 中间件,然后再添加app.get('*'...index.html 解析器,

所以 express 将首先检查请求是否匹配 webpack 提供的路由之一(如:/dist/bundle.js/__webpack_hmr_),如果不匹配,那么它将index.html使用*解析器移动到。

IE:

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)
})
于 2017-10-20T11:06:30.640 回答