Comment autoriser webpack-dev-server à autoriser les points d'entrée de react-router
je crée une application qui utilise webpack-dev-server en développement avec react-router.
il semble que webpack-dev-server est construit autour de l'hypothèse que vous aurez un point d'entrée public à un endroit (i.e."/"), alors que react-router permet un nombre illimité de points d'entrée.
je veux les avantages du webpack-dev-server, en particulier la fonction de rechargement à chaud qui est grande pour la productivité, mais je veux encore être en mesure pour charger des itinéraires mis à réagir-routeur.
Comment pourrait-on le mettre en œuvre pour qu'ils travaillent ensemble? Pourriez-vous lancer un serveur express devant webpack-dev-server de manière à permettre cela?
9 réponses
j'ai mis en place un mandataire pour réaliser ceci:
vous avez un serveur web express régulier qui sert l'index.html sur n'importe quelle route, sauf si sa un atout la route. s'il s'agit d'un actif, la requête est redirigée vers le serveur web-dev
vos points d'entrée react hot pointent toujours directement sur le serveur webpack dev, donc le rechargement à chaud fonctionne toujours.
supposons que vous exécutiez webpack-dev-server sur 8081 et votre proxy à 8080. Votre serveur.le fichier js ressemblera à ceci:
"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);
faites maintenant vos points d'entrée dans la configuration webpack comme ceci:
entry: [
'./src/main.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8081'
]
note l'appel direct à 8081 pour la recharge à chaud
assurez-vous également de passer une url absolue à l'option output.publicPath
:
output: {
publicPath: "http://localhost:8081/assets/",
// ...
}
vous devez définir historyApiFallback
de WebpackDevServer
comme vrai pour que cela fonctionne. Voici un petit exemple:
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);
});
pour toute autre personne qui pourrait encore être à la recherche de cette réponse. J'ai mis en place un bypass simple proxy qui réalise cela sans trop de tracas et la config va dans le webpack.config.js
je suis sûr qu'il y a des moyens beaucoup plus élégants pour tester le contenu local en utilisant regex, mais cela fonctionne pour mes besoins.
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';
}
}
}
}
}
si vous utilisez webpack-dev-server avec CLI, vous pouvez le configurer via webpack.config.js passant devServer objet:
module.exports = {
entry: "index.js",
output: {
filename: "bundle.js"
},
devServer: {
historyApiFallback: true
}
}
redirigera vers index.html chaque fois qu'il 404 est rencontré.
NOTE: Si vous utilisez publicPath, vous devrez le passer à devServer aussi:
module.exports = {
entry: "index.js",
output: {
filename: "bundle.js",
publicPath: "admin/dashboard"
},
devServer: {
historyApiFallback: {
index: "admin/dashboard"
}
}
}
vous pouvez vérifier que tout est configuré correctement en regardant les premières lignes de la sortie (la partie avec "erreur 404 se replie sur: chemin ").
pour une réponse plus récente, la version actuelle de webpack (4.1.1) vous pouvez simplement le définir dans votre webpack.config.js comme tel:
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
}
};
la partie importante est historyApiFallback: true
. Pas besoin d'exécuter un serveur personnalisé, il suffit d'utiliser le cli:
"scripts": {
"start": "webpack-dev-server --config ./webpack.config.js --mode development"
},
j'aimerais ajouter à la réponse pour le cas où vous lancez une application isomorphique (c'est-à-dire le rendu React component server-side.)
dans ce cas, vous voulez probablement aussi recharger automatiquement le serveur lorsque vous changez l'un de vos composants React. Vous le faites avec le paquet piping
. Tout ce que vous avez à faire est de l'installer et d'ajouter require("piping")({hook: true})
quelque part dans le début de votre serveur .js . C'est tout. Le serveur redémarrera après vous changer tout composant utilisé par lui.
cela pose un autre problème Cependant - si vous exécutez webpack server à partir du même processus que votre serveur express (comme dans la réponse acceptée ci-dessus), le serveur webpack redémarrera et recompilera votre paquet à chaque fois. Pour éviter cela, vous devriez exécuter votre serveur principal et votre serveur webpack dans des processus différents afin que la tuyauterie ne redémarre que votre serveur express et ne touche pas webpack.
Vous pouvez le faire avec concurrently
. Vous peut trouver un exemple de cela dans réagissent-isomorphe a ' -starterkit . Dans le paquet .json il a:
"scripts": {
...
"watch": "node ./node_modules/concurrently/src/main.js --kill-others 'npm run watch-client' 'npm run start'"
},
qui exécute les deux serveurs simultanément mais dans des processus séparés.
historyApiFallback
peut aussi être un objet au lieu d'un Booléen, contenant les itinéraires.
historyApiFallback: navData && {
rewrites: [
{ from: /route-1-regex/, to: 'route-1-example.html' }
]
}
peut ne pas être dans tous les cas, mais semble que l'option publicPath: '/'
dans le devServer est la solution la plus facile pour fixer la question des routes profondes, voir: https://github.com/ReactTraining/react-router/issues/676
cela a fonctionné pour moi: il suffit simplement d'ajouter les middlewares webpack en premier et l'index app.get('*'...
.html résolveur plus tard,
donc express vérifiera d'abord si la requête correspond à l'une des routes fournies par webpack (comme: /dist/bundle.js
ou /__webpack_hmr_
) et si non, il passera au index.html
avec le résolveur *
.
c'est à dire:
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)
})