How to Deploy Angular 4+ (front-end) to CDN?
Asked Answered
O

3

15

I would like to deploy my Angular app (with AOT) to a CDN, while using my own REST server.

I would like the first request always go to my REST server (let say https://example.com). Then the first response will instruct the browser to load Angular's first module from the CDN.

All the resources requests (API requests) will of course go to my REST server (let's say https://example.com/api/XXXX).

Now my question is:

How do the codes know from where to load next Angular module?

Could someone please explain the mechanism behind this?

Os answered 6/10, 2017 at 20:56 Comment(0)
O
25

Short Answer: use the option "--deploy-url" while doing "ng build".

What the "--deploy-url" does is to force <script> tags to use an absolute URL using the domain you specify. This way the browser will always know where to load static asset files (JavaScript, Images etc)

=========================

Use Case:

The REST server is running at our data centre. It not only provides REST APIs, but also serve the initial index.html (meaning the VERY FIRST request from browser always go to this REST server).

All our Angular static files (They are just JavaScript files) are deployed to CDNs (e.g. AWS, AZURE, GOOGLE ...)

=========================

Without the "--deploy-url", "ng build" will yield an index.html as following:

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>MyApp</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
  <script type="text/javascript" src="/inline.bundle.js"></script>
  <script type="text/javascript" src="/polyfills.bundle.js"></script>
  <script type="text/javascript" src="/styles.bundle.js"></script>
  <script type="text/javascript" src="/vendor.bundle.js"></script>
  <script type="text/javascript" src="/main.bundle.js"></script>
 </body>
</html>

With the "--deploy-url", "ng build" will yield an index.html as following:

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>MyApp</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
  <script type="text/javascript" src="https://any.cdn.com/inline.bundle.js"></script>
  <script type="text/javascript" src="https://any.cdn.com/polyfills.bundle.js"></script>   
  <script type="text/javascript" src="https://any.cdn.com/styles.bundle.js"></script>    
  <script type="text/javascript" src="https://any.cdn.com/vendor.bundle.js"></script>  
  <script type="text/javascript" src="https://any.cdn.com/main.bundle.js">
  </script>
</body>
</html>

=========================

What does deployment look like:

For example,

ng build --deploy-url YOUR-CDN-SERVER-DOMAIN --prod --aot

This should generate a /dist folder with everything (including index.html) in it. Next simply move the index.html to you REST server, and deploy the remaining of the files to CDNs.

Now you can have users go to your own domain www.example.com first. You can put all those Angular generated JS files to whatever CDNs you want without worrying about CORS.

=======================

Notes:

This solution may explain things from a high level point of view. It does work perfectly in my situation. Please feel free to leave comments if you have questions.

Os answered 1/11, 2017 at 20:26 Comment(0)
S
2

Not sure if this will help, but that's my solution to hosting the frontend on S3 with a REST server in our datacenter: We have the CNAME of www.example.com pointing to the S3 bucket, where the frontend lives and api.example.com to our REST server.

In your environment.prod.ts specify an apiUrl:

export const environment = {
    production: true,
    apiUrl: 'https://api.example.com'
};

which you can use for API calls like that:

import {environment} from '../environments/environment';

getHttp(url: string, params?: RequestOptions): Observable<any> {
    // prefix API URL if not already given
    if (url.indexOf(environment.apiUrl) === -1) {
        url = environment.apiUrl + url;
    }
    return this.http.get(url, params).map().catch();
}

Just make sure you actually pass the environment and not just the target when building:

ng build --env=prod

And most important, allow requests from www. to api. (CORS) by sending these headers from your REST server:

Access-Control-Allow-Origin: https://www.example.com
Vary: Origin

Note: this also makes using a proxy for local development obsolete, because you can simply specify the local apiUrl including a port in your environment.ts

Selfexcited answered 31/10, 2017 at 23:24 Comment(2)
First of all thanks for replying. Your solution is having the very FIRST request always go to whatever server is serving the front-end static files. But I want the FIRST request to go to my REST server first, so that I can avoid all sort of CORS related issues for all resources APIs calls, because they are under the same domain. I have come up a "solution" already, which I will post later (still needs some rewordings).Os
I still don't really understand why you want to serve your index.html from your REST server. Is it because you can't point www.example.com to the CDN? Because this will make deployment more difficult (index.html on your server, the rest of the app on the CDN) and is a bit against SoC. Just being curious...Selfexcited
G
1

You need to use Cdnify . Try and use a library like gulpCDN etc.

For our Problem what i did was to upload all the Dist files after the prod build in S3 and then ran

the gulp cdnify which will replace all the local host links of main and vendor bundle files to the links from the s3 bucket (you need to specify the root directly to the library for gulp to do that automatically) in the index.html

file which will be server by my node server and then use that.

The reason we went for this approach is Node is slow at serving static files sso using this mechanism we can get faster performance , once the index.html is loaded you need not worry about the other modules as all the vendor and main js files will be loaded form the cdn link which got changed in index.html .

For Reference i used these libraries Gulp S3 and gulp cdinfy

Glaswegian answered 27/10, 2017 at 6:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.