firebase-tools icon indicating copy to clipboard operation
firebase-tools copied to clipboard

When using environment variables to differentiate values for `initializeApp`, the warning "`params.IS_TEST.value()` invoked during function deployment, instead of during runtime" is emitted

Open sceee opened this issue 2 years ago • 3 comments

[REQUIRED] Environment info

firebase-tools: 12.0.1

Platform: Windows

[REQUIRED] Test case

.env.test

IS_TEST=true

environment.ts

const environmentVariable_IsTestEnvironment = defineBoolean('IS_TEST')

export function isTestEnvironment(): boolean {
  return environmentVariable_IsTestEnvironment.value() === true
}

index.ts

const storageBucketName = isTestEnvironment() ? "some-storage-bucket" : "some-other-bucket"

initializeApp({
  storageBucket: storageBucketName,
})

export const myFn = functions
  .runWith({ maxInstances: 1 })
  .https.onCall(async (data: unknown, context) => {
    const theFn = await import('./fns/myfn')
    return theFn.abc(data, context)
  })

// ... other exported functions

[REQUIRED] Steps to reproduce

Using the above code, trying to deploy the functions using firebase deploy --project test emits the following warning:

{"severity":"WARNING","message":"params.IS_TEST.value() invoked during function deployment, instead of during runtime."}
{"severity":"WARNING","message":"This is usually a mistake. In configs, use Params directly without calling .value()."}
{"severity":"WARNING","message":"example: { memory: memoryParam } not { memory: memoryParam.value() }"}

[REQUIRED] Expected behavior

Since the initializeApp call is executed during runtime, the warning seems to be incorrect in this case. Also, trying to change this to the deployment-structure for environment variables

const storageBucketName = defineBoolean('IS_TEST').equals(true).thenElse("some-storage-bucket", "some-other-bucket").toString()

initializeApp({
  storageBucket: storageBucketName,
})

causes the storageBucket name to be initialized with an invalid value (it then actually contains a string that contains the comparison).

So I expected this warning to not appear since the initializeApp call is made during function execution and not during deployment even though it is outside of an exported function.

[REQUIRED] Actual behavior

See steps to reproduce above.

sceee avatar May 17 '23 12:05 sceee

Hi @sceee,

Today, params are designed to be used to defer function options available in the Functions SDK. Using it to set options in other SDKs, like the Admin SDK, isn't really supported, hence the error.

During deployment, the Firebase CLI needs to import the module where your function is defined. That means that every line in your function source will be expected, so things like initializeApp() will be executed.

Do you think applying lazy initialization would be appropriate for your setup?

taeold avatar May 21 '23 14:05 taeold

Hi @taeold , thanks, lazy initialization may be an option, at least theoretically it seems a promising workaround even though it introduces more complexity to the code that was not necessary using the classic functions config I try to migrate away from.

Just some general side feedback in the params feature: overall it seems that using the new params/secrets are way more complicated and have a lot more pitfalls (also not mentioned in the docs) than the previous classic functions config (functions.config().env.X). I thought migrating from the functions config to the new params/secrets is a task of a few hours but it turned out it takes months, working through a lot of issues and there is still no real end in sight.

Anyway, I will definitely try to work around this specific issue using lazy initialization for initializeApp() (in fact I did the code change already) but I can unfortunately not test it completely at the moment as I am blocked by the next issue getting in my way ( functions are no longer initialized in emulator, probably caused by #5520 ).

sceee avatar May 22 '23 17:05 sceee

I agree with @sceee. The documentation has the following statement:

For most use cases, parameterized configuration is recommended. This approach makes configuration values available both at runtime and deploy time.

I'm also getting the following errors:

{"severity":"WARNING","message":"params.FIRE_API_KEY.value() invoked during function deployment, instead of during runtime."}
{"severity":"WARNING","message":"This is usually a mistake. In configs, use Params directly without calling .value()."}

This wasn't an issue when using env vars the old way.

elhe26 avatar May 31 '23 13:05 elhe26

Hey all, we've recently added a new lifecycle hook onInit() to perform initialization tasks (like loading params and calling initializeApp()) in production. For your use case, using the new hook would look something like this:

import { onInit } from "firebase-functions/v2"

onInit(() => {
  initializeApp({
    storageBucket: isTestEnvironment() ? "some-storage-bucket" : "some-other-bucket",
  });
);

export const myFn = functions
  .runWith({ maxInstances: 1 })
  .https.onCall(async (data: unknown, context) => {
    const theFn = await import('./fns/myfn')
    return theFn.abc(data, context)
  })

See the docs here for more context.

blidd-google avatar Apr 29 '24 16:04 blidd-google