How to make an angularjs application 12 factor compliant regarding configuration
Asked Answered
K

2

6

I'm trying to make an angularjs app 12 factor compliant regarding config (http://12factor.net/config).

It should depend on the environment and I should not see the words development, test, production, etc. in the code.

Variables could be stored in bash env for example. I could pass them to a webserver.

I already thought of an .erb template file to erb config.js.erb > config.js, but if I change a variable while the application is running I'd have to redo this.

I already found this article http://mindthecode.com/how-to-use-environment-variables-in-your-angular-application/

But it's a big lie and Grunt.js to do this, really... Anyway.

I know 12factor philosophy wasn't made for frontend application but my angular application could be deployed in many different servers across many environment and it won't harm anyone to try to do things properly :).

Thanks !

Edit:

The config parameters I'd like to use would be some stuff like :

app:
   api:
       url: "The url of the api server"
       port: 8080
   cdn:
       images: "url of my images caching service"
   google:
       oauth:
           "api_key": "The api key used for that deployment"
   #other external frontend services

Other Edit:

This guy kinda went with an answer : http://bahmutov.calepin.co/inject-valid-constants-into-angular.html which I find kind of ugly and totally bound to angularjs; but it works !

Kultur answered 30/5, 2014 at 10:14 Comment(11)
“I should not see the words development, test, production, etc. in the code” — I don’t think that’s what the 12 Factor App manifesto is saying. You shouldn’t see any config values in the code, but if the code should behave differently in different deployments (e.g. for an Express app, you might only want to enable static file serving in your local dev deployment), then that’s fine.Wanigan
In regards to your actual question, what config values do you have in your Angular app? What, if any, server-side code is running?Wanigan
Hey @paul-d-waite sorry it took so long to answer, the frontend stuff var I'd need would be, like google maps auth key, the actual url of my api on which the javascript client would make request, other oauth stuff, etc. Ps: thats weird because I remember writing this months agoKultur
that’s quite alright. Sure, that makes sense. What server-side code do you have running?Wanigan
I'm on heroku, using Express (its like 7 lines of code), but I'm open to anything :)Kultur
gotcha. I’m not super-experienced with Angular, but as far as I can see, the environment is determined by which server your code is being served from. So ultimately the server has to provide the environment variables; it’s not really Angular’s concern.Wanigan
Yup, but how would angular read them ? I thought of making a before bootstraping request, but that'd delay the pop time of the app. The link I just put in my edit tells to inject a <script/> code that would overwrite some angularjs parameter, which seems to be the best solution for now.Kultur
That depends on what you want. You mentioned in your question “I already thought of an .erb template file... but if I change a variable while the application is running I'd have to redo this.” If you want to be able to change variables and have your Angular browser app pick up changes without the user refreshing the browser, you’d need the server to supply the variables via AJAX, and have Angular read them via a new AJAX call each time. But if you’re okay with the user refreshing the browser, then server-side templating would work, as would writing out a JavaScript file on the server...Wanigan
...when you deploy the app, which Angular then picks up when you require() that file in your Angular code.Wanigan
Could I require that file avoiding it to be compressed, I mean, the grunt build will totally remove the require() part of angularjs right ?Kultur
no idea, although my understanding of grunt is that it allows you to write build scripts, so what it’ll do to your code depends on how you write your Grunt script.Wanigan
K
1

Here is the solution I found, it's totally bound to angularjs but it works for me on Heroku and it's very simple. I just append my conf module to the generated code.

Everytime I restart the app a new version of the code is copied therefore the Append only happens once.

The Append just redefines an already existing configuration variable. If someone find something more 'classy' I'd be happy to put it as the right solution !

var compression = require('compression');
var express = require('express');
var logfmt = require('logfmt');
var stdio = require('stdio');
var glob = require("glob");
var fs = require('fs');

// ------------------------
// Read config from args
var ops = stdio.getopt({
  'url': {
    key: 'u',
    args: 1,
    default: '',
    description: 'Url of api server'
  },
  'port': {
    key: 'p',
    args: 1,
    default: 5000,
    description: 'Port on which to listen'
  }
});


var port = ops.port || process.env.PORT;
ops.port = undefined;

// ------------------------
// Append config to js built file

var codeToAppend = 'angular.module("project.config",[]).constant("ApiConfig",' + JSON.stringify(ops) + ');';

glob(__dirname + '/dist/scripts/scripts.*.js', function(er, files) {
  fs.appendFile(files[0], codeToAppend, function(err) {
    if (err) {
      throw err;
    }
    console.log('The "conf code" was appended to file!');
  });
});

// ------------------------
// Start App :3

var app = express();

app.use(logfmt.requestLogger());
app.use(compression({
  threshold: 512
}));
app.use(express.static(__dirname + '/dist'));

app.get('/config', function(req, res) {
  res.json(ops);
});

app.listen(port);
Kultur answered 15/10, 2014 at 15:52 Comment(0)
C
0

I found a repository on github that hopefully help you Angular-Express-Train-Seed

Conversationalist answered 21/8, 2014 at 14:27 Comment(3)
Hello @nmrony, thanks thats what I want, only problem is it's an unofficial re-build of Angular.js, which I am sure will lead to a lot of problems.Kultur
I'll try to come with something more simpleKultur
@Azer I think you can replace the angularjs with newer version. yeah you may need to re-code some line to make it compatible.Conversationalist

© 2022 - 2024 — McMap. All rights reserved.