Đặt biến môi trường trong phản ứng gốc?


152

Tôi đang sử dụng Reac -igen để xây dựng một ứng dụng đa nền tảng, nhưng tôi không biết cách đặt biến môi trường để tôi có thể có các hằng số khác nhau cho các môi trường khác nhau.

Thí dụ:

development: 
  BASE_URL: '',
  API_KEY: '',
staging: 
  BASE_URL: '',
  API_KEY: '',
production:
  BASE_URL: '',
  API_KEY: '',

bạn có thể thử điều nàyimport {Platform} from 'react-native'; console.log(Platform);
Praveen Prasad

Câu trả lời:


138

Thay vì mã hóa cứng các hằng số ứng dụng của bạn và thực hiện chuyển đổi môi trường (tôi sẽ giải thích cách thực hiện điều đó ngay lập tức), tôi khuyên bạn nên sử dụng đề xuất mười hai yếu tố để quy trình xây dựng của bạn xác định BASE_URLvà của bạn API_KEY.

Để trả lời cách phơi bày môi trường của bạn react-native, tôi khuyên bạn nên sử dụng các biến babel-plugin-Transform-inline-môi trường-biến của Babel .

Để làm việc này, bạn cần tải xuống plugin và sau đó bạn sẽ cần phải thiết lập một .babelrcvà nó sẽ trông giống như thế này:

{
  "presets": ["react-native"],
  "plugins": [
    "transform-inline-environment-variables"
  ]
}

Và vì vậy, nếu bạn dịch mã mã gốc phản ứng của mình bằng cách chạy API_KEY=my-app-id react-native bundle(hoặc start, run-ios hoặc run-android) thì tất cả những gì bạn phải làm là để mã của bạn trông như thế này:

const apiKey = process.env['API_KEY'];

Và sau đó Babel sẽ thay thế bằng:

const apiKey = 'my-app-id';

Hi vọng điêu nay co ich!


7
Nghe có vẻ là giải pháp tuyệt vời, nhưng không hiệu quả với tôi tại RN@0.37.0. Tài sản duy nhất trên process.envNODE_ENV.
Adam Faryna

2
Xem câu trả lời dưới đây của Jack Zheng ... bạn không thể truy cập vào biến qua process.env.API_KEY... sử dụng process.env['API_KEY']thay thế
Steven Yap

6
Tôi nhận được process.env ['API_KEY'] là không xác định. Ai đó có thể giúp tôi thiết lập cái này không
user1106888

2
Tôi có cùng một vấn đề: không xác định
Guto Marrara Marzagao

7
Làm việc cho tôi trong v0.56. Bạn phải xóa bộ đệm của bộ đệm bằng cách chạy react-native start --reset-cachemỗi khi bạn thay đổi các biến môi trường.
soheilpro

55

Giải pháp đơn giản nhất (không phải là tốt nhất hoặc lý tưởng ) mà tôi tìm thấy là sử dụng Reac -igen-dotenv . Bạn chỉ cần thêm cài đặt trước "Reac -igen-dotenv" vào .babelrctệp của bạn tại thư mục gốc của dự án như sau:

{
  "presets": ["react-native", "react-native-dotenv"]
}

Tạo một .envtệp và thêm thuộc tính:

echo "SOMETHING=anything" > .env

Sau đó, trong dự án của bạn (JS):

import { SOMETHING } from 'react-native-dotenv'
console.log(SOMETHING) // "anything"

1
Tôi đã hy vọng cho một giải pháp dựa trên .env. Cảm ơn bạn!
Anshul Koka

3
@Slavo Vojacek Làm cách nào để sử dụng cấu hình này cho ví dụ một base_urlcho cả hai stagingproduction?
Compaq LE2202x

@ CompaqLE2202x Tôi không chắc là tôi hiểu? Bạn đang hỏi về việc sử dụng các .envtệp khác nhau (trên mỗi môi trường) hoặc về việc sử dụng lại một số giá trị của bạn trong các .envtệp khác nhau , vì vậy bạn không sao chép chúng qua, nói, Phân đoạn và Sản xuất?
Slavo Vojacek 17/03/18

5
@SlavoVojacek Tôi đang hỏi về các .envtệp khác nhau cho mỗi môi trường, hãy nói stagingproduction.
Compaq LE2202x

@SlavoVojacek bạn không thể ghi đè lên các giá trị trong giai đoạn CI hoặc khi triển khai?
mgamsjager

37

Theo tôi, lựa chọn tốt nhất là sử dụng Reac -igen-config . Nó hỗ trợ 12 yếu tố .

