ضبط البيئة


في كثير من الأحيان، ستحتاج إلى إعدادات إضافية لوظائفك، مثل مفاتيح واجهة برمجة التطبيقات التابعة لجهات خارجية أو الإعدادات القابلة للتعديل. توفّر حزمة تطوير البرامج (SDK) الخاصة بـ Firebase Cloud Functions إعدادات مدمجة للبيئة لتسهيل تخزين هذا النوع من البيانات واسترجاعه لمشروعك.

يمكنك الاختيار من بين الخيارات التالية:

  • الإعدادات المحدّدة المَعلمات (يُنصح بها في معظم السيناريوهات) يوفّر ذلك إعدادات بيئة ذات أنواع محددة بوضوح مع مَعلمات يتم التحقّق من صحتها في وقت النشر، ما يمنع حدوث أخطاء ويسهّل عملية تصحيح الأخطاء.
  • إعداد متغيّرات البيئة المستند إلى الملفات باستخدام هذا الأسلوب، يمكنك إنشاء ملف dotenv يدويًا لتحميل متغيرات البيئة.

في معظم حالات الاستخدام، يُنصح باستخدام الإعدادات التي تتضمّن مَعلمات. يتيح هذا الأسلوب توفُّر قيم الإعدادات أثناء وقت التشغيل ووقت النشر، كما يتم حظر النشر ما لم تتضمّن جميع المَعلمات قيمة صالحة. في المقابل، لا يتوفّر خيار الضبط باستخدام متغيّرات البيئة عند النشر.

الإعدادات التي تتضمّن مَعلمات

توفر Cloud Functions for Firebase واجهة لتحديد مَعلمات الضبط بشكل تصريحي داخل قاعدة الرموز البرمجية. تتوفّر قيمة هذه المَعلمات أثناء نشر الدالة، وعند ضبط خيارات النشر ووقت التشغيل، وأثناء التنفيذ. وهذا يعني أنّ واجهة سطر الأوامر ستمنع عملية النشر إلا إذا كانت جميع المَعلمات تتضمّن قيمة صالحة.

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineInt, defineString } = require('firebase-functions/params');

// Define some parameters
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")
WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

# To use configured parameters inside the config for a function, provide them
# directly. To use them at runtime, call .value() on them.
@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

عند نشر دالة تتضمّن متغيّرات إعداد ذات معلَمات، تحاول واجهة سطر الأوامر Firebase CLI أولاً تحميل قيمها من ملفات .env محلية. إذا لم تكن هذه المتغيرات متوفرة في تلك الملفات ولم يتم ضبط default، سيطلب منك واجهة سطر الأوامر إدخال القيم أثناء عملية النشر، ثم سيتم حفظ القيم تلقائيًا في ملف .env باسم .env.<project_ID> في الدليل functions/:

$ firebase deploy
i  functions: preparing codebase default for deployment
? Enter a string value for ENVIRONMENT: prod
i  functions: Writing new parameter values to disk: .env.projectId
…
$ firebase deploy
i  functions: Loaded environment variables from .env.projectId

استنادًا إلى سير عمل التطوير، قد يكون من المفيد إضافة ملف .env.<project_ID> الذي تم إنشاؤه إلى نظام التحكّم في الإصدارات.

استخدام المَعلمات في النطاق العام

أثناء عملية النشر، يتم تحميل رمز الدوال وفحصه قبل أن تتضمّن المَعلمات قيمًا فعلية. وهذا يعني أنّ جلب قيم المَعلمات أثناء نطاق عام يؤدي إلى تعذُّر النشر. في الحالات التي تريد فيها استخدام مَعلمة لإعداد قيمة عامة، استخدِم دالة معاودة الاتصال الخاصة بالإعداد onInit(). يتم تنفيذ هذه الدالة قبل تنفيذ أي دوال في مرحلة الإنتاج، ولكن لا يتم استدعاؤها أثناء وقت النشر، لذا فهي مكان آمن للوصول إلى قيمة المَعلمة.

Node.js

const { GoogleGenerativeAI } = require('@google/generative-ai');
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v2/core');

const apiKey = defineSecret('GOOGLE_API_KEY');

let genAI;
onInit(() => {
  genAI = new GoogleGenerativeAI(apiKey.value());
})

Python

