Static Angular Deployment to a Subfolder

If you ever try to deploy an Angular app to a subfolder in your server, you will see that your app will end up with a white screen of death on your main root.

There are 2 main issues; The base tag and LocationStrategy.

First part of the fix: The base tag

The HTML <base href=”…”/> specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. For example, given the <base href="/my/app/">, the browser resolves a URL such as some/place/foo.jpg into a server request for my/app/some/place/foo.jpg. During navigation, the Angular router uses the base href as the base path to the component, template, and module files.

In development, you typically start the server in the folder that holds index.html. That’s the root folder and you’d add <base href="/"> near the top of index.html because / is the root of the app. Furthermore Angular defaults to <base href="/"> because it is a common configuration for most deployments .

When the base tag is mis-configured, the app fails to load and the browser console displays 404 - Not Found errors for the missing files. Look at where it tried to find those files and adjust the base tag appropriately.

On subfolder structured production server, you might configure this to prevent errors. For example, when the URL to load the app is something like http://www.example.com/my/app/, the subfolder is my/app/ and you should add <base href="/my/app/"> to the server version of the index.html.

You can configure while building like this;

ng build --prod --output-path docs --base-href /my/app/

You can also configure in angular.json;

{
  //...
  "projects": {
    "app": {
      //...
      "architect": {
        "build": {
          //...
          "configurations": {
            "production": {
              "baseHref": "/my/app/",
              //...
            }
          }

It is possible to set base-href to . to achieve a generic app which works in all all subfolders by relative paths but all used asset should follow a relative path within the app to comply.

Second part of the fix: LocationStrategy

In a single-page application, there is only one path to the entry file. After bootstrapping the application, instead of going to the server to get a new page, you change what the user sees by showing or hiding parts of the screen that correspond to certain components. As users perform application tasks, they need to switch between the different views you define. In this case, the server needs to redirect all traffic to index.html so Angular can take over to handle path on UI.

This otherwise brilliant solution, overly complicates server management, especially when having applications in subfolders. When the location strategy is misconfigured, the app fails to load any sub-routes and the browser console displays 404 - Not Found.  HashLocationStrategy is another strategy which is immune to this subfolder – subroute mismatch.

HashLocationStrategy is a LocationStrategy used to configure the Location service to represent its state in the hash fragment of the browser’s URL.

To enable HashLocationStrategy in an Angular application we pass {useHash: true} when we are providing our routes with RouterModule, like so:TypeScript

RouterModule.forRoot(routes, {useHash: true})

URL can contain some data prepended with a # character. The # part of the URL is called the hash fragment. However, it has another very important characteristic in that anything past the # in a URL never gets sent to the server. It’s, therefore, an ideal solution for implementing client-side routing:-

  • It’s part of the URL so can be bookmarked and sent to other people.
  • It won’t confuse the server side since the hash fragment is never sent to the server.
  • It can be programmatically changed via JavaScript.

And that’s exactly why, for a number of years, the primary way of implementing client-side routing was via hash fragments.

HashLocationStrategy simplifies the server management when an angular app is running from a subfolder.

With this strategy and base href set properly, you can simply deploy in 2 steps;

  1. Start with the production build
  2. Copy everything within the output folder (dist/ by default) to the subfolder on the server.

This is the simplest way to deploy your application as a static file bundle in a subfolder.