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?

102
demandé sur Artjom B. 2014-10-05 18:49:12

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/",
        // ...
    }
65
répondu Retozi 2014-10-09 09:08:42

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);
});
91
répondu Juho Vepsäläinen 2015-02-20 07:27:10

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';
        }
      }
    }
  }
} 
17
répondu Werner Weber 2017-01-15 01:35:38

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 ").

enter image description here

9
répondu Eugene Kulabuhov 2017-05-29 13:43:47

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"
  },
6
répondu Michael Brown 2018-03-27 01:59:09

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.

2
répondu Viacheslav 2015-05-19 16:22:04

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' }
  ]
}
1
répondu Tom Roggero 2017-06-27 21:15:44

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

1
répondu Alex 2017-10-16 13:04:03

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)
})
0
répondu Graham Norton 2017-10-20 11:06:30