javascript - Wie konfiguriere ich verschiedene Umgebungen in Angular.js?
Wie verwalten Sie Konfigurationsvariablen/-konstanten für verschiedene Umgebungen?
Dies könnte ein Beispiel sein:
Meine REST-API ist unter localhost:7080/myapi/ erreichbar, aber mein Freund, der am gleichen Code unter Git-Versionierung arbeitet, hat die API auf seinem Tomcat unter localhost:8099/hisapi/ bereitgestellt.
Angenommen, wir haben so etwas wie dies:
angular
.module('app', ['ngResource'])
.constant('API_END_POINT','<local_end_point>')
.factory('User', function($resource, API_END_POINT) {
return $resource(API_END_POINT + 'user');
});
Wie kann ich den korrekten Wert des API-Endpunkts je nach Umgebung dynamisch einfügen?
In PHP mache ich normalerweise solche Sachen mit einer config.username.xml-Datei, indem ich die Basis-Konfigurationsdatei (config.xml) mit der lokalen Umgebungs-Konfigurationsdatei zusammenführe, die am Namen des Benutzers erkannt wird. Aber ich weiß nicht, wie man so etwas in JavaScript verwaltet?
Antwort #1
Ich bin ein wenig spät zum Thread, aber wenn du Grunt verwendest, habe ich mit grunt-ng-constant großen Erfolg gehabt.
Der Konfigurationsabschnitt für ngconstant in meiner Gruntfile.js sieht wie folgt aus
ngconstant: {
options: {
name: 'config',
wrap: '"use strict";\n\n{%= __ngModule %}',
space: ' '
},
development: {
options: {
dest: '<%= yeoman.app %>/scripts/config.js'
},
constants: {
ENV: 'development'
}
},
production: {
options: {
dest: '<%= yeoman.dist %>/scripts/config.js'
},
constants: {
ENV: 'production'
}
}
}
Die Aufgaben, die ngconstant verwenden, sehen aus wie
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run([
'build',
'open',
'connect:dist:keepalive'
]);
}
grunt.task.run([
'clean:server',
'ngconstant:development',
'concurrent:server',
'connect:livereload',
'open',
'watch'
]);
});
grunt.registerTask('build', [
'clean:dist',
'ngconstant:production',
'useminPrepare',
'concurrent:dist',
'concat',
'copy',
'cdnify',
'ngmin',
'cssmin',
'uglify',
'rev',
'usemin'
]);
Das Ausführen von grunt server erzeugt eine config.js-Datei in app/scripts/, die wie folgt aussieht
"use strict";
angular.module("config", []).constant("ENV", "development");
Schließlich erkläre ich die Abhängigkeit von allen Modulen, die sie benötigen:
// the 'config' dependency is generated via grunt
var app = angular.module('myApp', [ 'config' ]);
Jetzt können meine Konstanten dort, wo sie benötigt werden, per Dependency Injection eingefügt werden. Zum Beispiel,
app.controller('MyController', ['ENV', function( ENV ) {
if( ENV === 'production' ) {
...
}
}]);
Antwort #2
Eine coole Lösung könnte darin bestehen, alle umgebungsspezifischen Werte in ein separates Angular-Modul auszulagern, von dem alle anderen Module abhängen:
angular.module('configuration', [])
.constant('API_END_POINT','123456')
.constant('HOST','localhost');
Dann können Ihre Module, die diese Einträge benötigen, eine Abhängigkeit davon deklarieren:
angular.module('services',['configuration'])
.factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
return $resource(API_END_POINT + 'user');
});
Jetzt könntest du über weitere coole Sachen nachdenken:
Das Modul, das die Konfiguration enthält, kann in configuration.js aufgeteilt werden, das auf Ihrer Seite eingebunden wird.
Dieses Skript kann von jedem von euch leicht bearbeitet werden, solange ihr diese separate Datei nicht in Git eincheckt. Aber es ist einfacher, die Konfiguration nicht einzuchecken, wenn sie in einer separaten Datei ist. Außerdem könntet ihr sie lokal verzweigen.
Nun, wenn Sie ein Build-System wie ANT oder Maven haben, könnten Ihre nächsten Schritte darin bestehen, einige Platzhalter für die Werte API_END_POINT zu implementieren, die während der Build-Zeit durch Ihre spezifischen Werte ersetzt werden.
Oder Sie haben Ihre configuration_a.js und configuration_b.js und entscheiden im Backend, welche einzubinden ist.
Antwort #3
Für Gulp-Benutzer ist gulp-ng-constant auch in Kombination mit gulp-concat, event-stream und yargs nützlich.
var concat = require('gulp-concat'),
es = require('event-stream'),
gulp = require('gulp'),
ngConstant = require('gulp-ng-constant'),
argv = require('yargs').argv;
var enviroment = argv.env || 'development';
gulp.task('config', function () {
var config = gulp.src('config/' + enviroment + '.json')
.pipe(ngConstant({name: 'app.config'}));
var scripts = gulp.src('js/*');
return es.merge(config, scripts)
.pipe(concat('app.js'))
.pipe(gulp.dest('app/dist'))
.on('error', function() { });
});
In meinem Konfigurationsordner habe ich diese Dateien:
ls -l config
total 8
-rw-r--r--+ 1 .. ci.json
-rw-r--r--+ 1 .. development.json
-rw-r--r--+ 1 .. production.json
Dann können Sie gulp config --env development ausführen und das wird so etwas wie dies erstellen:
angular.module("app.config", [])
.constant("foo", "bar")
.constant("ngConstant", true);
Ich habe auch diese Spezifikation:
beforeEach(module('app'));
it('loads the config', inject(function(config) {
expect(config).toBeTruthy();
}));
Antwort #4
Um das zu erreichen, schlage ich vor, dass Sie das AngularJS Environment Plugin verwenden: https://www.npmjs.com/package/angular-environment
Hier ist ein Beispiel:
angular.module('yourApp', ['environment']).
config(function(envServiceProvider) {
// set the domains and variables for each environment
envServiceProvider.config({
domains: {
development: ['localhost', 'dev.local'],
production: ['acme.com', 'acme.net', 'acme.org']
// anotherStage: ['domain1', 'domain2'],
// anotherStage: ['domain1', 'domain2']
},
vars: {
development: {
apiUrl: '//localhost/api',
staticUrl: '//localhost/static'
// antoherCustomVar: 'lorem',
// antoherCustomVar: 'ipsum'
},
production: {
apiUrl: '//api.acme.com/v2',
staticUrl: '//static.acme.com'
// antoherCustomVar: 'lorem',
// antoherCustomVar: 'ipsum'
}
// anotherStage: {
// customVar: 'lorem',
// customVar: 'ipsum'
// }
}
});
// run the environment check, so the comprobation is made
// before controllers and services are built
envServiceProvider.check();
});
Und dann können Sie die Variablen von Ihren Controllern folgendermaßen aufrufen:
envService.read('apiUrl');
Ich hoffe, es hilft.
Antwort #5
Sie könnten lvh.me:9000 verwenden, um auf Ihre AngularJS-App zuzugreifen, (lvh.me zeigt einfach auf 127.0.0.1) und dann einen anderen Endpunkt angeben, wenn lvh.me der Host ist:
app.service("Configuration", function() {
if (window.location.host.match(/lvh\.me/)) {
return this.API = 'http://localhost\\:7080/myapi/';
} else {
return this.API = 'http://localhost\\:8099/hisapi/';
}
});
Und dann den Konfigurationsdienst injizieren und Configuration.API überall dort verwenden, wo Sie auf die API zugreifen müssen:
$resource(Configuration.API + '/endpoint/:id', {
id: '@id'
});
Etwas umständlich, funktioniert aber für mich gut, wenn auch in einer etwas anderen Situation (API-Endpunkte unterscheiden sich in Produktion und Entwicklung).
