javascript - Cum pot să configurez diferite medii în Angular.js?


Cum gestionezi variabilele/constantele de configurare pentru diferite medii?

Acesta ar putea fi un exemplu:

API-ul meu REST este accesibil la localhost:7080/myapi/, dar prietenul meu care lucrează la același cod sub controlul versiunilor Git are API-ul implementat pe Tomcat-ul său la localhost:8099/hisapi/.

Presupunând că avem ceva de genul acesta:

angular
    .module('app', ['ngResource'])

    .constant('API_END_POINT','<local_end_point>')

    .factory('User', function($resource, API_END_POINT) {
        return $resource(API_END_POINT + 'user');
    });

Cum pot injecta dinamic valoarea corectă a punctului final API, în funcție de mediu?

În PHP, de obicei fac acest gen de lucruri cu un fișier config.username.xml, combinând fișierul de configurare de bază (config.xml) cu fișierul de configurare pentru mediul local recunoscut după numele utilizatorului. Dar nu știu cum să gestionez acest gen de lucru în JavaScript?

Răspuns #1

Sunt puțin întârziat la discuție, dar dacă folosești Grunt, am avut mare succes cu grunt-ng-constant.

Secțiunea de configurare pentru ngconstant în Gruntfile.js arată astfel

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'
    }
  }
}

Sarcinile care folosesc ngconstant arată astfel

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'
]);

Deci, rularea grunt server va genera un fișier config.js în app/scripts/ care arată astfel

"use strict";
angular.module("config", []).constant("ENV", "development");

În cele din urmă, declar dependența față de modulele care au nevoie de ea:

// the 'config' dependency is generated via grunt
var app = angular.module('myApp', [ 'config' ]);

Acum constantele mele pot fi injectate prin dependință acolo unde este nevoie. De exemplu,

app.controller('MyController', ['ENV', function( ENV ) {
  if( ENV === 'production' ) {
    ...
  }
}]);

Răspunsul #2

O soluție interesantă ar putea fi separarea tuturor valorilor specifice mediului într-un modul Angular separat, de care depind toate celelalte module:

angular.module('configuration', [])
       .constant('API_END_POINT','123456')
       .constant('HOST','localhost');

Atunci modulele tale care au nevoie de acele intrări pot declara o dependență de acesta:

angular.module('services',['configuration'])
       .factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
           return $resource(API_END_POINT + 'user');
       });

Acum ai putea să te gândești la alte chestii tari:

Modulul, care conține configurația, poate fi separat în configuration.js, care va fi inclus în pagina ta.

Acest script poate fi ușor editat de fiecare dintre voi, atâta timp cât nu încărcați acest fișier separat în git. Dar este mai ușor să nu încărcați configurația dacă se află într-un fișier separat. De asemenea, ați putea să faceți un branch local.

Acum, dacă aveți un sistem de construire, cum ar fi ANT sau Maven, pașii următori ar putea fi implementarea unor marcaje pentru valorile API_END_POINT, care vor fi înlocuite în timpul construirii cu valorile voastre specifice.

Sau ai fișierul tău configuration_a.js și configuration_b.js și decizi la backend pe care să îl incluzi.

Răspunsul #3

Pentru utilizatorii Gulp, gulp-ng-constant este de asemenea util combinat cu gulp-concat, event-stream și yargs.

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() { });
});

În folderul meu de configurare am aceste fișiere:

ls -l config
total 8
-rw-r--r--+ 1 .. ci.json
-rw-r--r--+ 1 .. development.json
-rw-r--r--+ 1 .. production.json

Apoi poți rula gulp config --env development și asta va crea ceva de genul acesta:

angular.module("app.config", [])
.constant("foo", "bar")
.constant("ngConstant", true);

Am și această specificație:

beforeEach(module('app'));

it('loads the config', inject(function(config) {
  expect(config).toBeTruthy();
}));

Răspunsul #4

Pentru a realiza acest lucru, vă sugerez să folosiți pluginul AngularJS Environment: https://www.npmjs.com/package/angular-environment

Iată un exemplu:

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();
});

Și apoi, poți să apelezi variabilele din controllerele tale astfel:

envService.read('apiUrl');

Sper că ajută.

Răspunsul #5

Ai putea folosi lvh.me:9000 pentru a accesa aplicația ta AngularJS, (lvh.me indică pur și simplu către 127.0.0.1) și apoi specifica un endpoint diferit dacă lvh.me este gazda:

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/';
  }
});

Apoi injectați serviciul Configuration și folosiți Configuration.API oriunde aveți nevoie să accesați API-ul:

$resource(Configuration.API + '/endpoint/:id', {
  id: '@id'
});

Puțin greoi, dar funcționează bine pentru mine, deși într-o situație ușor diferită (endpoint-urile API diferă în producție și dezvoltare).