Mounting a SPA under different paths: including the mount path in links in the app


#1

The setup

I had a really simple app which didn’t really need the new navigation, but I decided to implement it anyway as a learning opportunity before I do something similar at work.

On my laptop I use elm-live so that my app is available under /. Then I compile it and deploy on GitHub Pages and it’s available under /random-color.

Letting Route.fromUrl know about the mount path

AKA having the same URL parser for both mount path.

Skipping all the problems related to deploying SPAs on GitHub Pages, the first problem I ran into is that the URL parser had to know what path the app root is mounted under (later called “mount path”) so that it can skip it when translating a string to a route. That was pretty easy to solve: I passed the mount path through flags and then just passed it whenever I had to call Route.fromUrl (I based my navigation code on elm-spa-example hence Route.fromUrl).

Including the mount path in the links

The bigger problem is including the mount path in the URLs in the app. I think most other frontend libraries and frameworks solve this problem by not using the <a> tag directly but rather some kind of a wrapper which knows about the mount path and can include it in the links generated in the app.

In Elm it would mean passing some kind of a link function to each view function. In a small app that’s not a problem but I can imagine it can get cumbersome in a bigger app.

So then I thought about just adding the mount path in the handler for internal URL requests. That kinda works but then the links on the page don’t point to the correct path by themselves which can break “Open in new tab”.

How else would you solve that problem?

The solutions I was able to come up with:

  1. A link function that I mentioned.
    • Something similar is proposed as a solution in How do I manage URL from a Browser.element?. However, the link function there doesn’t need information from the model, so using it deep down in some view function isn’t a problem.
    • If absolutely necessary, the link function could have the mount path hardcoded and then that path could be changed on production just before the compilation step.
  2. A web component which is just a simple wrapper over <a> and knows about the mount path.
    • If I absolutely had to solve this problem, then I’d probably go with that, but for simpler apps I’d love to have a more straightforward solution.
  3. Mounting it under the same path both on dev and production.
    • Seems straightforward, adds some troubles around dev setup. In this scenario, I’d probably still write a “static” link function which includes the mount path so that it can be easily changed if needed.
  4. Use hash navigation. All links in the app can then just start with a hash (<a href="#foo">) and the problem with knowing the mount path disappears since you’re not really changing the path in the browser but just the hash part.
    • elm-spa-example does this, but if possible I’d like to avoid doing that.

#2

Would it be possible to use relative paths in your links, like <a href="under/some/path">, then if it is mounted on / it would generate a link for /under/some/path and if it was on /random-color/ it would generate /random-color/under/some/path?


#3

I think that the best solution at the moment is to pass the flags to your views and build the urls there by prepending the basepath. Because it is simple and shows the target url in the href.


#4

AFAIK that’s not possible, because the relative paths are relative to the current page. So if I was at /random-color/colors/ff00ff, I’d have no way to link to /random-color (the mount path) with relative links.


#5

You may be able to successfully use <base> and relative urls through the app.

I recently learnt about it and it is quite interesting.


#6

Wow, it worked! I didn’t know about <base>, thank you very much!

The only thing I had to remember was that the path that is given to href of <base> needs to end with a trailing slash, otherwise links with empty href won’t point to the correct path.

This is a very elegant solution, as the SPA can use relative links for all URLs in the app and then if it ever needs to link to some other resource under the same domain, it can just use absolute links.


#7

Could a base tag help? :thinking: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base


#8

That’s what @joakin suggested just hours before you. :wink:


#9

Ah. My message got delayed because I just registered and my post needed to be verified. Glad it worked. Good to know. :smile:


#10

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