首页 文章

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

提问于
浏览
102

我正在创建一个使用webpack-dev-server开发的应用程序以及react-router .

似乎webpack-dev-server是基于这样一种假设,即你将在一个地方(即“/”)有一个公共入口点,而react-router允许无限量的入口点 .

我想要webpack-dev-server的好处,特别是热量重新加载功能,这对于提高工作效率很有帮助,但我仍然希望能够加载在react-router中设置的路由 .

如何实现它以便它们一起工作?你能以这种方式在webpack-dev-server前运行快速服务器吗?

9 回答

  • 1

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

  • 2

    我设置了一个代理来实现这个目标:

    您有一个常规的快速网络服务器,可以在任何路由上为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进行热重载

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

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

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

    对于其他可能仍在寻找此答案的人 . 我整理了一个简单的代理绕过,没有太多麻烦,配置进入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';
            }
          }
        }
      }
    }
    
  • 65

    如果您使用CLI运行webpack-dev-server,则可以通过webpack.config.js传递devServer对象来配置它:

    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 ”的部分)来验证是否已正确设置所有内容 .

    enter image description here

  • 92

    对于更新的答案,当前版本的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:无需运行自定义服务器,只需使用cli即可:

    "scripts": {
        "start": "webpack-dev-server --config ./webpack.config.js --mode development"
      },
    
  • 19

    当你运行一个同构应用程序(即渲染React组件服务器端)时,我想添加案例的答案 .

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

    这引发了另一个问题 - 如果你从与快速服务器相同的进程运行webpack服务器(如上面接受的答案),webpack服务器也将重新启动,并且每次都会重新编译你的软件包 . 为避免这种情况,您应该在不同的进程中运行主服务器和Webpack服务器,以便管道只重新启动您的快速服务器,并且不会触及webpack . 您可以使用 concurrently 包执行此操作 . 您可以在react-isomorphic-starterkit中找到此示例 . 在package.json中,他有:

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

    它同时运行两个服务器但在不同的进程中运行

  • 1

    historyApiFallback 也可以是包含路径的对象而不是布尔值 .

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

    这对我有用:只需先添加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)
    })
    

相关问题