Bagaimana cara mengkonfigurasi lingkungan yang berbeda di Angular.js?

220

Bagaimana Anda mengelola variabel / konstanta konfigurasi untuk lingkungan yang berbeda?

Ini bisa menjadi contoh:

API istirahat saya dapat dijangkau localhost:7080/myapi/, tetapi teman saya yang bekerja pada kode yang sama di bawah kontrol versi Git telah menggunakan API di Tomcat-nya.localhost:8099/hisapi/ .

Andaikata kita memiliki sesuatu seperti ini:

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

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

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

Bagaimana cara saya menyuntikkan nilai akhir API yang benar secara dinamis, tergantung pada lingkungannya?

Dalam PHP saya biasanya melakukan hal-hal semacam ini dengan config.username.xmlfile, menggabungkan file konfigurasi dasar (config.xml) dengan file konfigurasi lingkungan lokal yang dikenali oleh nama pengguna. Tapi saya tidak tahu bagaimana cara mengatur hal semacam ini di JavaScript?

rbarilani
sumber

Jawaban:

209

Saya sedikit terlambat ke utas, tetapi jika Anda menggunakan Grunt saya sudah sukses dengan grunt-ng-constant.

Bagian konfigurasi untuk ngconstantdi Gruntfile.jssepertinya saya

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

Tugas yang digunakan ngconstantterlihat seperti

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

Jadi menjalankan grunt serverakan menghasilkan config.jsfile app/scripts/seperti itu

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

Akhirnya, saya menyatakan ketergantungan pada modul apa pun yang membutuhkannya:

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

Sekarang konstanta saya dapat disuntikkan ketergantungan jika diperlukan. Misalnya,

app.controller('MyController', ['ENV', function( ENV ) {
  if( ENV === 'production' ) {
    ...
  }
}]);
André Dion
sumber
10
Daripada menempatkan 'ngconstant:development'di 'serve'- jika Anda memasukkannya ke dalam config menonton di bawah 'gruntfile'seperti tasks: ['ngconstant:development']- Anda tidak perlu me-restart grunt serveketika Anda memperbarui variabel pembangunan di gruntfile tersebut.
dihabiskan
10
Alih-alih menambahkan konstanta Anda di gruntfile.js, Anda dapat memasukkan file terpisah seperti ini:package: grunt.file.readJSON('development.json')
Guilhem Soulas
3
Ada sintaks yang diperbarui untuk Gruntfile.js dalam versi 0.5 grunt-ng-constant: github.com/werk85/grunt-ng-constant/issues/31 . Jawaban yang bagus, terima kasih!
pherris
10
Bagi mereka yang menggunakan tegukan, ada teguk-ng-konstan .
Dheeraj Vepakomma
4
Saya telah menemukan bahwa ini juga diperlukan untuk memasukkan file skrip / config.js ke angular untuk menemukan modul, seperti ini: <script src = "scripts / config.js"> </script>
Toni Gamez
75

Satu solusi keren mungkin memisahkan semua nilai spesifik lingkungan menjadi beberapa modul sudut terpisah, yang bergantung pada semua modul lainnya:

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

Kemudian modul Anda yang membutuhkan entri tersebut dapat mendeklarasikan ketergantungan padanya:

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

Sekarang Anda bisa memikirkan hal-hal keren lainnya:

Modul, yang berisi konfigurasi dapat dipisahkan menjadi configuration.js, yang akan disertakan di halaman Anda.

Script ini dapat dengan mudah diedit oleh Anda masing-masing, asalkan Anda tidak memeriksa file terpisah ini menjadi git. Tetapi lebih mudah untuk tidak memeriksa konfigurasi jika ada dalam file terpisah. Anda juga bisa bercabang secara lokal.

Sekarang, jika Anda memiliki sistem build, seperti ANT atau Maven, langkah lebih lanjut Anda dapat menerapkan beberapa placeholder untuk nilai API_END_POINT, yang akan diganti selama waktu build, dengan nilai spesifik Anda.

Atau Anda memiliki configuration_a.jsdan configuration_b.jsdan memutuskan di backend yang akan dimasukkan.

