How to allow for webpack-dev-server to allow entry points from react-router

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

Webpack-dev-server 似乎是基于这样的假设构建的: 您将在一个位置(即“/”)有一个公共入口点,而 response-router 允许无限量的入口点。

我希望获得 webpack-dev-server 的好处,特别是热重载特性,这对生产力非常有用,但是我仍然希望能够加载在 response-router 中设置的路由。

How could one implement it such that they work together? Could you run an express server in front of webpack-dev-server in such a way to allow this?

92093 次浏览

我建立了一个代理来实现这一点:

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

您的反应热入口点仍然直接指向 webpack 开发服务器,因此热重载仍然可以工作。

假设您在8081上运行 webpack-dev-server,在8080上运行代理:

"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获取热载荷

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

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

您应该将 WebpackDevServerhistoryApiFallback设置为 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);
});

我想为运行同构应用程序(即在服务器端呈现 React 组件)的情况添加一个答案

在这种情况下,您可能还希望在更改 React 组件之一时自动重新加载服务器。使用 piping包执行此操作。你所要做的就是安装它,然后在你的 Server.js的开头添加 require("piping")({hook: true})。就是这样。在您更改服务器所使用的任何组件后,服务器将重新启动。

这引起了另一个问题-如果你运行 webpack 服务器从相同的进程作为您的快递服务器(在接受的答案以上) ,webpack 服务器也将重新启动,并将重新编译您的捆绑包每次。为了避免这种情况,您应该在不同的进程中运行您的主服务器和 webpack 服务器,这样管道将只重新启动您的快递服务器,而不会触及 webpack。 您可以使用 concurrently软件包来实现这一点。您可以在 反应-同构-启动试剂盒中找到这方面的一个例子。在 包裹 Json中,他有:

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

which runs both servers simultaneously but in separate processes.

对于那些可能还在寻找答案的人来说。我组装了一个简单的代理绕过程序,它可以轻松地完成这个任务,然后将配置放到 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';
}
}
}
}
}

如果使用 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"
}
}
}

You can verify that everything is setup correctly by looking at the first few lines of the output (the part with "404s will fallback to: path").

enter image description here

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

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

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

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

so express will first check if the request matches one of the routes provided by webpack (like: /dist/bundle.js or /__webpack_hmr_) and if not, then it will move to the index.html with the * resolver.

即:

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

For a more recent answer, the current version of webpack (4.1.1) you can just set this in your webpack.config.js like such:

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