Angular.js içindeki farklı ortamları nasıl yapılandırabilirim?


220

Farklı ortamlar için yapılandırma değişkenlerini / sabitleri nasıl yönetiyorsunuz?

Bu bir örnek olabilir:

Dinlenme API'ma erişilebiliyor localhost:7080/myapi/, ancak Git sürüm kontrolü altında aynı kod üzerinde çalışan arkadaşımın Tomcat'inde API dağıtıldı localhost:8099/hisapi/.

Diyelim ki böyle bir şeyimiz var:

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

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

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

Ortama bağlı olarak, API uç noktasının doğru değerini dinamik olarak nasıl enjekte edebilirim?

PHP'de genellikle bu tür şeyleri bir config.username.xmldosya ile yaparım , temel yapılandırma dosyasını (config.xml) kullanıcının adıyla tanınan yerel ortam yapılandırma dosyasıyla birleştirir. Ancak bu tür şeyleri JavaScript'te nasıl yöneteceğimizi bilmiyorum?

Yanıtlar:


209

Konuya biraz geç kaldım, ama Grunt kullanıyorsanız çok başarılı oldum grunt-ng-constant.

İçin yapılandırma bölümü ngconstantşöyle Gruntfile.jsgörünüyor

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

Görevler kullanımının ngconstantgibi bakmak

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

Çalıştırmak şuna benzer grunt serverbir config.jsdosya oluştururapp/scripts/

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

Son olarak, hangi modüllere ihtiyaç duyduğuna bağlı olduğumu beyan ederim:

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

Artık sabitlerim gerektiğinde bağımlılık enjekte edilebilir. Örneğin,

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

10
Aksine koyarak daha 'ngconstant:development'içinde 'serve'sen altında saatin config koyarsanız - 'gruntfile'olarak tasks: ['ngconstant:development']size yeniden başlatma gerekmez - grunt serveEğer gruntfile geliştirme değişkenlerini güncelleştirme.
14'te harcanan

10
Sabitlerinizi gruntfile.js'ye eklemek yerine, bunun gibi ayrı dosyalar koyabilirsiniz:package: grunt.file.readJSON('development.json')
Guilhem Soulas

3
Grunt-ng-constant'ın 0,5 sürümünde Gruntfile.js için güncellenmiş bir sözdizimi vardır: github.com/werk85/grunt-ng-constant/issues/31 . Harika cevap, teşekkürler!
pherris

10
Yudum kullananlar için yutmaz sabit vardır .
Dheeraj Vepakomma

4
Ben de bu gibi modülü bulmak için açısal scripts / config.js dosyasını dahil etmek için bulduk: <script src = "scripts / config.js"> </script>
Toni Gamez

75

Serin bir çözüm, tüm diğer modüllerin bağlı olduğu, çevreye özgü tüm değerleri ayrı bir açısal modüle ayırmak olabilir:

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

O zaman bu girişlere ihtiyaç duyan modülleriniz buna bağımlı olabilir:

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

Şimdi daha havalı şeyler düşünebilirsiniz:

Konfigürasyonu içeren modül, sayfanıza eklenecek configuration.js'ye ayrılabilir.

Bu komut dosyasını, ayrı bir dosyayı git olarak işaretlemediğiniz sürece, her biriniz tarafından kolayca düzenlenebilir. Ancak yapılandırmanın ayrı bir dosyada olup olmadığını kontrol etmemek daha kolaydır. Ayrıca, yerel olarak şube olabilir.

Şimdi, ANT veya Maven gibi bir oluşturma sisteminiz varsa, sonraki adımlarınız, oluşturma sırasında belirli değerlerinizle değiştirilecek API_END_POINT değerleri için bazı yer tutucuları uygulamak olabilir.

Yoksa var senin configuration_a.jsve configuration_b.jsve içerecek şekilde arka uç konusunda karar.


30

İçin Gulp kullanıcı, yudum-ng sabit kombine de yararlıdır yudum concat , olay akışı ve 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() { });
});

Yapılandırma klasörümde şu dosyalar var:

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

Sonra çalıştırabilirsiniz gulp config --env developmentve bu böyle bir şey yaratacaktır:

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

Ayrıca bu spec var:

beforeEach(module('app'));

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

Bağımlılık dizisini yiv sabitiyle kaldırmanın bir yolu var mı? "NgAnimate" gibi sizin sabitlerime bağımlılığım yok. Bunu dahil etmezsem, angular.module ("my.module.config", []) olarak boş bir bağımlılık dizisi alıyorum ama angular.module ("my.module.config") olarak çıktı istiyorum. Yanaşma sabitinde herhangi bir seçenek görmüyorum ama ben deps geçebildiğini görüyorum: homurdanma sabit paketinde false. Herhangi bir yardım?
Arun Gopalpuri

17

Bunu başarmak için AngularJS Ortam Eklentisini kullanmanızı öneririm: https://www.npmjs.com/package/angular-environment

İşte bir örnek:

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

