Workspace Dependencies: Firebase Functions vs API Services โ
This guide explains how local workspace packages (@lantern/shared, @lantern/forge) are resolved across the two deployment platforms in this monorepo.
The Two Patterns โ
| Firebase Functions | API Services (Cloud Run) | |
|---|---|---|
| Deploy tool | Firebase CLI | gcloud CLI |
| What gets uploaded | Only services/functions/firebase/ | Service directory + copied packages |
| package.json references | file:../../../packages/shared (workspace paths) | file:../../../packages/shared (workspace paths) |
| Deploy-time transformation | pack-workspace-deps.sh creates .tgz tarballs and temporarily patches package.json | CI copies packages into service directory with cp -r |
Both patterns use workspace-relative paths (file:../../../packages/shared) in their committed package.json. The deploy-time transformation is temporary and never committed.
Firebase Functions โ
Firebase CLI uploads only the services/functions/firebase/ directory to Cloud Build. It cannot follow file:../../../packages/shared symlinks because the parent monorepo structure is not included.
Solution: A predeploy hook (firebase.json) runs pack-workspace-deps.sh which:
- Runs
npm packonpackages/sharedandpackages/forgeto create self-contained.tgztarballs - Temporarily patches
package.jsonto reference the tarballs (file:lantern-shared-0.1.0.tgz) - Firebase CLI reads the patched version and uploads it with the tarballs
- Restores
package.jsonto workspace paths via an EXIT trap
The .tgz files are gitignored (services/functions/firebase/.gitignore).
Do not commit tarball references โ
The committed package.json must always use workspace paths:
"@lantern/shared": "file:../../../packages/shared",
"@lantern/forge": "file:../../../packages/forge"Never commit tarball references like file:lantern-shared-0.1.0.tgz. This breaks:
npm cion fresh clones (tarballs are gitignored)- CI pipelines (no tarballs available)
- Emulator runs (
firebase emulators:start)
If you see tarball references in a diff, the restore step in pack-workspace-deps.sh did not run. Revert the package.json to workspace paths.
API Services (Cloud Run) โ
Cloud Run services use gcloud run deploy --source, which uploads the service directory. The CI workflow (and local deploy scripts) copy the shared packages into the service directory before deploy:
# From deploy-dev.yml / local deploy:dev script
cp -r packages/shared services/api/auth/.shared-pkg
gcloud run deploy auth-api --source services/api/auth ...
rm -rf services/api/auth/.shared-pkgNo package.json patching is needed because the file:../../../packages/shared path resolves correctly during npm ci inside the Cloud Build container (the copied .shared-pkg directory serves as the resolution target).
Key Files โ
| File | Purpose |
|---|---|
services/functions/firebase/pack-workspace-deps.sh | Predeploy: pack tarballs, patch + restore package.json |
firebase.json (functions.predeploy) | Triggers pack script before deploy |
services/functions/firebase/.gitignore | Ignores *.tgz tarballs |
.github/workflows/deploy-dev.yml | CI: copies packages for Cloud Run deploys |
services/api/*/package.json (deploy:dev script) | Local: copies packages for Cloud Run deploys |
Emulators โ
Firebase emulators (firebase emulators:start --only functions) run functions locally and need workspace-relative paths to resolve. This is another reason the committed package.json must use file:../../../packages/shared, not tarballs.