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

2

7

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

Ensoll answered 9/4, 2018 at 15:17 Comment(4)
To clarify, you're wanting to access the environment variables at build time? or run time?Multitude
Thank you for the response, I need to access at run timeEnsoll
Are you able to leverage Node to do your initial render with Angular Universal?Multitude
I am not familiar with Angular Universal, I will give a look at it.any help in advance is appreciated :)Ensoll
M
2

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

Multitude answered 10/4, 2018 at 13:19 Comment(4)
Thank you for your example. I will import and let you know for sure. as of now, I have come across another approach and deployed. This one seems interesting :)Ensoll
Another way to do this would be to base the environment.[whatever].ts file on an environment variable at build time and use cross-var: npmjs.com/package/cross-var to pick up the Node environment variable in the npm build script.Multitude
Thank you, I have created a environmentconfig.ts file during the ng build --prod command and then while uploading to PCF we need to use a package.json file. in that Package.json file in the "start" command i had given ts-node command to build the environmentconfig.ts file. This file is being build on PCF server hence it is reading the user provided environment variables and building a environmentconfig.js file, in the index.html file I am giving the reference to the newly generated environmentconfig.ts file. finally, reading window.environment.{KEY}, it's working as expected.Ensoll
Cool. Glad you were able to get to a solution.Multitude
C
2

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>
Chinkapin answered 1/8, 2019 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.