# How can I host my SPA application?

**URL:** <https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904>\
**Category:** General\
**Created:** [25 August 2022 12:34 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904 "2022-08-25T12:34:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![TomBots](https://avatars.discourse-cdn.com/v4/letter/t/91b2a8/32.png) [@TomBots](https://discourse.nodered.org/u/TomBots)\
**Post date:** [25 August 2022 12:34 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/1 "2022-08-25T12:34:58Z")

</div>

I have the following configuration for hosting static files.

settings.js  
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](http://localhost:1880)", but when you access "[http://localhost:1880/top](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"));  
});

---

<div class="post-metadata">

**Author:** ![UnborN](https://avatars.discourse-cdn.com/v4/letter/u/4491bb/32.png) [@UnborN](https://discourse.nodered.org/u/UnborN)\
**Post date:** [25 August 2022 13:06 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/2 "2022-08-25T13:06:59Z")

</div>

> [@TomBots](#):
>
> I would like to return "index.html" for all requests except those beginning with "api".

i bumped into this issue also when i was using a Vue SPA served with [uibuilder](https://flows.nodered.org/node/node-red-contrib-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.

```auto
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()");
    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 ?

```javascript
//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.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [25 August 2022 15:58 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/3 "2022-08-25T15:58:59Z")

</div>

> [@UnborN](#):
>
> i bumped into this issue also when i was using a Vue SPA served with [uibuilder](https://flows.nodered.org/node/node-red-contrib-uibuilder).  
> Refreshing on a sub-path was giving 404.

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.

> [@UnborN](#):
>
> 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

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.

> [@TomBots](#):
>
> 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](http://localhost:1880)", but when you access "[http://localhost:1880/top](http://localhost:1880/top)" the index.html is not returned and the page is Not Found.

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

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/3/231f2aeac64af700077af029f2fa9bc1a45fc5d3.png)

---

<div class="post-metadata">

**Author:** ![UnborN](https://avatars.discourse-cdn.com/v4/letter/u/4491bb/32.png) [@UnborN](https://discourse.nodered.org/u/UnborN)\
**Post date:** [25 August 2022 16:53 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/4 "2022-08-25T16:53:11Z")

</div>

> [@TotallyInformation](#):
>
> I do try to do extensive testing to ensure sub-folder paths work

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.

> [@TotallyInformation](#):
>
> That IS access to the ExpressJS server.

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

> [@TotallyInformation](#):
>
> Sub-paths work fine with the static folder and they absolutely recognize index.html default files

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](https://youtu.be/cdUyEou0LHg?t=549) (the interesting part starts at 9:12)

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [26 August 2022 01:04 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/5 "2022-08-26T01:04:39Z")

</div>

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:

[https://totallyinformation.github.io/node-red-contrib-uibuilder/#/](https://totallyinformation.github.io/node-red-contrib-uibuilder/#/)

---

<div class="post-metadata">

**Author:** ![TomBots](https://avatars.discourse-cdn.com/v4/letter/t/91b2a8/32.png) [@TomBots](https://discourse.nodered.org/u/TomBots)\
**Post date:** [30 August 2022 01:05 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/6 "2022-08-30T01:05:49Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [13 September 2022 01:06 UTC](https://discourse.nodered.org/t/how-can-i-host-my-spa-application/66904/7 "2022-09-13T01:06:03Z")

</div>

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