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 functionsin an empty folder. - Add relevant functions code to the
src/directory. - Run the
"deploy"script, or runfirebase deploy --only functionsfrom a terminal.- Result: functions deploy without any issues.
- Run
npx gts initin thefunctions/directory to initialise gts. - Run the
"deploy"script, or runfirebase deploy --only functionsfrom 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 foundby removing.cmdfrom 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.