Tôi thấy gói này cực kỳ hữu ích. Bạn có thể thiết lập nhiều môi trường, ví dụ như phát triển, dàn dựng, sản xuất.

Trong trường hợp của Android, các biến cũng có sẵn trong các lớp Java, gradle, AndroidManifest.xml, v.v. Trong trường hợp của iOS, các biến cũng có sẵn trong các lớp Obj-C, Info.plist.

Bạn chỉ cần tạo tập tin như

  • .env.development
  • .env.staging
  • .env.production

Bạn điền các tệp này bằng khóa, các giá trị như

API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh

và sau đó chỉ cần sử dụng nó:

import Config from 'react-native-config'

Config.API_URL  // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY  // 'abcdefgh'

Nếu bạn muốn sử dụng các môi trường khác nhau, về cơ bản, bạn đặt biến ENVFILE như thế này:

ENVFILE=.env.staging react-native run-android

hoặc để lắp ráp ứng dụng cho sản xuất (android trong trường hợp của tôi):

cd android && ENVFILE=.env.production ./gradlew assembleRelease

9
Có thể đáng lưu ý rằng trong README, nó ghi nhớ mô-đun này không làm xáo trộn hoặc mã hóa bí mật cho bao bì, vì vậy đừng lưu trữ các khóa nhạy cảm trong .env. Về cơ bản, không thể ngăn người dùng thực hiện các bí mật ứng dụng di động kỹ thuật đảo ngược, vì vậy hãy thiết kế ứng dụng (và API) của bạn với ý nghĩ đó
Marklar

Điều đó là nó sẽ không hoạt động với một số khung như twitter yêu cầu phải đặt khóa là com.twitter.sdk.android.CONSUMER_KEY trong .env
thibaut noah

Nếu bạn muốn đặt chìa khóa bên trong Bản kê khai, tiện ích mở rộng hỗ trợ nó. Nó chỉ không được mô tả trong câu trả lời này. Bạn có thể sử dụng các biến trong các tệp XML, Java và JS.
sfratini

4
Reac -igen-config không hoạt động với RN 0.56, nó có các vấn đề chưa được giải quyết và nó không được làm rõ trong hơn 6 tháng. Vấn đề phù thủy giết chết việc sử dụng nó trong RN là github.com/luggit/react-native-config/issues/267 , đây là một số hack để làm cho nó hoạt động github.com/luggit/react-native-config/issues/285
Marecky

24

React bản địa không có khái niệm về các biến toàn cục. Nó thực thi nghiêm ngặt phạm vi mô-đun , để thúc đẩy mô-đun thành phần và tái sử dụng.

Đôi khi, mặc dù, bạn cần các thành phần để nhận thức được môi trường của họ. Trong trường hợp này, rất đơn giản để xác định một Environmentmô-đun mà các thành phần sau đó có thể gọi để lấy các biến môi trường, ví dụ:

môi trường

var _Environments = {
    production:  {BASE_URL: '', API_KEY: ''},
    staging:     {BASE_URL: '', API_KEY: ''},
    development: {BASE_URL: '', API_KEY: ''},
}

function getEnvironment() {
    // Insert logic here to get the current platform (e.g. staging, production, etc)
    var platform = getPlatform()

    // ...now return the correct environment
    return _Environments[platform]
}

var Environment = getEnvironment()
module.exports = Environment

my-thành phần.js

var Environment = require('./environment.js')

...somewhere in your code...
var url = Environment.BASE_URL

Điều này tạo ra một môi trường đơn lẻ có thể được truy cập từ bất kỳ đâu trong phạm vi ứng dụng của bạn. Bạn phải rõ ràng require(...)mô-đun từ bất kỳ thành phần nào sử dụng biến môi trường, nhưng đó là một điều tốt.


19
vấn đề của tôi là làm thế nào để getPlatform(). Tôi đã tạo một tệp như thế này nhưng không thể hoàn thành logic ở đây trong React Native
Damon Yuan

@DamonYuan hoàn toàn phụ thuộc vào cách bạn thiết lập các gói của mình. Tôi không biết ý nghĩa staginghay productionthậm chí là gì, vì nó phụ thuộc vào môi trường của bạn. Ví dụ, nếu bạn muốn hương vị khác nhau cho IOS vs Android thì bạn có thể khởi tạo môi trường bằng cách nhập nó của bạn index.ios.jsindex.android.jscác tập tin và thiết lập nền tảng đó, ví dụ Environment.initialize('android').
tohster

@DamonYuan làm những gì tôi giúp đỡ, hoặc bạn cần làm rõ thêm?
chapinkapa

