When using firebase serve --only functions with firebase.json like the following:
{
"hosting": {
"public": "public",
"rewrites": [
{
"source": "**",
"function": "app"
}
]
},
"functions": {
"source": "./functions"
}
}
The Google Cloud Functions emulator doesn't start correctly.
The emulator works for me using function.source, but I'm not using the prefix of ./, instead just the bare path e.g. build/functions.
Hi, any update on this? :smiley:
@merlinnot Not yet, but will update this issue once we do! We also welcome PRs!
Without the dot it is working fine for me.
But partially related to this, where can you find the options that go into firebase.json? I can't seem to find any reference.
Also, I find it odd that firebase deploy requires a node_modules folder inside the functions source directory. I am using Babel to transpile the functions code, so I have a build directory separate from my source files. Firebase forces me to copy the package.json to the build output and run an install there before deploying. This seems unnecessary and redundant. Or I am misunderstanding the idea behind it. Can't firebase deploy use the same module resolution as regular node? That would mean it moves to the parent directory and looks for node_modules there, until it finds what it's looking for.
Thanks for the question @0x80. firebase-tools needs node_modules to be installed because it actually executes the functions code prior to deploying and pulls functions trigger information (what event triggers the function the run) from the module exports. That information is needed for the deployment of the functions. This is why you are able to define triggers through code, and do not have to use flags.
A feature that we are thinking of adding to make use cases like using Babel easier is to add a "build" script field to firebase.json that will run before to emulation or deployment. That way, you don't have to manually remember to run an install before deploying. Would that make things easier for you?
@laurenzlong I get the part about having to execute the code, but what I don't understand is the strict position of node_modules __inside__ the functions root. If my project uses "my_functions" as its functions location, and has a package.json 1 or 2 levels above that in the project root, the emulator should be able to execute from my_functions which depends on node_modules to levels up if it follows the standard module resolvement strategy? (by just moving up a level and checking again).
When deployment happens, the firebase tools can grab the folder that has the functions, and together with the package.json from the root it has everything it needs I would think. But maybe I'm missing something.
In any case, I solved things for myself by copying my package json into the babel built output. It works fine.
I also did an attempt with Webpack to bundle dependencies together with the code, but then the emulator wouldn't see the functions anymore. Also the google libs were using expressions in require statements which webpack warned about, so I think that was step too far for now :)
Anyway here is my setup for using babel:
{
"functions": {
"source": "build"
}
}
{
"name": "functions",
"private": true,
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase serve --only functions",
"shell": "npm run build && firebase experimental:functions:shell",
"start": "npm run shell",
"clean": "del 'build/**/*.js', 'build/*.json'",
"postbuild": "cpy 'package.json' build && cd build && npm install --production",
"build": "npm run clean && babel src --out-dir build",
"deploy": "npm run build && npm run postbuild && firebase deploy --only functions",
"logs": "firebase functions:log"
},
"dependencies": {
"circular-json": "^0.4.0",
"firebase-admin": "^5.5.0",
"firebase-functions": "^0.7.3",
"invariant": "^2.2.2"
},
"devDependencies": {
"@babel/cli": "^7.0.0-beta.31",
"@babel/core": "^7.0.0-beta.31",
"@babel/preset-env": "^7.0.0-beta.31",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"cpy-cli": "^1.0.1",
"del-cli": "^1.1.0",
"eslint": "^4.11.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"firebase-tools": "^3.15.0"
}
}
PS: As you can see I also made firebase-tools a local dependency. This is because firebase-tools was already built on my system with a different node version, and the emulator doesn't execute then. It needs to be built with node 6. Having it as a local dev dependency avoids conflicts like that.
Thanks for sharing your use case and your package.json. You make a good observation that firebase-tools only looks at the functions folder when doing functions emulation or deployment. This is a deliberate design choice to have isolation between the deployment targets (functions, hosting, etc.) When functions is being deployed, the entire functions folder is zipped up (ignoring node_modules) and deployed. Once deployed, the server "builds" the project by looking at what's inside package.json and pulling the dependencies from npm. The project root is not deployed. Therefore the emulator mimics deployment behavior by only looking at the functions folder.
Also, having firebase-tools as a dev dependency is really clever!
I directly installed functions into the project folder
$npm install firebase firebase-admin firebase-functions --save
{
"functions:": {
"source": "src/firebase/functions"
},
"hosting": {
"public": "public",
"ignore": [...]
}
}
Is this the same issue? Should Functions folder always have its own package.json and firebase-functions, and firebase-admin packages?
(Assigning this to someone to take a look)
@alexpilugin can you share what your directory structure looks like as well as any package.json files that live in it?
@thechenky @alexpilugin This is how I do it:
My functions sources lives in src/cloud-functions.
Then in my firebase.json file I have this:
{
"functions": {
"source": ".",
"predeploy": ["yarn lint", "yarn build"],
"ignore": [
"Dockerfile",
"Dockerfile.*",
"*.log",
".DS_Store",
".env",
".env.*",
".git",
".gitignore",
".vscode",
"cloud-builder",
"credentials",
"docs",
"exports",
"node_modules"
]
}
}
Yarn build for me is configured as: "tsc --pretty && tspath -f". This compiles all files to the "build" directory (configured in tsconfig) and rewrites the typescript path aliases so they work at runtime.
Lastly in package.json I set `"main": "build/cloud-functions/index.js".
This approach doesn't require any extra package.json or node_modules folder anywhere.
Can anyone confirm if this issue is still present with the new emulators (version 6.9.0 or higher)?
Firebase CLI V: 6.4.0 - works fine for me
"functions": {
"source": "server"
},
My folder structure:
public
src
server
credentials
functions
node_modules
This is an old issue that affected the old functions emulator (version 6.x, firebase serve). I have successfully used functions.source with firebase emulators:start without issues so I am going to close this as fixed/obsolete.