A Sapper-compatible setup to serve multiple apps from a single Express/Polka entry point
Asked Answered
D

1

8

I need to set up a Polka (or Express) server so that it can serve multiple applications (one per hostname) from a single server.js entry point. It can be done using the vhost middleware (https://github.com/expressjs/vhost). Each app is exported as a middleware, and the one that corresponds to each request is added in the middleware chain in server.js.

However, some (not all) of these apps will be Sapper applications so the setup must be compatible with Sapper. So far as I am aware, Sapper builds generate a server.js file which works as entry point for the app, but the app is not exported. Is there a build option to export the Sapper app (instead of doing listen on it)? Or some other way to do this?

I've tried to manually edit a build and it seems to work, although there are some issues with file paths because the root of the Sapper app is not that of the main application.

I've looked up this problem but didn't find any reference to it, so I am wondering if I am taking a wrong path and if there is a more obvious solution. (Note: the Node.js hosting I am using doesn't allow to map hostnames to app folders, which would of course make things simpler.)

Deadman answered 9/12, 2020 at 10:21 Comment(0)
G
1

Solution #1: Export Sapper app as a middleware

You can make your own export of Sapper app. In server.ts/server.js of your Sapper app, instead of starting the server you can export a middleware. Something like this:

import * as sapper from "@sapper/server";
export const handler = sapper.middleware();

Then in your express app just map the domain to exported middleware:

const express = require('express');
const vhost = require('vhost');
const path = require('path');
const { handler } = require('./__sapper__/build/server/server');


const app = express();

app.use(vhost('*.example.com', (req, res, next) => {

  if (req.vhost[0] === 'sapper') {
    return handler(req, res, next);
  }

  return res.statusCode(400);
}))

app.listen(3000, () => console.log('Server started'));

Solution #2: Use a reverse proxy

Another solution would be to run all the nested applications in different ports on the server and use a revers proxy to route the requests accordingly.

For running the nested applications on different ports, possible solution would be dockerizing them or using the pm2.

For the reverse proxy part you could use Nginx or Traefik. Also it is possible to write a reverse proxy middleware to handle it programmatically using http-proxy-middleware

Gould answered 17/12, 2020 at 9:34 Comment(3)
Thanks for your answer. This is what I meant when I said I edited the build manually. It works but it means modifiying this file upon each build. And there's the extra issue of file paths. In my test app, a JSON file is loaded from the local filesystem. When the app is run from the top-level server.js, the path to this file is broken. All in all, doing all this manually doesn't seem viable.Ism
@NicolasLeThierryd'Ennequin Thanks for explanation. Why do you need to modify the file upon each build? Is it because of development environment?Gould
Your comment made me realise that I was modifying __sapper__/build/server/server.js when I should obviously make the change once in src/server.js. This probably solves the main part of the problem. I'm going to check, thanks!Ism

© 2022 - 2024 — McMap. All rights reserved.