from firebase_functions.core import init
from firebase_functions.params import StringParam, PROJECT_ID
import firebase_admin
import vertexai

location = StringParam("LOCATION")

x = "hello"

@init
def initialize():
  # Note: to write back to a global, you'll need to use the "global" keyword
  # to avoid creating a new local with the same name.
  global x
  x = "world"
  firebase_admin.initialize_app()
  vertexai.init(PROJECT_ID.value, location.value)

إذا كنت تستخدم مَعلمات من النوع Secret، يُرجى العِلم أنّها لا تتوفّر إلا في عملية الدوال التي تم ربط السر بها. إذا كان سرّ معيّن مرتبطًا ببعض الدوال فقط، تحقّق مما إذا كانت قيمة secret.value() غير صحيحة قبل استخدامه.

ضبط سلوك واجهة سطر الأوامر

يمكن ضبط المَعلمات باستخدام كائن Options يتحكّم في الطريقة التي سيطلب بها واجهة سطر الأوامر القيم. يضبط المثال التالي الخيارات للتحقّق من صحة تنسيق رقم الهاتف، ولتوفير خيار تحديد بسيط، ولتعبئة خيار التحديد تلقائيًا من مشروع Firebase:

Node.js

const { defineString } = require('firebase-functions/params');

const welcomeMessage = defineString('WELCOME_MESSAGE', {default: 'Hello World',
description: 'The greeting that is returned to the caller of this function'});

const onlyPhoneNumbers = defineString('PHONE_NUMBER', {
  input: {
    text: {
      validationRegex: /\d{3}-\d{3}-\d{4}/,
      validationErrorMessage: "Please enter
a phone number in the format XXX-YYY-ZZZZ"
    },
  },
});

const selectedOption = defineString('PARITY', {input: params.select(["odd", "even"])});

const memory = defineInt("MEMORY", {
  description: "How much memory do you need?",
  input: params.select({ "micro": 256, "chonky": 2048 }),
});

const extensions = defineList("EXTENSIONS", {
  description: "Which file types should be processed?",
  input: params.multiSelect(["jpg", "tiff", "png", "webp"]),
});

const storageBucket = defineString('BUCKET', {
  description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets",
  input: params.PICK_STORAGE_BUCKET,
});

Python

from firebase_functions.params import (
    StringParam,
    ListParam,
    TextInput,
    SelectInput,
    SelectOptions,
    ResourceInput,
    ResourceType,
)

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

WELCOME_MESSAGE = StringParam(
    "WELCOME_MESSAGE",
    default="Hello World",
    description="The greeting that is returned to the caller of this function",
)

ONLY_PHONE_NUMBERS = StringParam(
    "PHONE_NUMBER",
    input=TextInput(
        validation_regex="\d{3}-\d{3}-\d{4}",
        validation_error_message="Please enter a phone number in the format XXX-YYY-XXX",
    ),
)

SELECT_OPTION = StringParam(
    "PARITY",
    input=SelectInput([SelectOptions(value="odd"), SelectOptions(value="even")]),
)

STORAGE_BUCKET = StringParam(
    "BUCKET",
    input=ResourceInput(type=ResourceType.STORAGE_BUCKET),
    description="This will automatically populate the selector field with the deploying Cloud Project's storage buckets",
)

أنواع المَعلمات

توفّر الإعدادات المحدّدة المَعلمات كتابة قوية لقيم المَعلمات، كما تتيح استخدام الأسرار من Cloud Secret Manager. الأنواع المتوافقة هي:

  • سري
  • سلسلة
  • قيمة منطقية
  • عدد صحيح
  • عائم
  • القائمة (Node.js)

قيم المَعلمات والعبارات

يقيّم Firebase المَعلمات في وقت النشر وأثناء تنفيذ الدالة. ونظرًا إلى هذه البيئات المزدوجة، يجب توخّي الحذر عند مقارنة قيم المَعلمات وعند استخدامها لضبط خيارات وقت التشغيل للدوال.

لتمرير مَعلمة إلى الدالة كخيار وقت تشغيل، مرِّرها مباشرةً:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineInt } = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO\_WORLD\_MININSTANCES');

