Agent.Logic_
Agent.Logic_

Reputation: 1593

nginx - Serve multiple roots for different single page applications

I'm trying to serve two different versions of a single page application - one, built with a brand new, shiny JS framework, and another built with an older, crummier JS framework. All of the important features and functionality are in the new SPA, and all the non-critical in the older SPA and are in the midst of being ported over.

With this in mind, I'm trying to make the older SPA available via a path, e.g. /old-app.

The new app resides in /www/new-app. The old app resides in /www/old-app.

This is what I have tried:

server {
  listen 443;

  root /www/new-app;
  index index.html;

  location / { # default to new app
    try_files $uri @prerender;
  }

  location /old-app {
    root /www/old-app; # I have also tried *alias* instead of *root* here
    index index.html;
    try_files $uri @prerender;
  }

  location @prerender {
    set $prerender = 0;

    # a bunch of rules for prerender from here: https://gist.github.com/thoop/8165802

    if ($prerender = 1) {
      proxy_pass http://127.0.0.1:8080/$scheme://$host$request_uri;
    }

    if ($prerender = 0) {
      rewrite .* /index.html break;
    }
  }
}

The above returns a 200 OK for https://www.domain.example/old-app/<route>, but the page served is not /www/old-app/index.html. Instead, the file served is from /www/new-app/index.html with a blank page, presumably because the new SPA does not understand the provided /<route>, which only the old SPA understands.

Upvotes: 1

Views: 893

Answers (2)

Agent.Logic_
Agent.Logic_

Reputation: 1593

While Richard's answer works and is probably more correct than mine, I ended up with the following config (before Richard had the chance to post his answer!) after a lot of trial and error. I'm posting it here for posterity, should anyone else have the same requirements as mine.

server {
  listen 443;

  root /www/new-app;
  index index.html;

  # I left the following alone
  location / {
    try_files $uri @prerender;
  }

  # Here's the meat of what worked
  location /old-app {
    alias /www/old-app;
    index index.html;
    try_files $uri $uri/ index.html;
  }
}

And finally, in the index.html of the old single page app, I added a <base href="/old-app/" /> to make sure any references to images, stylesheets etc. were served from the correct server path.

Now, visiting http://domain.example/old-app correctly serves the default route of the old SPA!

Upvotes: 0

Richard Smith
Richard Smith

Reputation: 49692

Two things are wrong here.

location /old-app {
    root /www/old-app;

This will look for files at /www/old-app/old-app (see this document for details).

try_files $uri @prerender;

This sends all of your routes to the location @prerender block, which ends with rewrite .* /index.html break;

There may be a more elegant solution, but you could just add a second "prerender" block, for example location @oldrender which is similar to the original, but ends with rewrite ^ /old-app/index.html last;

For example:

location /old-app {
    root /www;
    try_files $uri @oldrender;
}
location @oldrender {
    ...
        rewrite ^ /old-app/index.html last;
    ...
}

Notice the root has changed, and you need to use rewrite...last.

Upvotes: 1

Related Questions