Homepage

Connecting an Angular Single Page Application (SPA) with platformOS

Last edit: Jan 22, 2024

Problem

How to connect your Angular Single Page Application (SPA) that you created with the CLI to platformOS? The goal is to have your Angular app ready for local development communicating with the Instance by the API via proxy.

This article is based on Angular version 8.

To follow this article, you should have your development environment and a platformOS Instance set up, be familiar with pages and layouts, and have the Angular CLI installed.

Solution

Connecting Angular with platformOS is a six-step process. Angular CLI is based on webpack so some steps will be valid for other frameworks/builds based on webpack.

Step 1: Create place for Angular App files

The source files of a web app are not part of platformOS and can be stored anywhere you want.
In this example, to keep it together in one repo and in one project, you'll create the Angular app directly in your Instance's folder but not inside the /app folder. This is recommended but not required.

Navigate to your Instance folder and create new app with:

$ng new web-app

Pick scss as stylesheet format.

Instead of web-app you can also use another name for your project.

Step 2: Set up local development, production build and "hosting"

Angular app build files are part of the platformOS Instance.

In platformOS, there's no traditional hosting. You cannot put files straight into some root folder and have your-domain.com/the-file.html.

But there's a special place in your Instance where you can achieve a similar effect with a static address.
Each file put into app/assets/ will be "visible" as {your-uploads-path}/assets/.
For example app/assets/images/bg.jpg can be accessed also as {your-uploads-path}/assets/images/bg.jpg.
Read about assets for more information.

How to get your-uploads-path?

Put this code into some page liquid file and check what the server returns in the website's source code:


{{ "" | asset_url }}

It will look similar to:

https://uploads.staging.oregon.platform-os.com/instances/<YOUR-INSTANCE-ID>/assets/

We strongly recommend to wrap your build files into another folder like app/assets/web-app, because in the future you might want to store other assets, for example graphic files for emails, in the app/assets/ folder.

Change the location to store build files in the web-app/angular.json config file.
Find the line with "outputPath": "dist/web-app", and change it into:

"outputPath": "../app/assets/web-app",

If you are using version control like GIT, it's recommended to add this folder into your .gitignore rules.

After building your app, files will now be copied into app/assets/web-app.

But now compiled files will be stored under app/assets/web-app (like for example main.js) and Angular will be looking for it in the root folder. You need to let it know where to find it.

Open web-app/package.json and in scripts extend the build command:

"build": "ng build --prod --base-href / --deploy-url your-uploads-path/assets/web-app/",

Now your Angular app routing will know that your base-href is / and compiled files will be stored in /assets/web-app/.

It will append proper paths into index.html automatically.

Step 3: Set up routing and redirects

platformOS routing is based on Liquid files (pages and layouts).

Assuming that the Angular router will do its job, you'll need to rewrite all URLs into one file.

You can do this with pages and layouts. Learn More about Pages and Layouts.

First, create a layout that will be injected into every Liquid page. This file will be generated during build by Angular and copied into app/views/layouts as app.html.liquid.

You can do this in three steps:

  • open web-app/src and change the name index.html to app.html.liquid (you can name it as you want, but it has to have a .liquid extension)
  • open the web-app/angular.json config file, find the line with "index": "src/index.html", and change it to "index": "src/app.html.liquid",
  • open web-app/package.json and add commands
"copyIndex": "cp ../app/assets/web-app/app.html.liquid ../app/views/layouts/",

and

"postbuild": "npm run copyIndex"

So right after your web app will be built, your index will be copied into app/views/layouts as a layout with the name app.

Now create the home page.

You can do this in app/views/pages where you create the routing folder.
Now, in app/views/pages/routing, create the index.liquid page with the following code:

app/views/pages/routing/index.liquid
---
layout: app
---

You will need a similar page for every URL, but fortunately only on the first level.

For example, have the URLs:

  • company/about
  • company/terms-of-service
  • company/info/some-example-page

For all these links, only one page has to be created:

app/views/pages/company.html.liquid
---
layout: app
---

The Angular router will do rest of the job.

Step 4: Set up local and production paths

If you needed to add some asset files like for example images or custom svg icons for Angular Materials or maybe translation files like for ngx-translate, you should definitely store them in web-app/src/assets/.

Now you need to let your app know where you store them. You will use Angular environments files for this task.

web-app/src/environments/environment.ts
export const environment = {
  production: false,
  assetsPrefix: ''
}
web-app/src/environments/environment.prod.ts
export const environment = {
  production: true,
  assetsPrefix: 'your-uploads-path/assets/web-app',
}

Anywhere in code where you need a reference to one of your assets, you'll use the environment.assetsPrefix variable.

Step 5: Set up local and production paths inside (s)css files

Angular CLI cannot replace css files because css is built before the replacement engine runs.
There are some different approaches to achieve that, but in this tutorial, we go another way.

Create two files:

web-app/src/styles/environments/local/asset-path.scss
$assets-path: '';
web-app/src/styles/environments/prod/asset-path.scss
$assets-path: 'your-uploads-path/assets/web-app/';

(web-app/src/styles/ is where you store all global scss files)

Then create two commands that will do the job - before angular build will change the $assets-path: '' into $assets-path: '/assets/web-app/' and restore it after build.

"cssAssetsPath": "cp src/styles/environments/prod/asset-path.scss src/styles/environments/",
"cssAssetsPathReset": "cp src/styles/environments/local/asset-path.scss src/styles/environments/",

Also, add the "prebuild": "npm run cssAssetsPath", command to run it before and update postbuild so that's how your scripts look like now:

"cssAssetsPath": "cp src/styles/environments/prod/asset-path.scss src/styles/environments/",
"cssAssetsPathReset": "cp src/styles/environments/local/asset-path.scss src/styles/environments/",
"copyIndex": "cp ../app/assets/web-app/app.html.liquid ../app/views/layouts/",
"prebuild": "npm run cssAssetsPath",
"build": "ng build --prod --base-href / --deploy-url your-uploads-path/assets/web-app/",
"postbuild": "npm run copyIndex && npm run cssAssetsPathReset"

And now in any of your scss files when you need assets you'll use:

@import '~styles/environments/asset-path.scss';

.my-component {
  background-image: url('#{$assets-path}/assets/images/some-image.jpg');
}

Step 6: Set up proxy for local API calls

Due to security issues you should not use:

response_headers: >
  {
    "Access-Control-Allow-Origin": "*"
  }

So you need to use a proxy. To do this, follow the instructions here: Proxying to a backend server.

Now you have $ng serve for local development and $npm run build for production build.

Source code

You can find the source code of this example on GitHub.

Questions?

We are always happy to help with any questions you may have.

contact us