export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
  (req, res) => {
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

بالإضافة إلى ذلك، إذا كنت بحاجة إلى إجراء مقارنة مع مَعلمة لمعرفة الخيار الذي يجب اختياره، عليك استخدام أدوات المقارنة المضمّنة بدلاً من التحقّق من القيمة:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const environment = params.defineString(ENVIRONMENT, {default: 'dev'});

// use built-in comparators
const minInstancesConfig = environment.equals('PRODUCTION').thenElse(10, 1);
export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
  (req, res) => {
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

ENVIRONMENT = StringParam("ENVIRONMENT", default="dev")
MIN_INSTANCES = ENVIRONMENT.equals("PRODUCTION").then(10, 0)

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

يمكن الوصول إلى المَعلمات وتعبيرات المَعلمات التي يتم استخدامها فقط في وقت التشغيل باستخدام الدالة value الخاصة بها:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = onRequest(
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import StringParam

WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

@https_fn.on_request()
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

المَعلمات المضمَّنة

تقدّم حزمة تطوير البرامج (SDK) الخاصة بـ Cloud Functions ثلاث مَعلمات محدّدة مسبقًا، وهي متاحة من الحزمة الفرعية firebase-functions/params:

Node.js

  • projectID: مشروع Cloud الذي يتم تشغيل الدالة فيه.
  • databaseURL: عنوان URL لمثيل Realtime Database المرتبط بالدالة (في حال تفعيلها في مشروع Firebase)
  • storageBucket: حزمة Cloud Storage المرتبطة بالدالة (في حال تفعيلها في مشروع Firebase)

Python

  • PROJECT_ID: مشروع Cloud الذي يتم تشغيل الدالة فيه.
  • DATABASE_URL: عنوان URL لمثيل Realtime Database المرتبط بالدالة (في حال تفعيلها في مشروع Firebase)
  • STORAGE_BUCKET: حزمة Cloud Storage المرتبطة بالدالة (في حال تفعيلها في مشروع Firebase)

تعمل هذه الدوال مثل مَعلمات السلسلة التي يحددها المستخدم من جميع النواحي، باستثناء أنّه بما أنّ قيمها معروفة دائمًا لواجهة سطر الأوامر (CLI) في Firebase، لن يُطلب إدخال قيمها عند النشر ولن يتم حفظها في ملفات .env.

المَعلمات السرية

تمثّل المَعلمات من النوع Secret، والمحدّدة باستخدام defineSecret()، مَعلمات السلسلة التي يتم تخزين قيمتها في Cloud Secret Manager. بدلاً من التحقّق من ملف .env محلي وكتابة قيمة جديدة في الملف في حال عدم توفّره، تتحقّق مَعلمات المفتاح السرّي من توفّرها في Cloud Secret Manager، وتطلب بشكل تفاعلي قيمة مفتاح سرّي جديد أثناء عملية النشر.

يجب ربط المَعلمات السرية المحدّدة بهذه الطريقة بوظائف فردية يجب أن يكون لديها إذن الوصول إليها:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineSecret } = require('firebase-functions/params');
const discordApiKey = defineSecret('DISCORD_API_KEY');

export const postToDiscord = onRequest(
  { secrets: [discordApiKey] },
  (req, res) => {
  const apiKey = discordApiKey.value();
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import SecretParam

DISCORD_API_KEY = SecretParam('DISCORD_API_KEY')

@https_fn.on_request(secrets=[DISCORD_API_KEY])
def post_to_discord(req):
    api_key = DISCORD_API_KEY.value

بما أنّ قيم الأسرار تكون مخفية إلى حين تنفيذ الدالة، لا يمكنك استخدامها أثناء ضبط الدالة.

متغيّرات البيئة

تتيح Cloud Functions for Firebase استخدام تنسيق ملف dotenv لتحميل متغيرات البيئة المحدّدة في ملف .env إلى وقت تشغيل التطبيق. بعد نشرها، يمكن قراءة متغيرات البيئة من خلال واجهة process.env (في المشاريع المستندة إلى Node.js) أو os.environ (في المشاريع المستندة إلى Python).

لضبط بيئتك بهذه الطريقة، أنشئ ملف .env في مشروعك، وأضِف المتغيرات المطلوبة، ثم نفِّذ عملية النشر:

  1. أنشئ ملف .env في دليل functions/:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. افتح ملف .env للتعديل، وأضِف المفاتيح المطلوبة. على سبيل المثال:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. نشر الدوال والتحقّق من تحميل متغيّرات البيئة:

    firebase deploy --only functions
    # ...
    # i functions: Loaded environment variables from .env.
    # ...
    

بعد نشر متغيّرات البيئة المخصّصة، يمكن لرمز الدالة الوصول إليها:

Node.js

// Responds with "Hello Earth and Humans"
exports.hello = onRequest((request, response) => {
  response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});

Python

import os

@https_fn.on_request()
def hello(req):
    return https_fn.Response(
        f"Hello {os.environ.get('PLANET')} and {os.environ.get('AUDIENCE')}"
    )

نشر مجموعات متعدّدة من متغيّرات البيئة

إذا كنت بحاجة إلى مجموعة بديلة من متغيرات البيئة لمشاريع Firebase (مثل مرحلة الاختبار مقابل مرحلة الإنتاج)، أنشئ ملف .env.<project or alias> واكتب فيه متغيرات البيئة الخاصة بمشروعك. سيتم تضمين متغيّرات البيئة من الملفين .env و.env الخاصين بالمشروع (إذا كانا متوفّرين) في جميع الدوال التي تم نشرها.

على سبيل المثال، يمكن أن يتضمّن المشروع الملفات الثلاثة التالية التي تحتوي على قيم مختلفة قليلاً للتطوير والإنتاج:

.env .env.dev .env.prod
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

وبالنظر إلى القيم في هذه الملفات المنفصلة، ستختلف مجموعة متغيرات البيئة التي يتم نشرها مع الدوال حسب المشروع المستهدف:

$ firebase use dev
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.dev.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Dev Humans

$ firebase use prod
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.prod.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Prod Humans

متغيرات البيئة المحجوزة

بعض مفاتيح متغيرات البيئة محجوزة للاستخدام الداخلي. لا تستخدِم أيًا من المفاتيح التالية في ملفات .env:

  • جميع المفاتيح التي تبدأ بـ X_GOOGLE_
  • جميع المفاتيح التي تبدأ بـ EXT_
  • جميع المفاتيح التي تبدأ بـ FIREBASE_
  • أي مفتاح من القائمة التالية:
  • CLOUD_RUNTIME_CONFIG
  • ENTRY_POINT
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • GOOGLE_CLOUD_PROJECT
  • FUNCTION_TRIGGER_TYPE
  • FUNCTION_NAME
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • FUNCTION_IDENTITY
  • FUNCTION_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICE
  • K_REVISION
  • PORT
  • K_CONFIGURATION

تخزين معلومات الإعدادات الحساسة والوصول إليها

يمكن استخدام متغيّرات البيئة المخزّنة في ملفات .env لإعداد الدوال، ولكن لا يجب اعتبارها طريقة آمنة لتخزين المعلومات الحسّاسة، مثل بيانات اعتماد قاعدة البيانات أو مفاتيح واجهة برمجة التطبيقات. ويكون ذلك مهمًا بشكل خاص إذا كنت تتحقّق من ملفات .env في نظام التحكّم بالمصادر.

لمساعدتك في تخزين معلومات الإعدادات الحسّاسة، يتكامل Cloud Functions for Firebase مع Google Cloud Secret Manager. تخزّن هذه الخدمة المشفرة قيم الإعدادات بشكل آمن، مع السماح بالوصول إليها بسهولة من الدوال عند الحاجة.

إنشاء سر واستخدامه

لإنشاء سرّ، استخدِم واجهة سطر الأوامر Firebase.

لإنشاء سرّ واستخدامه، اتّبِع الخطوات التالية:

  1. من جذر دليل مشروعك المحلي، نفِّذ الأمر التالي:

    firebase functions:secrets:set SECRET_NAME

  2. أدخِل قيمة لـ SECRET_NAME.

    تعرض واجهة سطر الأوامر رسالة نجاح وتحذّر من أنّه يجب نشر الدوال لكي يسري التغيير.

  3. قبل النشر، تأكَّد من أنّ رمز الدوال يسمح للدالة بالوصول إلى كلمة المرور السرية باستخدام المَعلمة runWith:

    Node.js

    const { onRequest } = require('firebase-functions/v2/https');
    
    exports.processPayment = onRequest(
      { secrets: ["SECRET_NAME"] },
      (req, res) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      }
    );

    Python

    import os
    from firebase_functions import https_fn
    
    @https_fn.on_request(secrets=["SECRET_NAME"])
    def process_payment(req):
        myBillingService = initialize_billing(key=os.environ.get('SECRET_NAME'))
        # Process the payment
        ...
    
  4. نشر Cloud Functions:

    firebase deploy --only functions

    يمكنك الآن الوصول إليها مثل أي متغير بيئة آخر. في المقابل، إذا حاولت دالة أخرى لا تحدّد كلمة المرور في runWith الوصول إلى كلمة المرور، ستتلقّى قيمة غير محدّدة:

    Node.js

    exports.anotherEndpoint = onRequest((request, response) => {
      response.send(`The secret API key is ${process.env.SECRET_NAME}`);
      // responds with "The secret API key is undefined" because the `runWith` parameter is missing
    });
    

    Python

    @https_fn.on_request()
    def another_endpoint(req):
        return https_fn.Response(f"The secret API key is {os.environ.get("SECRET_NAME")}")
        # Responds with "The secret API key is None" because the `secrets` parameter is missing.
    

بعد نشر الدالة، سيصبح بإمكانها الوصول إلى قيمة كلمة المرور. فقط الدوال التي تتضمّن سرًا في المَعلمة runWith ستتمكّن من الوصول إلى هذا السر كمتغيّر بيئة. يساعدك ذلك في التأكّد من أنّ قيم الأسرار متاحة فقط عند الحاجة إليها، ما يقلّل من خطر تسريب سرّ عن طريق الخطأ.

إدارة المفاتيح السرية

استخدِم واجهة سطر الأوامر Firebase لإدارة أسرارك. أثناء إدارة الأسرار بهذه الطريقة، يُرجى العِلم أنّ بعض التغييرات في واجهة سطر الأوامر تتطلّب تعديل و/أو إعادة نشر الدوال المرتبطة. على وجه التحديد:

  • عندما تحدّد قيمة جديدة لمفتاح سرّي، عليك إعادة نشر جميع الدوال التي تشير إلى هذا المفتاح السرّي لكي تستخدم أحدث قيمة.
  • إذا حذفت سرًا، تأكَّد من أنّ أيًا من الدوال التي تم نشرها لا يشير إلى هذا السر. ستتعذّر الدوال التي تستخدم قيمة سرية تم حذفها بدون إظهار أي رسالة خطأ.

في ما يلي ملخّص لأوامر واجهة سطر الأوامر Firebase لإدارة الأسرار:

# Change the value of an existing secret
firebase functions:secrets:set SECRET_NAME

# View the value of a secret
functions:secrets:access SECRET_NAME

# Destroy a secret
functions:secrets:destroy SECRET_NAME

# View all secret versions and their state
functions:secrets:get SECRET_NAME

# Automatically clean up all secrets that aren't referenced by any of your functions
functions:secrets:prune

بالنسبة إلى الأمرَين access وdestroy، يمكنك تقديم مَعلمة الإصدار الاختيارية لإدارة إصدار معيّن. على سبيل المثال:

functions:secrets:access SECRET_NAME[@VERSION]

لمزيد من المعلومات حول هذه العمليات، أضِف -h إلى الأمر لعرض مساعدة واجهة سطر الأوامر.

كيفية احتساب تكلفة المفاتيح السرية

تسمح Secret Manager بـ 6 إصدارات نشطة من الأسرار بدون أي تكلفة. يعني ذلك أنّه يمكنك الحصول على 6 أسرار شهريًا في مشروع Firebase بدون أي تكلفة.

يحاول Firebase CLI تلقائيًا حذف إصدارات المفتاح السري غير المستخدَمة عند الاقتضاء، مثلاً عند نشر دوال باستخدام إصدار جديد من المفتاح السري. يمكنك أيضًا إزالة الأسرار غير المستخدَمة بشكل نشط باستخدام functions:secrets:destroy وfunctions:secrets:prune.

تسمح Secret Manager بإجراء 10,000 عملية وصول شهرية غير مدفوعة التكلفة إلى سر. لا تقرأ مثيلات الدوال سوى الأسرار المحدّدة في المَعلمة runWith في كل مرة تبدأ فيها التشغيل البارد. إذا كان لديك الكثير من مثيلات الدوال التي تقرأ الكثير من الأسرار، قد يتجاوز مشروعك هذا الحدّ المسموح به، وفي هذه الحالة، سيتم تحصيل 0.03 دولار أمريكي مقابل كل 10,000 عملية وصول.

لمزيد من المعلومات، يُرجى الاطّلاع على Secret Manager الأسعار.

التوافق مع المحاكي

تم تصميم إعدادات البيئة باستخدام dotenv لتعمل مع Cloud Functions محاكي محلي.

عند استخدام محاكي Cloud Functions محلي، يمكنك تجاهل متغيرات البيئة لمشروعك من خلال إعداد ملف .env.local. يكون لمحتوى .env.local الأولوية على .env وملف .env الخاص بالمشروع.

على سبيل المثال، يمكن أن يتضمّن المشروع الملفات الثلاثة التالية التي تحتوي على قيم مختلفة قليلاً للتطوير والاختبار المحلي:

.env .env.dev .env.local
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

عند بدء المحاكي في السياق المحلي، يتم تحميل متغيرات البيئة كما هو موضّح أدناه:

  $ firebase emulators:start
  i  emulators: Starting emulators: functions
  # Starts emulator with following environment variables:
  #  PLANET=Earth
  #  AUDIENCE=Local Humans

الأسرار وبيانات الاعتماد في محاكي Cloud Functions

يتيح محاكي Cloud Functions استخدام الأسرار من أجل تخزين معلومات الضبط الحساسة والوصول إليها. سيحاول المحاكي تلقائيًا الوصول إلى أسرار الإصدار العلني باستخدام بيانات الاعتماد التلقائية للتطبيق. في حالات معيّنة، مثل بيئات التكامل المستمر، قد يتعذّر على المحاكي الوصول إلى قيم الأسرار بسبب قيود الأذونات.

على غرار إتاحة محاكي Cloud Functions لمتغيرات البيئة، يمكنك إلغاء قيم الأسرار من خلال إعداد ملف .secret.local. يسهّل ذلك عليك اختبار الدوال محليًا، خاصةً إذا لم يكن لديك إذن بالوصول إلى قيمة المفتاح السري.

نقل البيانات من إعدادات البيئة

إذا كنت تستخدم إعدادات البيئة مع functions.config، يمكنك نقل الإعدادات الحالية كمتغيّرات بيئية (بتنسيق dotenv). توفّر واجهة سطر الأوامر Firebase أمر تصدير يعرض إعدادات كل اسم مستعار أو مشروع مُدرَج في ملف .firebaserc الخاص بدليلك (في المثال أدناه، local وdev وprod) كملفات .env.

لنقل البيانات، عليك تصدير إعدادات البيئة الحالية باستخدام الأمر firebase functions:config:export:

firebase functions:config:export
i  Importing configs from projects: [project-0, project-1]
⚠  The following configs keys could not be exported as environment variables:

⚠  project-0 (dev):
    1foo.a => 1FOO\_A (Key 1FOO\_A must start with an uppercase ASCII letter or underscore, and then consist of uppercase ASCII letters, digits, and underscores.)

Enter a PREFIX to rename invalid environment variable keys: CONFIG\_
✔  Wrote functions/.env.prod
✔  Wrote functions/.env.dev
✔  Wrote functions/.env.local
✔  Wrote functions/.env

يُرجى العِلم أنّه في بعض الحالات، سيُطلب منك إدخال بادئة لإعادة تسمية مفاتيح متغيرات البيئة التي تم تصديرها. ويرجع ذلك إلى أنّه لا يمكن تحويل جميع الإعدادات تلقائيًا لأنّها قد تكون غير صالحة أو قد تكون مفتاحًا لمتغيّر بيئة محجوز.

ننصحك بمراجعة محتوى ملفات .env التي تم إنشاؤها بعناية قبل نشر الدوال أو تسجيل ملفات .env في نظام التحكّم بالمصادر. إذا كانت أي قيم حساسة ويجب عدم تسريبها، عليك إزالتها من ملفات .env وتخزينها بشكل آمن في Secret Manager بدلاً من ذلك.

عليك أيضًا تعديل رمز الدوال. يجب الآن استخدام process.env بدلاً من أي دوال تستخدم functions.config، كما هو موضّح في متغيرات البيئة.