Ardından, denetleyicilerinizdeki değişkenleri şu şekilde çağırabilirsiniz:

envService.read('apiUrl');

Umarım yardımcı olur.


1
geliştirme ve üretim arasında nasıl geçiş yapar?
Mawg, Monica

Merhaba Juan Pablo ya da anladıysanız @Mawg. SO hakkında bir soru sormadan / Github ile ilgili bir konuyu gündeme getirmeden önce; angular-environmentçevreyi nasıl algılar? yani yerel makine / web sunucunuzda sırasıyla dev / prod olduğunu bilmesi için ne yapmanız gerekir?
StevieP

Dokümanların tekrar okunması ... " envServiceProvider.check()... verilen alanlara göre uygun ortamı otomatik olarak ayarlayacaktır". Bu yüzden mevcut etki alanını algılar ve ortamı uygun şekilde ayarlar - test etme zamanı!
StevieP

13

lvh.me:9000AngularJS uygulamanıza erişmek için kullanabilirsiniz ( lvh.mesadece 127.0.0.1'e işaret eder) ve ardından lvh.meana bilgisayar ise farklı bir uç nokta belirtebilirsiniz :

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

Ardından Yapılandırma hizmetini enjekte edin Configuration.APIve API'ya erişmek için ihtiyaç duyduğunuz her yerde kullanın :

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

Biraz hantal, ama biraz farklı bir durumda da olsa benim için iyi çalışıyor (API uç noktaları üretim ve geliştirmede farklıdır).


1
bu yüzden insanların sık sık karmaşık şeyler yaptığını düşünüyorum. Basit kullanımı window.location.hostbenim için fazlasıyla yeterliydi.
joseym

7

Bunun gibi bir şey de yapabiliriz.

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

    });

})();

Ve sizin controller/service, bağımlılığı enjekte edebilir ve erişilecek özellik ile get yöntemini çağırabiliriz.

(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') url'yi ana bilgisayar ortamına göre döndürür.


5

İyi soru!

Bir çözüm, config.xml dosyanızı kullanmaya devam etmek ve arka uçtan oluşturulan html'nize api uç noktası bilgilerini sağlamaktır (örneğin php'de):

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

Belki güzel bir çözüm değil, ama işe yarardı.

Başka bir çözüm, API_END_POINTsabit değeri üretimde olması gerektiği gibi tutmak ve ana bilgisayar dosyanızı yalnızca bu URL'yi yerel API'nize yönlendirecek şekilde değiştirmek olabilir.

Ya da belki localStorageböyle geçersiz kılmalar için bir çözüm :

.factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
   var myApi = localStorage.get('myLocalApiOverride');
   return $resource((myApi || API_END_POINT) + 'user');
});

Merhaba joakimbeng, ben noktayı açıklamak için php kullandığım çözüm yazdı. Biz saf bir RESTful java arka uç ile saf bir javascript istemci kodlamak için çalışıyoruz, bu yüzden php / js karışımı benim durumum değil ve ayrıca php yazarken her zaman php ve js karışık değil tutmak çalışın. ama cevap için teşekkürler. Bence @kfis yanıt çözümü işe yarayabilir: bir yapılandırma modülü içeren sürüm denetimi altında olmayan bir configuration.js dosyası. Bu yaklaşımla, gerekirse test amaçlı farklı bir yapılandırma modülü de enjekte edebilir / yükleyebilirim. Teşekkürler beyler.
rbarilani

@ hal9087 Karıştırma dilleri kısmı hakkında tamamen katılıyorum, ne pahasına olursa olsun kaçınılmalıdır :) Ben de configuration.js çözümünü beğendim, benzer bir şeye ihtiyacım olduğunda bunu aklımda tutacağım!
joakimbeng

4

İş parçacığına çok geç, ancak Açısal öncesi kullandığım bir teknik, JSON ve JS'nin toplama anahtarlarına dinamik olarak başvurma ve ortamın devredilemez gerçeklerini (ana makine sunucusu adı, geçerli tarayıcı dili) kullanma esnekliğinden yararlanmaktır. vb.) bir JSON veri yapısı içinde sonlandırılmış anahtar adlarını seçici olarak ayırmak / tercih etmek için girişler olarak.

Bu, yalnızca dağıtım ortamı bağlamını (OP başına) değil, aynı anda ve (ideal olarak) tek bir yapılandırma bildirimi içinde, çoğaltma olmadan ve net bir şekilde gerekli olan i18n veya diğer varyansları sağlamak için herhangi bir keyfi bağlam (dil gibi) sağlar.

10 LINES VANILLA JS HAKKINDA

Aşırı basitleştirilmiş ancak klasik örnek: JSON biçimli özellikler dosyasındaki, ana makine sunucusunun (natch) da değişeceği ortama göre değişen bir API uç noktası temel URL'si:

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

Ayrımcılık işlevinin anahtarı, istekte bulunan sunucu ana bilgisayar adıdır.

Bu, doğal olarak, kullanıcının dil ayarlarına bağlı olarak ek bir anahtarla birleştirilebilir:

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