Điều này là rất tốt khi bạn có quyền kiểm soát mã. Tôi đang chạy một mô-đun phần thứ ba dựa trên process.env, vì vậy ...
enapupe

2
Nếu bạn tạo một env.jstệp, hãy chắc chắn bỏ qua nó từ đăng ký vào kho lưu trữ và sao chép các khóa được sử dụng, với các giá trị chuỗi trống, vào một env.js.exampletệp khác mà bạn đăng ký để người khác có thể xây dựng ứng dụng của bạn dễ dàng hơn. Nếu bạn vô tình kiểm tra các bí mật dự án, hãy xem xét viết lại lịch sử để loại bỏ chúng không chỉ khỏi nguồn mà cả lịch sử của nó.
Josh Habdas

17

Tôi đã sử dụng __DEV__polyfill được tích hợp sẵn để phản ứng để giải quyết vấn đề này. Nó được tự động đặt thành truemiễn là bạn không xây dựng phản ứng tự nhiên cho sản xuất.

Ví dụ:

//vars.js

let url, publicKey;
if (__DEV__) {
  url = ...
  publicKey = ...
} else {
  url = ...
  publicKey = ...
}

export {url, publicKey}

Sau đó, chỉ import {url} from '../vars'và bạn sẽ luôn luôn có được một cái chính xác. Thật không may, điều này sẽ không hoạt động nếu bạn muốn có nhiều hơn hai môi trường, nhưng nó dễ dàng và không liên quan đến việc thêm nhiều phụ thuộc vào dự án của bạn.


Bạn có biết một cách để 'foce' DEV thành TRUE ngay cả khi tạo bản phát hành xây dựng trong xcode không?
realtebo

1
Không. Tôi chỉ nhận xét các vars prod và sau đó sao chép dán vars dev vào phần prod khi tôi muốn thực hiện một bản phát hành với các biến dev.
Logister

1
Tôi thấy đây là giải pháp tao nhã nhất
Dani Sh90

5

Phương pháp cụ thể được sử dụng để đặt biến môi trường sẽ thay đổi theo dịch vụ CI, cách tiếp cận xây dựng, nền tảng và công cụ bạn đang sử dụng.

Nếu bạn đang sử dụng Buddybuild cho CI để xây dựng ứng dụng và quản lý các biến môi trường và bạn cần truy cập để định cấu hình từ JS, hãy tạo một env.js.examplekhóa (có giá trị chuỗi trống) để đăng ký để kiểm soát nguồn và sử dụng Buddybuild để tạo env.jstệp tại thời điểm xây dựng trong post-clonebước, ẩn nội dung tệp khỏi nhật ký bản dựng, như vậy:

#!/usr/bin/env bash

ENVJS_FILE="$BUDDYBUILD_WORKSPACE/env.js"

# Echo what's happening to the build logs
echo Creating environment config file

# Create `env.js` file in project root
touch $ENVJS_FILE

# Write environment config to file, hiding from build logs
tee $ENVJS_FILE > /dev/null <<EOF
module.exports = {
  AUTH0_CLIENT_ID: '$AUTH0_CLIENT_ID',
  AUTH0_DOMAIN: '$AUTH0_DOMAIN'
}
EOF

Mẹo: Đừng quên thêm env.jsvào.gitignore để cấu hình và các bí mật không được kiểm tra trong kiểm soát nguồn một cách tình cờ trong quá trình phát triển.

Sau đó, bạn có thể quản lý cách tệp được ghi bằng các biến Buddybuild như BUDDYBUILD_VARIANTSđể có quyền kiểm soát lớn hơn đối với cách cấu hình của bạn được tạo trong thời gian xây dựng.


Tổng thể tôi thích ý tưởng, nhưng env.js.examplephần này hoạt động như thế nào? giả sử tôi muốn khởi chạy ứng dụng trong môi trường địa phương. nếu env.jstệp của tôi nằm trong gitignore và env.js.exampleđược sử dụng làm phác thảo, env.js.examplethì đó không phải là một phần mở rộng JS hợp pháp, vì vậy tôi chỉ hơi bối rối về ý nghĩa của phần này
volk

@volk Tập env.js.exampletin nằm trong cơ sở mã như một tài liệu tham khảo, một nguồn sự thật kinh điển về những gì cấu hình khóa mà ứng dụng muốn tiêu thụ. Cả hai đều mô tả các khóa cần thiết để chạy ứng dụng, cũng như tên tệp dự kiến ​​một khi được sao chép và đổi tên. Mẫu này phổ biến trong các ứng dụng Ruby sử dụng đá quý dotenv , đây là nơi tôi nâng mẫu từ đó.
Josh Habdas

