使用React-Router browserHistory,Webpack 2 historyApiFallback和Node

时间:2017-04-17 20:44:58

标签: node.js reactjs webpack react-router webpack-dev-server

我尝试使用React,Node,Webpack 2在本地运行我的React应用程序。每当我遇到一条不是/的路线时,我得到404.我的目标是能够运行我的节点服务器,运行webpack-dev-server,使用browserHistory并返回我的webpack historyApiFallback工作。

目前的工作原理:

  1. 如果我只运行webpack-dev-server而没有节点服务器,那么browserHistory工作正常,没有404s。
  2. 如果我使用hashHistory运行节点,它可以正常工作,没有404s。
  3. 因此排除我的路线不起作用。这是一些代码:

    server.js

    const express = require('express');
    const expressGraphQL = require('express-graphql');
    const schema = require('./schema');
    
    const app = express();
    
    app.use('/graphql', expressGraphQL({
      schema,
      graphiql: true
    }));
    
    const webpackMiddleware = require('webpack-dev-middleware');
    const webpack = require('webpack');
    const webpackConfig = require('../webpack.config.js');
    app.use(webpackMiddleware(webpack(webpackConfig)));
    
    app.listen(process.env.PORT || 5000, () => console.log('Listening'));
    

    webpack.config.js

    const webpack = require('webpack');
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    const VENDOR_LIBS = [
      'axios', 'react', 'react-dom', 'react-router', 'react-apollo', 'prop-types'
    ];
    
    module.exports = {
      entry: {
        bundle: './client/src/index.js',
        vendor: VENDOR_LIBS
      },
      output: {
        path: path.join(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[chunkhash].js'
      },
      module: {
        rules: [
          {
            use: 'babel-loader',
            test: /\.js$/,
            exclude: /node_modules/
          },
          {
            test: /\.scss$/,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader"
                }, {
                    loader: "sass-loader"
                }]
          },
          {
            test: /\.(jpe?g|png|gif|svg|)$/,
            use: [
              {
                loader: 'url-loader',
                options: {limit: 40000}
              },
              'image-webpack-loader'
            ]
          }
        ]
      },
      plugins: [
        new webpack.optimize.CommonsChunkPlugin({
          names: ['vendor', 'manifest']
        }),
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        }),
        new HtmlWebpackPlugin({
          template: './client/src/index.html'
        })
      ],
      devServer: {
        historyApiFallback: true
      }
    };
    

    routes.js

    import React from 'react';
    import { Router, Route, IndexRoute, browserHistory } from 'react-router';
    
    import App from './components/App';
    import Portal from './components/portal/Portal';
    
    const componentRoutes = {
      component: App,
      path: '/',
      indexRoute: { component: Portal },
      childRoutes: [
        {
          path: 'home',
          getComponent(location, cb) {
            System.import('./components/homepage/Home')
              .then(module => cb(null, module.default));
          }
        }
      ]
    };
    
    const Routes = () => {
      return <Router history={ browserHistory } routes={ componentRoutes } />
    };
    
    export default Routes;
    

    同样,目标是能够在本地启动我的节点服务器,使用browserHistory而不是404。我不想使用hashHistory,我需要使用我的节点服务器,所以我可以使用graphql。我也不想恢复到webpack v1。虽然这里是人们在v1中工作的链接:

    historyApiFallback doesn't work in Webpack dev server

1 个答案:

答案 0 :(得分:2)

historyApiFallback选项专门用于webpack-dev-server。如果您正在运行自己的服务器,即使使用webpack-dev-middleware,也需要将其配置为在发生404时发送index.html。由于您正在使用html-webpack-plugin,因此您要发送的index.html不存在于您的文件系统中,而只存在于内存中。要使其工作,您可以访问webpack编译器的输出,如comment of html-webpack-plugin #145

所示

<强> server.js

const path = require('path');
const express = require('express');
const expressGraphQL = require('express-graphql');
const schema = require('./schema');

const app = express();

app.use('/graphql', expressGraphQL({
  schema,
  graphiql: true
}));

const webpackMiddleware = require('webpack-dev-middleware');
const webpack = require('webpack');
const webpackConfig = require('../webpack.config.js');
const compiler = webpack(webpackConfig);

app.use(webpackMiddleware(compiler));
// Fallback when no previous route was matched
app.use('*', (req, res, next) => {
  const filename = path.resolve(compiler.outputPath, 'index.html');
  compiler.outputFileSystem.readFile(filename, (err, result) => {
    if (err) {
      return next(err);
    }
    res.set('content-type','text/html');
    res.send(result);
    res.end();
  });
});

app.listen(process.env.PORT || 5000, () => console.log('Listening'));