Ayrımcılık / tercih kapsamı, "temel" anahtarın yalnızca işleve veya tüm yapının girişleri için eşleşen bir anahtar + sonek varsa ve bu yapının kendisinin üzerine yazıldığı ayrı tuşlarla (yukarıdaki gibi) sınırlandırılabilir. ayrımcılık / tercih soneklerini eşleştirmek için özyinelemeli olarak ayrıştırılır:

    'help': {
        'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
        'PHONE': '808-867-5309',
        'EMAIL': 'coder.jen@lostnumber.com'
    },
    'help@www.productionwebsite.com': {
        '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': 'customer.service@productionwebsite.com'
    },

Dolayısıyla, üretim web sitesini ziyaret eden bir kullanıcının Almanca ( de ) dil tercihi ayarı varsa, yukarıdaki yapılandırma şu şekilde daraltılır:

    'help': {
        'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': 'customer.service@productionwebsite.com'
    },

Böyle büyülü bir tercih / ayrımcılık JSON-yeniden yazma işlevi neye benziyor? Fazla değil:

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

    };
};

Açısal ve Açısal web sitelerini içeren uygulamalarımızda, JSON'u tercihli () işlevi dahil olmak üzere kendi kendini yürüten bir JS kapanışına yerleştirerek ve ana bilgisayar adı ve dil kodu (ve ihtiyacınız olabilecek ek isteğe bağlı ekleri kabul eder):

(function(prefs){ var props = {
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
        'API@www.productionwebsite.com': '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])  ] );

Açısal olmayan bir sitenin artık daraltılmış (@ soneki anahtar yok) window.app_props ifadesi olacaktır.

Açısal bir site, bir bootstrap / init adımı olarak, ölü bırakılan sahne nesnesini $ rootScope'a kopyalar ve (isteğe bağlı olarak) global / pencere kapsamından yok eder

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

daha sonra kontrolörlere enjekte edilecek:

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

veya görünümlerde ciltlerden bahsedilir:

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

Uyarılar? @ Karakteri geçerli JS / JSON değişkeni / anahtar adlandırması değil, şimdiye kadar kabul edildi. Bu bir anlaşma kırıcı ise, "__" (çift alt çizgi) gibi herhangi bir konvansiyonun yerine sadık kaldığınız sürece kullanın.

Teknik, sunucu tarafında uygulanabilir, Java veya C # 'a taşınabilir, ancak verimliliğiniz / kompaktlığınız değişebilir.

Alternatif olarak, işlev / kural, ön uç derleme komut dosyanızın bir parçası olabilir, böylece tam kanlı tüm ortam / tüm dilde JSON kablo üzerinden iletilmez.

GÜNCELLEME

Bu tekniğin bir anahtara birden çok sonek vermesine izin vermek, koleksiyonları kullanmaya zorlanmaktan kaçınmak için (yine de istediğiniz kadar derinlemesine yapabilirsiniz) ve tercih edilen eklerin sırasını onurlandırmak için bu tekniği kullandık.

Örnek (ayrıca bkz. Çalışan jsFiddle ):

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 (temel kullanım) '@dev' tuşlarını tercih eder, diğer tüm eklenmiş tuşları atar

3 '@fr' yerine '@dev', diğerlerini '' dev & fr 'tercih eder

4 (3 ile aynı ancak '@dev' yerine '@fr' tercih eder)

5 tercih edilen ek yok, TÜM ekli özellikleri düşürüyor

Bunu, her bir ekli mülkü puanlayarak ve ekler üzerinde bir özelliğin değerini, özellikler üzerinde yineleme yaparken ve daha yüksek puanlı bir sonek bulurken ekli olmayan özelliğe yükselterek gerçekleştirir.

JSON'a derin kopyalamaya bağımlılığı kaldırmak ve yalnızca derinlemesine puanlama turunda hayatta kalan nesnelere yineleme dahil olmak üzere bu sürümdeki bazı verimlilikler:

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


-8

Bu soruyu ve cevabını gördünüz mü ?

Uygulamanız için şu şekilde global olarak geçerli bir değer ayarlayabilirsiniz:

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

ve ardından hizmetlerinizde kullanın. Bu kodu bir config.js dosyasına taşıyabilir ve sayfa yüklemesinde veya başka bir uygun zamanda çalıştırabilirsiniz.


7
Birisi bunun neden bu kadar kötü bir cevap olduğunu açıklayabilir mi? Büyük ölçüde indirildi, ancak tek bir yorum değil ...
aendrew

5
Bu cehennem kadar eski, ancak neden aşağı oyları tahmin etmek zorunda kalsaydım, bunun nedeni ortama özgü yapılandırmalar sorununu çözmemesi, herhangi bir eski uygulamada global bir değer ayarlamak için .value () kullanılması için bir öneri. Env'ye veya orijinal soru parametreleri boyunca herhangi bir şeye bağlı olarak bunun nasıl kullanılacağından bahsedilmez.
coblr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.