3

Tôi nghĩ rằng một cái gì đó giống như thư viện sau đây có thể giúp bạn giải quyết phần còn thiếu của câu đố, hàm getPl platform ().

https://github.com/joeferraro/react-native-env

const EnvironmentManager = require('react-native-env');

// read an environment variable from React Native
EnvironmentManager.get('SOME_VARIABLE')
  .then(val => {
    console.log('value of SOME_VARIABLE is: ', val);

  })
  .catch(err => {
    console.error('womp womp: ', err.message);
  });

Vấn đề duy nhất tôi thấy với điều này, đó là mã async. Có một yêu cầu kéo để hỗ trợ getSync. Kiểm tra nó quá.

https://github.com/joeferraro/react-native-env/pull/9


3
Upvote để cung cấp một phương pháp thay thế không được đề cập. Không một kích thước phù hợp với tất cả.
Josh Habdas

Req kéo asynch đã được hợp nhất trong
jcollum

5
Reac -igen-env không xuất hiện để hỗ trợ Android. Vấn đề ở đây là gì?
jcollum

3

tôi đã tạo một tập lệnh xây dựng trước cho cùng một vấn đề vì tôi cần một số điểm cuối api khác nhau cho các môi trường khác nhau

const fs = require('fs')

let endPoint

if (process.env.MY_ENV === 'dev') {
  endPoint = 'http://my-api-dev/api/v1'
} else if (process.env.MY_ENV === 'test') {
  endPoint = 'http://127.0.0.1:7001'
} else {
  endPoint = 'http://my-api-pro/api/v1'
}

let template = `
export default {
  API_URL: '${endPoint}',
  DEVICE_FINGERPRINT: Math.random().toString(36).slice(2)
}
`

fs.writeFile('./src/constants/config.js', template, function (err) {
  if (err) {
    return console.log(err)
  }

  console.log('Configuration file has generated')
})

Và tôi đã tạo ra một tùy chỉnh npm run scriptsđể thực thi Reac -igen ..

Gói của tôi

"scripts": {
    "start-ios": "node config-generator.js && react-native run-ios",
    "build-ios": "node config-generator.js && react-native run-ios --configuration Release",
    "start-android": "node config-generator.js && react-native run-android",
    "build-android": "node config-generator.js && cd android/ && ./gradlew assembleRelease",
    ...
}

Sau đó, trong các thành phần dịch vụ của tôi chỉ cần nhập tệp được tạo tự động:

import config from '../constants/config'

fetch(`${config.API_URL}/login`, params)

3

Bước 1: Tạo thành phần riêng biệt như thế này Tên thành phần: pagebase.js
Bước 2: Bên trong mã này sử dụng mã này

    export const BASE_URL = "http://192.168.10.10:4848/";
    export const API_KEY = 'key_token';

Bước 3: Sử dụng nó trong bất kỳ thành phần nào, để sử dụng nó trước tiên hãy nhập thành phần này sau đó sử dụng nó. Nhập nó và sử dụng nó:

        import * as base from "./pagebase";

        base.BASE_URL
        base.API_KEY

2

Tôi sử dụng babel-plugin-transform-inline-environment-variables.

Những gì tôi đã làm là đặt một tệp cấu hình trong S3 với các môi trường khác nhau của tôi.

s3://example-bucket/dev-env.sh
s3://example-bucket/prod-env.sh
s3://example-bucket/stage-env.sh

MACHI tập tin env:

FIRSTENV=FIRSTVALUE
SECONDENV=SECONDVALUE

Sau đó, tôi đã thêm một tập lệnh mới package.jsonđể chạy tập lệnh cho gói