kfis
sumber
30

Untuk pengguna Gulp , gulp-ng-constant juga berguna dikombinasikan dengan gulp-concat , event-stream, dan 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() { });
});

Dalam folder konfigurasi saya, saya memiliki file-file ini:

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

Kemudian Anda dapat menjalankan gulp config --env developmentdan itu akan membuat sesuatu seperti ini:

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

Saya juga punya spec ini:

beforeEach(module('app'));

it('loads the config', inject(function(config) {
  expect(config).toBeTruthy();
}));
Rimian
sumber
Apakah ada cara untuk menghapus array ketergantungan dengan menelan konstan? Saya tidak memiliki ketergantungan pada konstanta saya seperti yang Anda miliki dalam hal ini misalnya "ngAnimate". Jika saya tidak memasukkannya, saya mendapatkan array dependensi kosong sebagai angular.module ("my.module.config", []) tapi saya ingin output sebagai angular.module ("my.module.config"). Saya tidak melihat opsi di tegukan konstan tetapi saya melihat bahwa Anda dapat melewati deps: false dalam paket konstan mendengus. Ada bantuan?
Arun Gopalpuri
17

Untuk mencapai itu, saya sarankan Anda untuk menggunakan AngularJS Environment Plugin: https://www.npmjs.com/package/angular-environment

Ini sebuah contoh:

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

Dan kemudian, Anda dapat memanggil variabel dari pengontrol Anda seperti ini:

envService.read('apiUrl');

Semoga ini bisa membantu.

juanpablob
sumber
1
bagaimana dia beralih antara pengembangan dan produksi?
Mawg mengatakan mengembalikan Monica
Hai Juan Pablo, atau @Mawg jika Anda menemukan jawabannya. Sebelum saya mengajukan pertanyaan pada SO / angkat masalah di Github; Bagaimana cara angular-environmentmendeteksi lingkungan? yaitu apa yang perlu Anda lakukan pada mesin / server web lokal Anda sehingga tahu bahwa itu adalah dev / prod masing-masing?
StevieP
Membaca dokumen lagi ... " envServiceProvider.check()... akan secara otomatis mengatur lingkungan yang sesuai berdasarkan domain yang diberikan". Jadi saya rasa itu mendeteksi domain saat ini dan mengatur lingkungan dengan tepat - waktu untuk mengujinya!
StevieP
13

Anda dapat menggunakan lvh.me:9000untuk mengakses aplikasi AngularJS Anda, ( lvh.mehanya menunjuk ke 127.0.0.1) dan kemudian tentukan titik akhir yang berbeda jika lvh.metuan rumah:

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

Dan kemudian menyuntikkan layanan Konfigurasi dan menggunakan di Configuration.APImana pun Anda perlu mengakses API:

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

Agak kikuk, tetapi bekerja dengan baik untuk saya, meskipun dalam situasi yang sedikit berbeda (API endpoint berbeda dalam produksi dan pengembangan).

Jure Triglav
sumber
1
jadi saya pikir sering kali orang terlalu rumit. Penggunaan sederhana dari window.location.hostlebih dari cukup bagi saya.
joseym
7

Kita juga bisa melakukan hal seperti ini.

