Firebase CLI部署Functions时突然忽略环境变量问题
问题背景
现有包含Cloud Functions的Firebase代码项目,需要跨多区域部署到多个Firebase项目。此前通过如下代码设置函数部署区域:
return functions .region(process.env.REGION) // ...
此前部署时使用如下命令传参即可正常生效:
$ REGION=us-central1 firebase deploy --only functions
近期该方案失效:即便执行firebase deploy前通过export命令提前导出REGION变量,部署流程也会完全忽略REGION=us-central1的配置,部署全程无报错。
2022-06-13 排查进展
在代码中添加部署阶段的日志逻辑,将process.env全量导出到文件后,发现部署阶段实际读取到的环境变量和本地Shell的变量列表完全不一致,输出内容如下:
{ "FIREBASE_CONFIG": "{\"projectId\":\"REDACTED\",\"storageBucket\":\"REDACTED.appspot.com\",\"locationId\":\"us-central\"}", "GCLOUD_PROJECT": "REDACTED", "CLOUD_RUNTIME_CONFIG": "{REDACTED}", "__CF_USER_TEXT_ENCODING": "REDACTED" }
目前已知几个可能的配置入口:
- 可通过
FIREBASE_CONFIG中的locationId字段获取当前项目的默认部署位置 - 可通过
CLOUD_RUNTIME_CONFIG(存储functions.config()对象的导出内容)配置自定义参数 - 可通过
.env、.env.{项目别名或ID}文件配置变量,让部署阶段的process.env可读取到对应值
基础环境信息
- 运行系统:MacOS
- 部署流程无任何报错
- 近期未升级或变更Firebase CLI版本
问题根因
Firebase CLI调整了Functions部署阶段的构建逻辑:部署时的代码编译、配置解析流程运行在独立隔离沙箱中,默认不会透传本地Shell导出的临时自定义环境变量,因此此前命令行拼接变量、提前export变量的方式会失效。
可行解决方案
方案1:使用官方.env文件配置(推荐,稳定性最高)
Firebase CLI原生支持从Functions目录(firebase.json同级的functions文件夹)下的环境变量文件加载配置,部署时会自动匹配当前部署的项目加载对应文件,完全适配多项目、多区域部署场景:
- 在functions目录下新建环境变量文件:
- 所有项目通用的配置写入
.env - 特定项目的差异化配置写入
.env.<project-id>或.env.<project-alias>
- 所有项目通用的配置写入
- 在文件中写入区域配置:
REGION=us-central1
- 部署时无需额外在命令前拼接环境变量,直接执行
firebase deploy --only functions即可,部署阶段会自动加载对应文件中的变量,process.env.REGION可正常读取。
方案2:直接解析内置FIREBASE_CONFIG变量(零额外配置)
部署阶段默认注入的FIREBASE_CONFIG环境变量已经自带当前项目的locationId字段,无需额外传参即可自动适配不同项目的默认区域,适合不想维护额外配置文件的场景:
修改Functions初始化代码即可:
const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG); // 优先读自定义REGION配置,不存在则 fallback 到项目默认locationId const targetRegion = process.env.REGION || firebaseConfig.locationId; return functions .region(targetRegion) // ...
如果需要给特定项目指定非默认区域,配合方案1的.env文件覆盖REGION值即可。
方案3:通过Runtime Config配置区域
使用Firebase原生的运行时配置功能存储区域参数,适合已经在使用functions.config()管理配置的项目:
- 针对每个目标项目单独设置配置项:
# 切换到对应项目后执行 firebase functions:config:set deploy.region=us-central1
- 代码中直接读取配置:
const targetRegion = functions.config().deploy.region; return functions .region(targetRegion) // ...
该方案的缺点是多项目切换时需要逐个项目设置配置项,灵活度低于.env文件方案。
内容的提问来源于stack exchange,提问作者eddien