if [ "$ENV" == "production" ]
then
  eval $(aws s3 cp s3://example-bucket/prod-env.sh - | sed 's/^/export /')
elif [ "$ENV" == "staging" ]
then
  eval $(aws s3 cp s3://example-bucket/stage-env.sh - | sed 's/^/export /')
else
  eval $(aws s3 cp s3://example-bucket/development-env.sh - | sed 's/^/export /')
fi

react-native start

Trong ứng dụng của bạn, bạn có thể sẽ có một tệp cấu hình có:

const FIRSTENV = process.env['FIRSTENV']
const SECONDENV = process.env['SECONDENV']

sẽ được thay thế bởi babel để:

const FIRSTENV = 'FIRSTVALUE'
const SECONDENV = 'SECONDVALUE'

HÃY NHỚ bạn phải sử dụng process.env['STRING']KHÔNG process.env.STRINGhoặc nó sẽ không chuyển đổi đúng cách.


REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly.Cảm ơn! Đây là một trong những chuyến đi cho tôi lên !!!
Steven Yap

1

[Nguồn] Từ những gì tôi tìm thấy, có vẻ như theo mặc định, chỉ có thể thực hiện các cấu hình sản xuất và phát triển (không có dàn dựng hoặc các môi trường khác) - đúng không?

Ngay bây giờ, tôi đã sử dụng tệp môi trường có thể được sử dụng để phát hiện các kênh phát hành expo và thay đổi các biến được trả về dựa trên đó, nhưng để xây dựng, tôi cần cập nhật biến không DEV được trả về để phân tầng hoặc sản phẩm:

import { Constants } from 'expo';
import { Platform } from 'react-native';
const localhost = Platform.OS === 'ios' ? 'http://localhost:4000/' : 'http://10.0.2.2:4000/';
const ENV = {
  dev: {
    apiUrl: localhost,
  },
  staging: {
    apiUrl: 'https://your-staging-api-url-here.com/'
  },
  prod: {
    apiUrl: 'https://your-prod-api-url-here.com/'
  },
}
const getEnvVars = (env = Constants.manifest.releaseChannel) => {
  // What is __DEV__ ?
  // This variable is set to true when react-native is running in Dev mode.
  // __DEV__ is true when run locally, but false when published.
  if (__DEV__) {
    return ENV.dev;
  } else {
    // When publishing to production, change this to `ENV.prod` before running an `expo build`
    return ENV.staging;
  }
}
export default getEnvVars;

Lựa chọn thay thế

Có ai có kinh nghiệm sử dụng Reac -igen-dotenv cho các dự án được xây dựng bằng expo không? Tôi rất thích nghe suy nghĩ của bạn

https://github.com/zetachang/react-native-dotenv


Bạn có thể xác định số lượng tên kênh phát hành như bạn muốn và kiểm tra tên để xác định biến môi trường của bạn. Nơi tôi thấy giới hạn là trong môi trường dev nơi phát hành kênh không xác định. Vì vậy, có lẽ bạn có thể sử dụng các biến babel-plugin-Transform-inline-môi trường - bạn có thể chuyển các biến môi trường trong tập lệnh và quy trình tham chiếu của mình.env ['VAR_NAME'] trong tệp môi trường của bạn nếu dev?
colemerrick

0

bạn cũng có thể có các tập lệnh env khác nhau: sản xuất.env.sh Development.env.sh sản xuất.env.sh

Và sau đó nguồn chúng vào khi bắt đầu hoạt động [chỉ gắn với bí danh], vì vậy tất cả các tệp sh có là xuất cho mỗi biến env:

export SOME_VAR=1234
export SOME_OTHER=abc

Và sau đó thêm các biến babel-plugin-Transform-inline-môi trường sẽ cho phép truy cập chúng trong mã:

export const SOME_VAR: ?string = process.env.SOME_VAR;
export const SOME_OTHER: ?string = process.env.SOME_OTHER;

Bạn có thêm bất cứ điều gì @chapinkapa chưa nói?
Maximo Toduez

0

Câu trả lời của chapinkapa là tốt. Một cách tiếp cận mà tôi đã thực hiện vì Trung tâm di động không hỗ trợ các biến môi trường, là hiển thị cấu hình bản dựng thông qua một mô-đun gốc:

Trên Android:

   @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        String buildConfig = BuildConfig.BUILD_TYPE.toLowerCase();
        constants.put("ENVIRONMENT", buildConfig);
        return constants;
    } 

hoặc trên ios:

  override func constantsToExport() -> [String: Any]! {
    // debug/ staging / release
    // on android, I can tell the build config used, but here I use bundle name
    let STAGING = "staging"
    let DEBUG = "debug"

    var environment = "release"
    if let bundleIdentifier: String = Bundle.main.bundleIdentifier {
      if (bundleIdentifier.lowercased().hasSuffix(STAGING)) {
        environment = STAGING
      } else if (bundleIdentifier.lowercased().hasSuffix(DEBUG)){
        environment = DEBUG
      }
    }

    return ["ENVIRONMENT": environment]
  }

Bạn có thể đọc cấu hình bản dựng một cách đồng bộ và quyết định trong Javascript cách bạn sẽ hành xử.


0

Có thể truy cập các biến với process.env.blablathay vì process.env['blabla']. Gần đây tôi đã làm cho nó hoạt động và nhận xét về cách tôi đã làm nó trên một vấn đề trên GitHub vì tôi có một số vấn đề với bộ đệm dựa trên câu trả lời được chấp nhận. Đây là vấn đề.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.