(function(){
    'use strict';

    angular.module('app').service('env', function env() {

        var _environments = {
            local: {
                host: 'localhost:3000',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            dev: {
                host: 'dev.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            test: {
                host: 'test.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            stage: {
                host: 'stage.com',
                config: {
                apiroot: 'staging'
                }
            },
            prod: {
                host: 'production.com',
                config: {
                    apiroot: 'production'
                }
            }
        },
        _environment;

        return {
            getEnvironment: function(){
                var host = window.location.host;
                if(_environment){
                    return _environment;
                }

                for(var environment in _environments){
                    if(typeof _environments[environment].host && _environments[environment].host == host){
                        _environment = environment;
                        return _environment;
                    }
                }

                return null;
            },
            get: function(property){
                return _environments[this.getEnvironment()].config[property];
            }
        }

    });

})();

Dan di Anda controller/service, kami dapat menyuntikkan dependensi dan memanggil metode get dengan properti yang akan diakses.

(function() {
    'use strict';

    angular.module('app').service('apiService', apiService);

    apiService.$inject = ['configurations', '$q', '$http', 'env'];

    function apiService(config, $q, $http, env) {

        var service = {};
        /* **********APIs **************** */
        service.get = function() {
            return $http.get(env.get('apiroot') + '/api/yourservice');
        };

        return service;
    }

})();

$http.get(env.get('apiroot') akan mengembalikan url berdasarkan lingkungan host.

Thalaivar
sumber
5

Pertanyaan bagus!

Salah satu solusinya adalah dengan terus menggunakan file config.xml Anda, dan memberikan informasi titik akhir api dari backend ke html yang Anda hasilkan, seperti ini (contoh dalam php):

<script type="text/javascript">
angular.module('YourApp').constant('API_END_POINT', '<?php echo $apiEndPointFromBackend; ?>');
</script>

Mungkin bukan solusi yang bagus, tetapi itu akan berhasil.

Solusi lain mungkin untuk menjaga API_END_POINT konstan seperti yang seharusnya dalam produksi, dan hanya memodifikasi file host Anda untuk mengarahkan url ke api lokal Anda saja.

Atau mungkin solusi yang digunakan localStorageuntuk mengganti, seperti ini:

.factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
   var myApi = localStorage.get('myLocalApiOverride');
   return $resource((myApi || API_END_POINT) + 'user');
});
joakimbeng
sumber
Halo joakimbeng, saya menulis solusi yang saya gunakan di php untuk menjelaskan maksudnya. Kami mencoba untuk mengkode klien javascript murni dengan backend java murni, jadi campuran php / js itu bukan kasus saya dan juga ketika saya menulis di php saya selalu mencoba untuk menjaga php dan js tidak dicampur. tapi terima kasih atas jawabannya. Saya pikir solusi jawaban @kfis bisa berfungsi: file configuration.js tidak di bawah kontrol versi yang berisi modul konfigurasi. Dengan pendekatan ini saya dapat menyuntikkan / memuat juga modul konfigurasi yang berbeda untuk tujuan pengujian, jika perlu. Terima kasih kawan
rbarilani
@ hal9087 Saya sangat setuju tentang bagian bahasa pencampuran, itu harus dihindari sama sekali :) Saya suka solusi configuration.js juga, saya akan mengingatnya ketika saya membutuhkan sesuatu yang serupa!
joakimbeng
4

Sangat terlambat ke utas, tetapi teknik yang saya gunakan, pra-Angular, adalah untuk mengambil keuntungan dari JSON dan fleksibilitas JS untuk referensi kunci koleksi yang dinamis, dan menggunakan fakta lingkungan yang tidak dapat dicabut (nama server host, bahasa browser saat ini) , dll.) sebagai input untuk secara selektif membedakan / memilih nama kunci yang suffixed dalam struktur data JSON.

Ini tidak hanya menyediakan konteks lingkungan penerapan (per OP) tetapi konteks sewenang-wenang (seperti bahasa) untuk memberikan i18n atau varian lain yang diperlukan secara bersamaan, dan (idealnya) dalam manifes konfigurasi tunggal, tanpa duplikasi, dan jelas terlihat.

DALAM TENTANG 10 LINES VANILLA JS

Contoh yang terlalu sederhana tetapi klasik: URL dasar endpoint API dalam file properti berformat JSON yang bervariasi per lingkungan di mana (natch) server host juga akan bervariasi:

    ...
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        '[email protected]': 'https://www.uat.productionwebsite.com:9090/res/',
        '[email protected]': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...

Kunci ke fungsi diskriminasi adalah hanya nama host server dalam permintaan.

Ini, secara alami, dapat dikombinasikan dengan kunci tambahan berdasarkan pada pengaturan bahasa pengguna:

    ...
    'app': {
        'NAME': 'Ferry Reservations',
        'NAME@fr': 'Réservations de ferry',
        'NAME@de': 'Fähren Reservierungen'
    },
    ...

