使用Hapi反应路由

时间:2019-04-12 10:42:10

标签: reactjs react-router-v4 hapijs react-router-dom

我有一个要求将Hapi与create-react-app一起使用,其中Hapi充当api请求的代理,并且还服务于React应用。

我正在尝试使路由正常工作,但似乎不适用于当前的Hapi配置。

这是我的服务器代码:

const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');

const init = async () => {

    const server = new Hapi.Server({
        port: process.env.PORT || 5000,
        routes: {
            files: {
                relativeTo: Path.join(__dirname, '../build')
            }
        }
    });

    await server.register(Inert);

    server.route({
        method: 'GET',
        path: '/{param*}',
        handler: {
            directory: {
                path: '.'
            }
        }
    });

    const options = {
        ops: {
            interval: 1000
        },
        reporters: {
            myConsoleReporter: [
                {
                    module: 'good-console',
                    args: [{ request: '*', response: '*' }]
                },
                'stdout'
            ]
        }
    };

    await server.register({
        plugin: require('good'),
        options,
    });

    await server.start();

    console.log('Server running at:', server.info.uri);
};

init();

打开localhost:5000时,index.html文件加载正常。我在/dashboard部分中配置了路由react-router。击中localhost:5000/dashboard会得到404。

问题:

  • 如何在Hapi中配置路由,以便在呈现index.html之后React接管路由?
  • 在构建应用程序之后,当前服务器代码将从build文件夹为该应用程序提供服务。如何配置它以进行热重装而不会从create-react-app
  • 弹出

注意:使用npm start运行react应用时,路由有效。但这没有运行Hapi服务器。

我是使用Hapi的新手,因此欢迎使用任何指针。

2 个答案:

答案 0 :(得分:0)

所以我玩了各种hapi +惰性组合,这才对我有用。

  

server.js

const Path = require('path');
const Hapi = require('hapi');
const Inert = require('inert');
const routes = require('./routes');
const init = async () => {

    console.log('Routes are', routes);
    const server = new Hapi.Server({
        port: process.env.PORT || 5000,
        routes: {
            files: {
                relativeTo: Path.join(__dirname, '../build')
            }
        }
    });

    await server.register(Inert);

    server.route(routes);

    /**
     * This is required here because there are references to *.js and *.css in index.html,
     * which will not be resolved if we don't match all remaining paths.
     * To test it out, comment the code below and try hitting /login.
     * Now that you know it doesn't work without the piece of code below,
     * uncomment it.
     */
    server.route({
        method: 'GET',
        path: '/{path*}',
        handler: {
            directory: {
                path: '.',
                redirectToSlash: true,
                index: true,
            }
        }
    });

    const options = {
        ops: {
            interval: 1000
        },
        reporters: {
            myConsoleReporter: [
                {
                    module: 'good-console',
                    args: [{ request: '*', response: '*' }]
                },
                'stdout'
            ]
        }
    };

    await server.register({
        plugin: require('good'),
        options,
    });

    await server.start();

    console.log('Server running at:', server.info.uri);
};

init();
  

/routes/index.js

/**
* Use this for all paths since we just need to resolve index.html for any given path.
* react-router will take over and show the relevant component.
* 
* TODO: add a 404 handler for paths not defined in react-router
*/
const fileHandler = {
    handler: (req, res) => {
        console.log(res.file('index.html'));
        return res.file('index.html');
    }
}

const routes = [
    { method: 'GET', path: '/login', config: fileHandler },
]

module.exports = routes;

这里要观察的关键是,对于任何命名路径(在本例中为/login),我们总是返回index.html文件。对于所有其他路径,我们告诉hapi从build目录中返回文件,以便解决对*.css中对*.jsindex.hml文件的任何引用,而我们不这样做不会遇到404。

我不确定一旦装入index.html后react-router将如何接管路径解析,但是它超出了此问题的范围,也许是下一次讨论的话题。

至于有关热装的第二个问题,我仍在设法解决。现在,我需要同时运行hapi服务器和react-app,因为我需要/api才能在react-app中使用。欢迎任何建议或答案。

答案 1 :(得分:0)

这是我如何做到的。测试了一下。版本 "@hapi/hapi": "^20.0.1"

const path = require("path")
const Hapi = require('@hapi/hapi')
const Boom = require('@hapi/boom');

const server = Hapi.server({
    port: 3000,
    host: '0.0.0.0',
    routes: {
        files: {
            relativeTo: path.join(__dirname, 'YOU BUILD REACT DIR')
        }

    }
});
(async () => {
    await server.register([
        require('vision'),
        require('inert')
    ]);
    server.route(
        [{
            method: 'GET',
            path: '/{path*}',
            options: {
                ext: {
                    onPreResponse: {
                        method(req, h) {
                            //for other path prefix /Api
                            const isApi = req.path.substr(1)
                                .toLowerCase()
                                .trim()
                                .split('/')[0]
                                .replace(/\//g, "") === "api"

                            const response = req.response
                            if (response && req.response.output && req.response.output.statusCode === 404) {
                                if (isApi)
                                    return Boom.notFound("Not Found")
                                return h.file('index.html');
                            }
                            return h.continue
                        },
                    }
                }
            },
            handler: {
                directory: {
                    path: ".",
                    listing: false,
                    index: true
                }
            }
        },
        {
            method: 'GET',
            path: '/Api/test',
            handler: () => "OK"
        }
    ])
    await server.start();
    console.log('Server running on %s', server.info.uri)
})()