Intention:
I want to use Google's TypeScript style guide gts in my Firebase Functions project.
Expected Result:
The command firebase deploy --only functions
should still successfully deploy my functions without errors after running npx gts init
.
Actual Result:
Deployment of my functions fails even after fixing numerous obvious issues.
Steps to reproduce:
- Initialise the firebase functions project by running
firebase init functions
in an empty folder. - Add relevant functions code to the
src/
directory. - Run the
"deploy"
script, or runfirebase deploy --only functions
from a terminal.- Result: functions deploy without any issues.
- Run
npx gts init
in thefunctions/
directory to initialise gts. - Run the
"deploy"
script, or runfirebase deploy --only functions
from a terminal.- Result: deployment fails:
- Error: There was an error reading functions\package.json:
functions\lib\index.js does not exist, can't deploy Cloud Functions
- Error: There was an error reading functions\package.json:
- Result: deployment fails:
- Fix directory mismatch.
- Result: deployment still fails with same error.
- Fix location of
"main"
.- Result: deployment fails:
- Error: npm.cmd: not found.
- Result: deployment fails:
- Fix
npm.cmd: not found
by removing.cmd
from scripts.- Result: deployment fails:
- Error:
tsc: not found
- Error:
- Result: deployment fails:
Below I've listed the project structure and contents of relevant project files at some of the key stages from the above list.
My apologies if it seems verbose, but I thought it best to try and cover most of the potentially relevant info.
After initialising the Firebase functions project, but before initializing gts:
Project has standard Firebase Functions structure.
my-project
+- functions/ # Directory containing all your functions code
|
+- lib/
| |
| +- index.js # Built/transpiled JavaScript code
| |
| +- index.js.map # Source map for debugging
|
+- src/ # Directory containing TypeScript source
| |
| +- index.ts # main source file for your Cloud Functions code
|
+- .eslintrc.js # Optional file if you enabled ESLint
|
+- package.json # npm package file describing your Cloud Functions code
|
+- tsconfig.dev.json # Optional file that references .eslintrc.js
|
+- tsconfig.json
.eslintrc.js
module.exports = {
root: true,
env: {
es6: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"google",
"plugin:@typescript-eslint/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: ["tsconfig.json", "tsconfig.dev.json"],
sourceType: "module",
},
ignorePatterns: [
"/lib/**/*", // Ignore built files.
],
plugins: [
"@typescript-eslint",
"import",
],
rules: {
"quotes": ["error", "double"],
"import/no-unresolved": 0,
"indent": ["error", 2],
},
};
package.json
{
"name": "functions",
"scripts": {
"lint": "eslint --ext .js,.ts .",
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "16"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^11.5.0",
"firebase-functions": "^4.2.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"firebase-functions-test": "^3.0.0",
"typescript": "^4.9.0"
},
"private": true
}
tsconfig.dev.json
{
"include": [
".eslintrc.js"
]
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017"
},
"compileOnSave": true,
"include": [
"src"
]
}
In the above project state the "deploy"
script completes successfully. The functions are deployed without any errors.
After initializing gts:
Project structure.
my-project
+- functions/ # Directory containing all your functions code
|
+- lib/
| |
| +- index.js # Built/transpiled JavaScript code
| |
| +- index.js.map # Source map for debugging
|
+- src/ # Directory containing TypeScript source
| |
| +- index.ts # main source file for your Cloud Functions code
|
+- .editorconfig
|
+- .eslintignore
|
+- .eslintrc.js # Optional file if you enabled ESLint
|
+- .eslintrc.json
|
+- .prettierrc.js
|
+- package.json # npm package file describing your Cloud Functions code
|
+- tsconfig.dev.json # Optional file that references .eslintrc.js
|
+- tsconfig.json
.editorconfig
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
insert_final_newline = true
.eslintignore
build/
.eslintrc.js
No change.
.eslintrc.json
{
"extends": "./node_modules/gts/"
}
.prettierrc.js
module.exports = {
...require('gts/.prettierrc.json')
}
package.json
{
"name": "functions",
"scripts": {
"lint": "gts lint",
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"clean": "gts clean",
"compile": "tsc",
"fix": "gts fix",
"prepare": "npm.cmd run compile",
"pretest": "npm.cmd run compile",
"posttest": "npm.cmd run lint"
},
"engines": {
"node": "16"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^11.5.0",
"firebase-functions": "^4.2.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"firebase-functions-test": "^3.0.0",
"typescript": "~4.7.0",
"gts": "^3.1.1",
"@types/node": "^14.11.2"
},
"private": true
}
tsconfig.dev.json
No change.
tsconfig.json
{
"extends": "./node_modules/gts/tsconfig-google.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "build"
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}
In the above project state the "deploy"
script fails with the error:
Error: There was an error reading functions\package.json:
functions\lib\index.js does not exist, can't deploy Cloud Functions
This error is because by default Firebase functions sets the "outDir"
in tsconfig.json
to "lib"
, but initialising gts changes the "outDir"
to "build"
.
I'm not sure how I would go about changing the "deploy"
script to expect the "outDir"
to be "build"
, so I instead reverted the "outDir"
to be "lib"
.
After reverting to "outDir": "lib"
in tsconfig.json
:
tsconfig.json
{
"extends": "./node_modules/gts/tsconfig-google.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "lib"
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}
In this project state the "deploy"
script again fails with the error:
Error: There was an error reading functions\package.json:
functions\lib\index.js does not exist, can't deploy Cloud Functions
This time the error is because index.js
gets built to the directory functions\lib\src\
not functions\lib\
.
I fixed this issue by changing "main": "lib/index.js"
in package.json
to "main": "lib/src/index.js"
.
After setting "main": "lib/src/index.js"
in package.json
:
package.json
{
"name": "functions",
"scripts": {
"lint": "gts lint",
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"clean": "gts clean",
"compile": "tsc",
"fix": "gts fix",
"prepare": "npm.cmd run compile",
"pretest": "npm.cmd run compile",
"posttest": "npm.cmd run lint"
},
"engines": {
"node": "16"
},
"main": "lib/src/index.js",
"dependencies": {
"firebase-admin": "^11.5.0",
"firebase-functions": "^4.2.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"firebase-functions-test": "^3.0.0",
"typescript": "~4.7.0",
"gts": "^3.1.1",
"@types/node": "^14.11.2"
},
"private": true
}
In this project state the "deploy"
script fails as shown below:
i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint
> lint
> gts lint
version: 16
Running command: npm --prefix "$RESOURCE_DIR" run build
> build
> tsc
+ functions: Finished running predeploy script.
i functions: preparing codebase default for deployment
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
i artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
+ functions: required API cloudbuild.googleapis.com is enabled
+ functions: required API cloudfunctions.googleapis.com is enabled
+ artifactregistry: required API artifactregistry.googleapis.com is enabled
i functions: preparing functions directory for uploading...
i functions: packaged D:\Projects\my-project\functions (127.84 KB) for uploading
i functions: ensuring required API identitytoolkit.googleapis.com is enabled...
+ functions: required API identitytoolkit.googleapis.com is enabled
+ functions: functions folder uploaded successfully
i functions: updating Node.js 16 function userBeforeCreate(us-central1)...
i functions: updating Node.js 16 function userOnCreate(us-central1)...
Build failed: > prepare
> npm.cmd run compile
sh: 1: npm.cmd: not found
npm ERR! code 127
npm ERR! path /workspace
npm ERR! command failed
npm ERR! command sh -c -- npm.cmd run compile
npm ERR! A complete log of this run can be found in:
npm ERR! /www-data-home/.npm/_logs/2023-05-05T09_23_49_048Z-debug-0.log; Error ID: beaf8772
Build failed: > prepare
> npm.cmd run compile
sh: 1: npm.cmd: not found
npm ERR! code 127
npm ERR! path /workspace
npm ERR! command failed
npm ERR! command sh -c -- npm.cmd run compile
npm ERR! A complete log of this run can be found in:
npm ERR! /www-data-home/.npm/_logs/2023-05-05T09_24_40_038Z-debug-0.log; Error ID: beaf8772
Functions deploy had errors with the following functions:
userBeforeCreate(us-central1)
userOnCreate(us-central1)
i functions: cleaning up build files...
Error: There was an error deploying functions:
- Error Failed to update function userBeforeCreate in region us-central1
- Error Failed to update function userOnCreate in region us-central1
Process finished with exit code 2
And here's one of the Google Cloud logs mentioned (they're both essentially identical)[Note: ids etc have been xxxxx hidden]:
{
"protoPayload": {
"@type": "type.googleapis.com/google.cloud.audit.AuditLog",
"status": {
"code": 3,
"message": "Build failed: > prepare\n> npm.cmd run compile\n\nsh: 1: npm.cmd: not found\nnpm ERR! code 127\nnpm ERR! path /workspace\nnpm ERR! command failed\nnpm ERR! command sh -c -- npm.cmd run compile\n\nnpm ERR! A complete log of this run can be found in:\nnpm ERR! /www-data-home/.npm/_logs/2023-05-05T09_10_41_708Z-debug-0.log; Error ID: beaf8772"
},
"authenticationInfo": {},
"serviceName": "cloudfunctions.googleapis.com",
"methodName": "google.cloud.functions.v1.CloudFunctionsService.UpdateFunction",
"resourceName": "projects/my-project/locations/us-central1/functions/userBeforeCreate"
},
"insertId": "xxxxx",
"resource": {
"type": "cloud_function",
"labels": {
"region": "us-central1",
"function_name": "userBeforeCreate",
"project_id": "my-project"
}
},
"timestamp": "2023-05-05T09:10:59.793425Z",
"severity": "ERROR",
"logName": "projects/my-project/logs/cloudaudit.googleapis.com%2Factivity",
"operation": {
"id": "operations/xxxxx",
"producer": "cloudfunctions.googleapis.com",
"last": true
},
"receiveTimestamp": "2023-05-05T09:11:00.085118556Z"
}
To address the npm.cmd: not found
issue, I then tried removing .cmd
from the "prepare"
, "pretest"
& "posttest"
scripts in package.json
.
After removing .cmd
from the "prepare"
, "pretest"
& "posttest"
scripts:
package.json
{
"name": "functions",
"scripts": {
"lint": "gts lint",
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"clean": "gts clean",
"compile": "tsc",
"fix": "gts fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
"posttest": "npm run lint"
},
"engines": {
"node": "16"
},
"main": "lib/src/index.js",
"dependencies": {
"firebase-admin": "^11.5.0",
"firebase-functions": "^4.2.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"eslint": "^8.9.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"firebase-functions-test": "^3.0.0",
"typescript": "~4.7.0",
"gts": "^3.1.1",
"@types/node": "^14.11.2"
},
"private": true
}
In this project state the "deploy"
script fails as shown below:
i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint
> lint
> gts lint
version: 16
Running command: npm --prefix "$RESOURCE_DIR" run build
> build
> tsc
+ functions: Finished running predeploy script.
i functions: preparing codebase default for deployment
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
i artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
+ functions: required API cloudfunctions.googleapis.com is enabled
+ artifactregistry: required API artifactregistry.googleapis.com is enabled
+ functions: required API cloudbuild.googleapis.com is enabled
i functions: preparing functions directory for uploading...
i functions: packaged D:\Projects\my-project\functions (127.96 KB) for uploading
i functions: ensuring required API identitytoolkit.googleapis.com is enabled...
+ functions: required API identitytoolkit.googleapis.com is enabled
+ functions: functions folder uploaded successfully
i functions: updating Node.js 16 function userBeforeCreate(us-central1)...
i functions: updating Node.js 16 function userOnCreate(us-central1)...
Build failed: > prepare
> npm run compile
> compile
> tsc
sh: 1: tsc: not found
npm ERR! code 127
npm ERR! path /workspace
npm ERR! command failed
npm ERR! command sh -c -- npm run compile
npm ERR! A complete log of this run can be found in:
npm ERR! /www-data-home/.npm/_logs/2023-05-05T10_46_49_310Z-debug-0.log; Error ID: beaf8772
Build failed: > prepare
> npm run compile
> compile
> tsc
sh: 1: tsc: not found
npm ERR! code 127
npm ERR! path /workspace
npm ERR! command failed
npm ERR! command sh -c -- npm run compile
npm ERR! A complete log of this run can be found in:
npm ERR! /www-data-home/.npm/_logs/2023-05-05T10_47_18_266Z-debug-0.log; Error ID: beaf8772
Functions deploy had errors with the following functions:
userBeforeCreate(us-central1)
userOnCreate(us-central1)
i functions: cleaning up build files...
Error: There was an error deploying functions:
- Error Failed to update function userBeforeCreate in region us-central1
- Error Failed to update function userOnCreate in region us-central1
Process finished with exit code 2
I don't know how to fix the issue from here, so any assistance would be most appreciated.