Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make angular application read environment variables from private cloud foundry (Runtime)

I am working with angular 5 application and deploying to private cloud foundry. In general, while building the application we would provide API endpoint in "environment.{*}.ts" file and run npm run build --prod command.

my requirement is to read user provided environment variables after deployment. I am new to PCF.

Thanks in advance.

Links I have tried so far, Link1, Link2,Link3

like image 652
Gowtham.K.Reddy Avatar asked Apr 09 '18 15:04

Gowtham.K.Reddy


People also ask

What environment variable is used for application monitoring on Cloud Foundry?

For apps bound to certain services that use a database, Cloud Foundry creates a DATABASE_URL environment variable based on the VCAP_SERVICES environment variable. Cloud Foundry uses the structure of the VCAP_SERVICES environment variable to populate the DATABASE_URL environment variable.

How do I set environment variables in Cloud Foundry?

View Environment Variables Using the Cloud Foundry Command Line Interface (cf CLI), you can run the cf env command to view the Application Service Adapter environment variables for your app. The cf env command displays the following environment variables: The user-provided variables set using the cf set-env command.

What is Vcap_services in PCF?

VCAP_SERVICES variables provided in the container environment in which the application runs. VCAP_SERVICES environment variable is in JSON data structure. Cloud Foundry makes sure that multiple JSON elements can be set in the VCAP_SERVICES JSON.


2 Answers

One way to accomplish this is to use Angular Universal to do your initial render server-side via Node.

As part of your Angular Universal setup, you'll have a server.ts file, which can read any environment variables you need. I chose Nunjucks for this example to render the index.html from the Angular application (I'm sure you can use EJS or another templating engine).

// server.ts
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import * as nunjucks from 'nunjucks';

import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4201;
const DIST_FOLDER = join(process.cwd(), 'dist');

// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'index.html')).toString();

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist-server/main.bundle');

const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');

nunjucks.configure(DIST_FOLDER, {
  autoescape: true,
  express: app,
});

app.engine('html', (_, options, callback) => {
  renderModuleFactory(AppServerModuleNgFactory, {
    // Our index.html
    document: template,
    url: options.req.url,
    // DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP)
    ]
  }).then(html => {
    callback(null, html);
  });
});

app.set('view engine', 'html');

// Server static files from dist folder
app.get('*.*', express.static(DIST_FOLDER));

// All regular routes use the Universal engine
// You can pass in server-side values here to have Nunjucks render them
app.get('*', (req, res) => {
  res.render('index', { req, someValue: process.env.someValue });
});

// Start up the Node server
app.listen(PORT);

In your index.html, you can output the server-side variables wherever you need. I chose to assign a value to the window here called environment.

<!DOCTYPE html>
<html lang="en">
  <head>
    <base href="/" />
    ...
  </head>
  <body>
    <app-root></app-root>
    <script>
      window['environment'] = {
        someValue: '{{ someValue }}',
      };
    </script>
  </body>
</html>

Subsequently in Angular components, services, etc, you can access the value via window['environment'].someValue

like image 87
Brandon Avatar answered Sep 26 '22 03:09

Brandon


I wrote a blogpost about this. In short:

  • Fork the staticfile-buildpack
  • Change the data.go to include:
location /inject {
    default_type application/json;
    return 200 '<%= ENV["INJECT"] %>';
    }
  • Set a environment var "INJECT" with json in CF
  • cf push with -b [your forked repo]
  • enable SSI in the buildpack by including a Staticfile
  • Add a SSI to your angular index.html to include this:
<html>
    <head>
        <script type="text/javascript">window["INJECT"] = 
            <!--#include virtual="/inject" -->
        </script>
like image 32
Flores Avatar answered Sep 26 '22 03:09

Flores