Cakupan diskriminasi / preferensi dapat terbatas pada kunci individual (seperti di atas) di mana kunci "dasar" hanya ditimpa jika ada kunci yang cocok + akhiran untuk input ke fungsi - atau seluruh struktur, dan struktur itu sendiri diuraikan secara rekursif untuk mencocokkan sufiks / preferensi preferensi:

    'help': {
        'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
        'PHONE': '808-867-5309',
        'EMAIL': '[email protected]'
    },
    '[email protected]': {
        'BLURB': 'Please contact Customer Service Center',
        'BLURB@fr': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
        'BLURB@de': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': '[email protected]'
    },

SO, jika pengguna yang mengunjungi situs web produksi memiliki pengaturan preferensi bahasa Jerman ( de ), konfigurasi di atas akan runtuh ke:

    'help': {
        'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': '[email protected]'
    },

Seperti apa fungsi penulisan ulang preferensi / diskriminasi JSON? Tidak banyak:

// prefer(object,suffix|[suffixes]) by/par/durch storsoc
// prefer({ a: 'apple', a@env: 'banana', b: 'carrot' },'env') -> { a: 'banana', b: 'carrot' }
function prefer(o,sufs) {
    for (var key in o) {
        if (!o.hasOwnProperty(key)) continue; // skip non-instance props
        if(key.split('@')[1]) { // suffixed!
            // replace root prop with the suffixed prop if among prefs
            if(o[key] && sufs.indexOf(key.split('@')[1]) > -1) o[key.split('@')[0]] = JSON.parse(JSON.stringify(o[key]));

            // and nuke the suffixed prop to tidy up
            delete o[key];

            // continue with root key ...
            key = key.split('@')[0];
        }

        // ... in case it's a collection itself, recurse it!
        if(o[key] && typeof o[key] === 'object') prefer(o[key],sufs);

    };
};

Dalam implementasi kami, yang mencakup situs web Angular dan pra-Angular, kami cukup mem-bootstrap konfigurasi jauh di depan panggilan sumber daya lainnya dengan menempatkan JSON dalam penutupan JS yang dapat dieksekusi sendiri, termasuk fungsi prefer (), dan memasukkan properti dasar dari nama host dan kode bahasa (dan menerima sufiks arbitrer tambahan apa pun yang mungkin Anda butuhkan):

(function(prefs){ var props = {
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        '[email protected]': 'https://www.uat.productionwebsite.com:9090/res/',
        '[email protected]': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...
    /* yadda yadda moar JSON und bisque */

    function prefer(o,sufs) {
        // body of prefer function, broken for e.g.
    };

    // convert string and comma-separated-string to array .. and process it
    prefs = [].concat( ( prefs.split ? prefs.split(',') : prefs ) || []);
    prefer(props,prefs);
    window.app_props = JSON.parse(JSON.stringify(props));
})([location.hostname, ((window.navigator.userLanguage || window.navigator.language).split('-')[0])  ] );

Situs pra-Angular sekarang akan memiliki jendela collapsed (no @ suffixed keys ) .app_props untuk merujuk.

Situs Angular, sebagai langkah bootstrap / init, cukup menyalin objek prop yang mati ke $ rootScope, dan (secara opsional) menghancurkannya dari ruang lingkup global / jendela

app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );

untuk selanjutnya disuntikkan ke pengendali:

app.controller('CtrlApp',function($log,props){ ... } );

atau disebut dari binding dalam tampilan:

<span>{{ props.help.blurb }} {{ props.help.email }}</span>

Peringatan? Karakter @ tidak valid penamaan variabel / kunci JS / JSON, tetapi sejauh ini diterima. Jika itu adalah deal-breaker, gantikan konvensi yang Anda suka, seperti "__" (double garis bawah) selama Anda tetap menggunakannya.

Teknik ini bisa diterapkan di sisi server, porting ke Java atau C # tetapi efisiensi / kekompakan Anda mungkin bervariasi.

