如何允许webpack-dev-server允许来自react-router的入口点


117

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

似乎webpack-dev-server是建立在以下假设的基础上的:您将在一个位置拥有一个公共入口点(即“ /”),而react-router允许无限数量的入口点。

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

一个人如何才能实现它以使其协同工作?您能以这种方式在webpack-dev-server前面运行快速服务器吗?


我在这里有一个非常hacky的版本,但是它很脆弱,只允许简单的路由匹配:github.com/natew/react-base(请参阅make-webpack-config)和(app / routes.js)
Nathan Wienert

内森,您设法解决了这个问题吗?如果可以,怎么办?请尝试在此处stackoverflow.com/questions/31091702/…回答我的问题。谢谢..!
SudoPlz

Answers:


69

我设置了代理来实现此目的:

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

您的反应热入口点仍将直接指向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

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

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

1
嘿,太棒了。我实际上是在此之前不久到达此设置的,打算发布答案,但我认为您做得更好。
内森·维纳

1
一个问题,无关紧要,因此我可以在需要时提出一个新问题,但是我注意到现在webpack dev服务器的控制台输出没有流式传输。以前,您可以查看它的编译情况并看到百分比上升,而现在它只是在编译后阻止输出。
内森·维纳

干得好。这正是应该做的事情。我添加了有关该output.publicPath选项的注释,该注释也应该是绝对网址。
Tobias K. 2014年

5
仅使用内置的webpack代理会更容易。因此,您不会干扰服务器本身,只会使服务器保持纯净状态。相反,您只需对Webpack配置做一点(3-5行)的添加。因此,您仅出于开发目的而修改了开发脚本,而使生产代码(server.js)处于和平状态(与您的版本不同),而imo是正确的选择。
jalooc 2015年

3
尽管有些过时,这个答案仍然是正确的。现在可以找到更直接的方法historyApiFallback
尤金·库拉布霍夫

102

你应该设置historyApiFallbackWebpackDevServer这个作为真正的工作。这是一个小示例(进行调整以适合您的目的):

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顶部的状态栏,但这非常
有用

7
这应该是公认的答案。从webpack开发服务器文档中:“如果您使用的是HTML5历史记录API,则可能需要提供您的index.html来代替404响应,这可以通过将historyApiFallback设置为true来实现。”如果我正确理解了这个问题,它将解决问题。
塞巴斯蒂安

很简单...谢谢!
smnbbrv

1
@smnbbrv没有问题。它实际上在下面使用connect-history-api-fallback,并且您可以根据需要传递具有中间件特定选项的对象,而不是just true
JuhoVepsäläinen16年

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';
        }
      }
    }
  }
} 

为我工作得很好
2013年

工作很好!..谢谢!
Dhrumil Bhankhar '16

这只是快速简便的完美答案。
多米诺

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

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

在此处输入图片说明


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组件之一时自动重新加载服务器。您可以使用piping软件包来执行此操作。您所要做的就是安装它,并require("piping")({hook: true})server.js的开头添加一些内容。而已。更改服务器使用的任何组件后,服务器将重新启动。

但是,这会带来另一个问题-如果您以与快递服务器相同的过程运行webpack服务器(如上面接受的答案所示),则webpack服务器也将重新启动并每次都会重新编译捆绑软件。为了避免这种情况,您应该在不同的进程中运行主服务器和Webpack服务器,以便管道将仅重新启动Express服务器,而不会触及Webpack。您可以使用concurrentlypackage 进行此操作。您可以在react-isomorphic-starterkit中找到一个示例。在package.json中,他具有:

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

它可以同时运行两个服务器,但是要在单独的进程中运行。


这是否意味着某些文件被监视了两次?例如共享的同构/通用文件?
David Sinclair

1

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

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


-1

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

因此express会首先检查请求是否与webpack提供的路由之一匹配(例如:/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)
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.