How can I host my SPA application?

I have the following configuration for hosting static files.

httpNodeRoot: '/api'
httpStatic: '/data/public'

If you place the index.html and Javascript files generated by the SPA application in the public folder, the page will be displayed when you access "http://localhost:1880", but when you access "http://localhost:1880/top" the index.html is not returned and the page is Not Found.

I would like to return "index.html" for all requests except those beginning with "api".
In Express, it would be as follows...

app.use((req, res, next) => {
res.sendFile(path.join(__dirname, "..", "public", "index.html"));

i bumped into this issue also when i was using a Vue SPA served with uibuilder.
Refreshing on a sub-path was giving 404.
Same with Node-red we dont have access to the express server but you do have access to settings.js httpNodeMiddleware where by reading the req you can do some if checks (possibly with regex) and then sendFile index.html

Im sending part of my code in the middleware, which i dont even know if its the correct method and in your case will need more modifications since you are not serving from a subpath but i hope it can give you some pointers.

const re = new RegExp(`^(${req.baseUrl})\/(.*)(.js|.html|.css|.jpg|.png)$`);
//   console.log(re);
  if (req.originalUrl.replaceAll("/","") === req.baseUrl.replaceAll("/","") ||  re.test(req.originalUrl)) {
    // console.log("IN REGEX .. called next()");
  } else {
    // console.log("IN THE ELSE .. sendFile");
    res.sendFile(path.join(__dirname, "../", req.baseUrl, "dist", "index.html"));
    // next();

ps. maybe it would be easier if you also served your SPA from a sub-path ?
to avoid clashes with other endpoints ?

//httpStatic: [
  //    {path: '/home/nol/pics/',    root: "/img/"},
  //    {path: '/home/nol/reports/', root: "/doc/"},

ps2. try uibuilder it can serve your app and also provide very useful methods for receiving / sending msgs between your app and NR using websockets.

That shouldn't be happening. I do try to do extensive testing to ensure sub-folder paths work. However, you do need to be aware of a few limitations. I've reduced those over the years though and if you are using v5, you should no longer need to do anything to have everything working on sub-folders.

That IS access to the ExpressJS server.

Also, with uibuilder v5, you also have the option of using a different ExpressJS instance which allows you to have different option settings in addition to the usual uibuilder custom middleware capabilities. On either setup, you can also create local API's as well.

Sub-paths work fine with the static folder and they absolutely recognise index.html default files:


i know and it works fine .. maybe my choice of word "issue" was wrong to describe it ..
its just how Express works in the case of a Single Page Application, which in my case uses vue-router, that creates sub-routes to the main serving path. Those sub-paths are created by the vue-router and dont really exist on the express server and when we refresh .. cannot GET 404.

True .. and thats where i tackled it .. in the case of uibuilder in /.config/uibMiddleware.js
thanks for implementing this

yes .. with the difference that those are actual folders .. in the case of react or vue router it doesnt match any static assets. Maybe we can PM and i'll give you access to my system to show you or there is a video on youtube that demonstrates this BrowserHistory in Production (the interesting part starts at 9:12)

OK, I can see the issue from Express. I'm not an SPA expert but I think I've mostly seen this worked around by making sure that the SPA "routes" can't be seen as real routes by doing something like https://localhost/#/sparoute?

As in this example using the github version of the uibuilder tech docs that use the Docksify SPA:

1 Like

Thank you for the useful information.
I was eventually able to solve the problem by using a hash router.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.