Bergantian, fungsi / konvensi dapat menjadi bagian dari skrip kompilasi front-end Anda, sehingga JSON lengkap semua-lingkungan / semua-bahasa tidak pernah dikirimkan melalui kabel.

MEMPERBARUI

Kami telah mengembangkan penggunaan teknik ini untuk memungkinkan beberapa sufiks pada kunci, untuk menghindari dipaksa menggunakan koleksi (Anda masih bisa, sedalam yang Anda inginkan), dan juga untuk menghormati urutan sufiks yang disukai.

Contoh (juga lihat jsFiddle yang berfungsi ):

var o = { 'a':'apple', 'a@dev':'apple-dev', 'a@fr':'pomme',
          'b':'banana', 'b@fr':'banane', 'b@dev&fr':'banane-dev',
          'c':{ 'o':'c-dot-oh', 'o@fr':'c-point-oh' }, 'c@dev': { 'o':'c-dot-oh-dev', 'o@fr':'c-point-oh-dev' } };

/*1*/ prefer(o,'dev');        // { a:'apple-dev', b:'banana',     c:{o:'c-dot-oh-dev'}   }
/*2*/ prefer(o,'fr');         // { a:'pomme',     b:'banane',     c:{o:'c-point-oh'}     }
/*3*/ prefer(o,'dev,fr');     // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme',     b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o);              // { a:'apple',     b:'banana',     c:{o:'c-dot-oh'}       }

1/2 (penggunaan dasar) lebih suka kunci '@dev', buang semua kunci sufiks lainnya

3 lebih suka '@dev' daripada '@fr', lebih suka '@ dev & fr' daripada yang lainnya

4 (sama dengan 3 tetapi lebih suka '@fr' daripada '@dev')

5 tidak ada sufiks pilihan, tetes SEMUA properti sufiks

Ini mencapai ini dengan mencetak setiap properti suffix dan mempromosikan nilai properti suffix ke properti non-suffix ketika iterating atas properti dan menemukan akhiran skor yang lebih tinggi.

Beberapa efisiensi dalam versi ini, termasuk menghilangkan ketergantungan pada JSON untuk menyalin dalam, dan hanya berulang ke objek yang bertahan dari putaran penilaian di kedalamannya:

function prefer(obj,suf) {
    function pr(o,s) {
        for (var p in o) {
            if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1] ) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
            var b = p.split('@')[0]; // base prop name
            if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
            var ps = p.split('@')[1].split('&'); // array of property suffixes
            var sc = 0; var v = 0; // reset (running)score and value
            while(ps.length) {
                // suffix value: index(of found suffix in prefs)^10
                v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
                if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
                sc += v;
            }
            if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
            delete o[p];
        }
        for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
        for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
    }
    if( typeof obj !== 'object' ) return; // validate
    suf = ( (suf || suf === 0 ) && ( suf.length || suf === parseFloat(suf) ) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
    pr(obj,suf.reverse());
}
storsoc
sumber
2

Jika Anda menggunakan Brunch , plugin Constangular membantu Anda mengelola variabel untuk lingkungan yang berbeda.

jvannistelrooy
sumber
-8

Sudahkah Anda melihat pertanyaan ini dan jawabannya?

Anda dapat menetapkan nilai yang berlaku secara global untuk aplikasi Anda seperti ini:

app.value('key', 'value');

dan kemudian menggunakannya dalam layanan Anda. Anda bisa memindahkan kode ini ke file config.js dan menjalankannya pada pemuatan halaman atau momen lain yang nyaman.

thalador
sumber
7
Bisakah seseorang tolong jelaskan mengapa ini adalah jawaban yang buruk? Sudah secara besar-besaran diturunkan, tetapi tidak ada satu komentar ...
aendrew
5
Ini sudah sangat lama, tetapi jika saya harus menebak mengapa downvotes, itu karena tidak membahas masalah konfigurasi khusus lingkungan, itu hanya saran untuk menggunakan .value () untuk menetapkan nilai global di aplikasi lama apa pun. Tidak disebutkan tentang bagaimana seseorang akan menggunakan ini tergantung pada env atau apa pun di sepanjang parameter pertanyaan asli.
coblr