From 7cba2abf5b0e500cb51e10328ffd13d33b76c487 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 8 Oct 2025 12:56:09 -0700 Subject: [PATCH 1/4] Update functions template to meet modern dev practices. --- src/init/features/functions.spec.ts | 41 ++++++-------- src/init/features/functions/javascript.ts | 39 ++++---------- src/init/features/functions/typescript.ts | 54 +++++-------------- templates/init/functions/javascript/_eslintrc | 28 ---------- .../init/functions/javascript/biome.json | 13 +++++ templates/init/functions/javascript/index.js | 46 ++++++++-------- .../{package.nolint.json => package.json} | 21 ++++---- .../functions/javascript/package.lint.json | 26 --------- templates/init/functions/typescript/_eslintrc | 33 ------------ .../init/functions/typescript/biome.json | 13 +++++ templates/init/functions/typescript/index.ts | 44 +++++++-------- .../{package.nolint.json => package.json} | 24 +++++---- .../functions/typescript/package.lint.json | 31 ----------- .../functions/typescript/tsconfig.dev.json | 5 -- .../init/functions/typescript/tsconfig.json | 11 ++-- 15 files changed, 136 insertions(+), 293 deletions(-) delete mode 100644 templates/init/functions/javascript/_eslintrc create mode 100644 templates/init/functions/javascript/biome.json rename templates/init/functions/javascript/{package.nolint.json => package.json} (66%) delete mode 100644 templates/init/functions/javascript/package.lint.json delete mode 100644 templates/init/functions/typescript/_eslintrc create mode 100644 templates/init/functions/typescript/biome.json rename templates/init/functions/typescript/{package.nolint.json => package.json} (62%) delete mode 100644 templates/init/functions/typescript/package.lint.json delete mode 100644 templates/init/functions/typescript/tsconfig.dev.json diff --git a/src/init/features/functions.spec.ts b/src/init/features/functions.spec.ts index d1650ebd87e..d51f89daedf 100644 --- a/src/init/features/functions.spec.ts +++ b/src/init/features/functions.spec.ts @@ -72,11 +72,8 @@ describe("functions", () => { it("creates a new javascript codebase with the correct configuration", async () => { const setup = { config: { functions: [] }, rcfile: {} }; prompt.select.onFirstCall().resolves("javascript"); - - // say "yes" to enabling eslint for the js project - prompt.confirm.onFirstCall().resolves(true); // do not install dependencies - prompt.confirm.onSecondCall().resolves(false); + prompt.confirm.onFirstCall().resolves(false); askWriteProjectFileStub = sandbox.stub(emptyConfig, "askWriteProjectFile"); askWriteProjectFileStub.resolves(); @@ -86,11 +83,11 @@ describe("functions", () => { source: TEST_SOURCE_DEFAULT, codebase: TEST_CODEBASE_DEFAULT, ignore: ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"], - predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], + predeploy: [], }); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ `${TEST_SOURCE_DEFAULT}/package.json`, - `${TEST_SOURCE_DEFAULT}/.eslintrc.js`, + `${TEST_SOURCE_DEFAULT}/biome.json`, `${TEST_SOURCE_DEFAULT}/index.js`, `${TEST_SOURCE_DEFAULT}/.gitignore`, ]); @@ -99,10 +96,8 @@ describe("functions", () => { it("creates a new typescript codebase with the correct configuration", async () => { const setup = { config: { functions: [] }, rcfile: {} }; prompt.select.onFirstCall().resolves("typescript"); - // Lint - prompt.confirm.onFirstCall().resolves(true); // do not install dependencies - prompt.confirm.onSecondCall().resolves(false); + prompt.confirm.onFirstCall().resolves(false); askWriteProjectFileStub = sandbox.stub(emptyConfig, "askWriteProjectFile"); askWriteProjectFileStub.resolves(); @@ -112,15 +107,11 @@ describe("functions", () => { source: TEST_SOURCE_DEFAULT, codebase: TEST_CODEBASE_DEFAULT, ignore: ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"], - predeploy: [ - 'npm --prefix "$RESOURCE_DIR" run lint', - 'npm --prefix "$RESOURCE_DIR" run build', - ], + predeploy: ['npm --prefix "$RESOURCE_DIR" run build'], }); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ `${TEST_SOURCE_DEFAULT}/package.json`, - `${TEST_SOURCE_DEFAULT}/.eslintrc.js`, - `${TEST_SOURCE_DEFAULT}/tsconfig.dev.json`, + `${TEST_SOURCE_DEFAULT}/biome.json`, `${TEST_SOURCE_DEFAULT}/tsconfig.json`, `${TEST_SOURCE_DEFAULT}/src/index.ts`, `${TEST_SOURCE_DEFAULT}/.gitignore`, @@ -138,9 +129,8 @@ describe("functions", () => { // Initialize as JavaScript prompt.select.onSecondCall().resolves("javascript"); - // Lint but do not install dependencies - prompt.confirm.onFirstCall().resolves(true); - prompt.confirm.onSecondCall().resolves(false); + // do not install dependencies + prompt.confirm.onFirstCall().resolves(false); askWriteProjectFileStub = sandbox.stub(config, "askWriteProjectFile"); askWriteProjectFileStub.resolves(); @@ -157,7 +147,7 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], + predeploy: [], }, { source: "testsource2", @@ -169,12 +159,12 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], + predeploy: [], }, ]); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ `testsource2/package.json`, - `testsource2/.eslintrc.js`, + `testsource2/biome.json`, `testsource2/index.js`, `testsource2/.gitignore`, ]); @@ -185,9 +175,8 @@ describe("functions", () => { prompt.select.onFirstCall().resolves("reinit"); prompt.select.onSecondCall().resolves("javascript"); - // Lint but do not install dependencies - prompt.confirm.onFirstCall().resolves(true); - prompt.confirm.onSecondCall().resolves(false); + // do not install dependencies + prompt.confirm.onFirstCall().resolves(false); askWriteProjectFileStub = sandbox.stub(config, "askWriteProjectFile"); askWriteProjectFileStub.resolves(); @@ -204,12 +193,12 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], + predeploy: [], }, ]); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ `${TEST_SOURCE_DEFAULT}/package.json`, - `${TEST_SOURCE_DEFAULT}/.eslintrc.js`, + `${TEST_SOURCE_DEFAULT}/biome.json`, `${TEST_SOURCE_DEFAULT}/index.js`, `${TEST_SOURCE_DEFAULT}/.gitignore`, ]); diff --git a/src/init/features/functions/javascript.ts b/src/init/features/functions/javascript.ts index 1664991bd4c..18cae55d3da 100644 --- a/src/init/features/functions/javascript.ts +++ b/src/init/features/functions/javascript.ts @@ -1,42 +1,23 @@ import { askInstallDependencies } from "./npm-dependencies"; -import { confirm } from "../../../prompt"; import { configForCodebase } from "../../../functions/projectConfig"; import { readTemplateSync } from "../../../templates"; import * as supported from "../../../deploy/functions/runtimes/supported"; const INDEX_TEMPLATE = readTemplateSync("init/functions/javascript/index.js"); -const PACKAGE_LINTING_TEMPLATE = readTemplateSync("init/functions/javascript/package.lint.json"); -const PACKAGE_NO_LINTING_TEMPLATE = readTemplateSync( - "init/functions/javascript/package.nolint.json", -); -const ESLINT_TEMPLATE = readTemplateSync("init/functions/javascript/_eslintrc"); +const PACKAGE_TEMPLATE = readTemplateSync("init/functions/javascript/package.json"); +const BIOME_TEMPLATE = readTemplateSync("init/functions/javascript/biome.json"); const GITIGNORE_TEMPLATE = readTemplateSync("init/functions/javascript/_gitignore"); export async function setup(setup: any, config: any): Promise { - setup.functions.lint = - setup.functions.lint || - (await confirm("Do you want to use ESLint to catch probable bugs and enforce style?")); - if (setup.functions.lint) { - const cbconfig = configForCodebase(setup.config.functions, setup.functions.codebase); - cbconfig.predeploy = ['npm --prefix "$RESOURCE_DIR" run lint']; - await config.askWriteProjectFile( - `${setup.functions.source}/package.json`, - PACKAGE_LINTING_TEMPLATE.replace( - "{{RUNTIME}}", - supported.latest("nodejs").replace("nodejs", ""), - ), - ); - await config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE); - } else { - await config.askWriteProjectFile( - `${setup.functions.source}/package.json`, - PACKAGE_NO_LINTING_TEMPLATE.replace( - "{{RUNTIME}}", - supported.latest("nodejs").replace("nodejs", ""), - ), - ); - } + const cbconfig = configForCodebase(setup.config.functions, setup.functions.codebase); + cbconfig.predeploy = []; + const runtime = supported.latest("nodejs").replace("nodejs", ""); + await config.askWriteProjectFile( + `${setup.functions.source}/package.json`, + PACKAGE_TEMPLATE.replace("{{RUNTIME}}", runtime), + ); + await config.askWriteProjectFile(`${setup.functions.source}/biome.json`, BIOME_TEMPLATE); await config.askWriteProjectFile(`${setup.functions.source}/index.js`, INDEX_TEMPLATE); await config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE); await askInstallDependencies(setup.functions, config); diff --git a/src/init/features/functions/typescript.ts b/src/init/features/functions/typescript.ts index 8c021c9a821..a7ae6da879e 100644 --- a/src/init/features/functions/typescript.ts +++ b/src/init/features/functions/typescript.ts @@ -1,58 +1,28 @@ import { askInstallDependencies } from "./npm-dependencies"; -import { confirm } from "../../../prompt"; import { configForCodebase } from "../../../functions/projectConfig"; import { readTemplateSync } from "../../../templates"; import * as supported from "../../../deploy/functions/runtimes/supported"; -const PACKAGE_LINTING_TEMPLATE = readTemplateSync("init/functions/typescript/package.lint.json"); -const PACKAGE_NO_LINTING_TEMPLATE = readTemplateSync( - "init/functions/typescript/package.nolint.json", -); -const ESLINT_TEMPLATE = readTemplateSync("init/functions/typescript/_eslintrc"); +const PACKAGE_TEMPLATE = readTemplateSync("init/functions/typescript/package.json"); +const BIOME_TEMPLATE = readTemplateSync("init/functions/typescript/biome.json"); const TSCONFIG_TEMPLATE = readTemplateSync("init/functions/typescript/tsconfig.json"); -const TSCONFIG_DEV_TEMPLATE = readTemplateSync("init/functions/typescript/tsconfig.dev.json"); const INDEX_TEMPLATE = readTemplateSync("init/functions/typescript/index.ts"); const GITIGNORE_TEMPLATE = readTemplateSync("init/functions/typescript/_gitignore"); export async function setup(setup: any, config: any): Promise { - setup.functions.lint = - setup.functions.lint || - (await confirm({ - message: "Do you want to use ESLint to catch probable bugs and enforce style?", - default: true, - })); - const cbconfig = configForCodebase(setup.config.functions, setup.functions.codebase); - cbconfig.predeploy = []; - if (setup.functions.lint) { - cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run lint'); - cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build'); - await config.askWriteProjectFile( - `${setup.functions.source}/package.json`, - PACKAGE_LINTING_TEMPLATE.replace( - "{{RUNTIME}}", - supported.latest("nodejs").replace("nodejs", ""), - ), - ); - await config.askWriteProjectFile(`${setup.functions.source}/.eslintrc.js`, ESLINT_TEMPLATE); - // TODO: isn't this file out of date now? - await config.askWriteProjectFile( - `${setup.functions.source}/tsconfig.dev.json`, - TSCONFIG_DEV_TEMPLATE, - ); - } else { - cbconfig.predeploy.push('npm --prefix "$RESOURCE_DIR" run build'); - await config.askWriteProjectFile( - `${setup.functions.source}/package.json`, - PACKAGE_NO_LINTING_TEMPLATE.replace( - "{{RUNTIME}}", - supported.latest("nodejs").replace("nodejs", ""), - ), - ); - } + cbconfig.predeploy = [ + 'npm --prefix "$RESOURCE_DIR" run lint', + 'npm --prefix "$RESOURCE_DIR" run build', + ]; + const runtime = supported.latest("nodejs").replace("nodejs", ""); + await config.askWriteProjectFile( + `${setup.functions.source}/package.json`, + PACKAGE_TEMPLATE.replace("{{RUNTIME}}", runtime), + ); + await config.askWriteProjectFile(`${setup.functions.source}/biome.json`, BIOME_TEMPLATE); await config.askWriteProjectFile(`${setup.functions.source}/tsconfig.json`, TSCONFIG_TEMPLATE); - await config.askWriteProjectFile(`${setup.functions.source}/src/index.ts`, INDEX_TEMPLATE); await config.askWriteProjectFile(`${setup.functions.source}/.gitignore`, GITIGNORE_TEMPLATE); await askInstallDependencies(setup.functions, config); diff --git a/templates/init/functions/javascript/_eslintrc b/templates/init/functions/javascript/_eslintrc deleted file mode 100644 index f4cb76caae2..00000000000 --- a/templates/init/functions/javascript/_eslintrc +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = { - env: { - es6: true, - node: true, - }, - parserOptions: { - "ecmaVersion": 2018, - }, - extends: [ - "eslint:recommended", - "google", - ], - rules: { - "no-restricted-globals": ["error", "name", "length"], - "prefer-arrow-callback": "error", - "quotes": ["error", "double", {"allowTemplateLiterals": true}], - }, - overrides: [ - { - files: ["**/*.spec.*"], - env: { - mocha: true, - }, - rules: {}, - }, - ], - globals: {}, -}; diff --git a/templates/init/functions/javascript/biome.json b/templates/init/functions/javascript/biome.json new file mode 100644 index 00000000000..529873c8215 --- /dev/null +++ b/templates/init/functions/javascript/biome.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://biomejs.dev/schemas/latest/schema.json", + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + } +} diff --git a/templates/init/functions/javascript/index.js b/templates/init/functions/javascript/index.js index b2c5d416bd5..bae0b216c75 100644 --- a/templates/init/functions/javascript/index.js +++ b/templates/init/functions/javascript/index.js @@ -1,32 +1,28 @@ -/** - * Import function triggers from their respective submodules: - * - * const {onCall} = require("firebase-functions/v2/https"); - * const {onDocumentWritten} = require("firebase-functions/v2/firestore"); - * - * See a full list of supported triggers at https://firebase.google.com/docs/functions - */ +import { setGlobalOptions } from "firebase-functions"; +import * as logger from "firebase-functions/logger"; +import { onRequest } from "firebase-functions/v2/https"; -const {setGlobalOptions} = require("firebase-functions"); -const {onRequest} = require("firebase-functions/https"); -const logger = require("firebase-functions/logger"); +// Start writing functions: +// https://firebase.google.com/docs/functions -// For cost control, you can set the maximum number of containers that can be -// running at the same time. This helps mitigate the impact of unexpected -// traffic spikes by instead downgrading performance. This limit is a -// per-function limit. You can override the limit for each function using the -// `maxInstances` option in the function's options, e.g. -// `onRequest({ maxInstances: 5 }, (req, res) => { ... })`. // NOTE: setGlobalOptions does not apply to functions using the v1 API. V1 // functions should each use functions.runWith({ maxInstances: 10 }) instead. // In the v1 API, each function can only serve one request per container, so // this will be the maximum concurrent request count. -setGlobalOptions({ maxInstances: 10 }); +setGlobalOptions({ + // For cost control, you can set the maximum number of containers that can be + // running at the same time. This helps mitigate the impact of unexpected + // traffic spikes by instead downgrading performance. This limit is a + // per-function limit. You can override the limit for each function using the + // `maxInstances` option in the function's options, e.g. + // `onRequest({ maxInstances: 5 }, (req, res) => { ... })`. + maxInstances: 10, + // Tip: event-driven triggers must run in the same region as the Firebase + // services they listen to (Firestore, Storage, etc.). + region: "us-central1", +}); -// Create and deploy your first functions -// https://firebase.google.com/docs/functions/get-started - -// exports.helloWorld = onRequest((request, response) => { -// logger.info("Hello logs!", {structuredData: true}); -// response.send("Hello from Firebase!"); -// }); +export const helloWorld = onRequest((_request, response) => { + logger.info("Hello from Firebase!", { structuredData: true }); + response.send("Hello from Firebase!"); +}); diff --git a/templates/init/functions/javascript/package.nolint.json b/templates/init/functions/javascript/package.json similarity index 66% rename from templates/init/functions/javascript/package.nolint.json rename to templates/init/functions/javascript/package.json index 4aea0a9f1b6..4b819a34d3b 100644 --- a/templates/init/functions/javascript/package.nolint.json +++ b/templates/init/functions/javascript/package.json @@ -1,23 +1,26 @@ { "name": "functions", - "description": "Cloud Functions for Firebase", + "type": "module", + "private": true, + "engines": { + "node": "{{RUNTIME}}" + }, + "main": "index.js", "scripts": { + "lint": "biome lint .", + "format": "biome format --write .", "serve": "firebase emulators:start --only functions", "shell": "firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log" }, - "engines": { - "node": "{{RUNTIME}}" - }, - "main": "index.js", "dependencies": { - "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1" + "firebase-admin": "^13.5.0", + "firebase-functions": "^6.4.0" }, "devDependencies": { + "@biomejs/biome": "^2.2.5", "firebase-functions-test": "^3.1.0" - }, - "private": true + } } diff --git a/templates/init/functions/javascript/package.lint.json b/templates/init/functions/javascript/package.lint.json deleted file mode 100644 index 1b951d0759f..00000000000 --- a/templates/init/functions/javascript/package.lint.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "functions", - "description": "Cloud Functions for Firebase", - "scripts": { - "lint": "eslint .", - "serve": "firebase emulators:start --only functions", - "shell": "firebase functions:shell", - "start": "npm run shell", - "deploy": "firebase deploy --only functions", - "logs": "firebase functions:log" - }, - "engines": { - "node": "{{RUNTIME}}" - }, - "main": "index.js", - "dependencies": { - "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1" - }, - "devDependencies": { - "eslint": "^8.15.0", - "eslint-config-google": "^0.14.0", - "firebase-functions-test": "^3.1.0" - }, - "private": true -} diff --git a/templates/init/functions/typescript/_eslintrc b/templates/init/functions/typescript/_eslintrc deleted file mode 100644 index 0f8e2a9b7e8..00000000000 --- a/templates/init/functions/typescript/_eslintrc +++ /dev/null @@ -1,33 +0,0 @@ -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. - "/generated/**/*", // Ignore generated files. - ], - plugins: [ - "@typescript-eslint", - "import", - ], - rules: { - "quotes": ["error", "double"], - "import/no-unresolved": 0, - "indent": ["error", 2], - }, -}; diff --git a/templates/init/functions/typescript/biome.json b/templates/init/functions/typescript/biome.json new file mode 100644 index 00000000000..529873c8215 --- /dev/null +++ b/templates/init/functions/typescript/biome.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://biomejs.dev/schemas/latest/schema.json", + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + } +} diff --git a/templates/init/functions/typescript/index.ts b/templates/init/functions/typescript/index.ts index ade33ec3159..e04f51e7468 100644 --- a/templates/init/functions/typescript/index.ts +++ b/templates/init/functions/typescript/index.ts @@ -1,32 +1,28 @@ -/** - * Import function triggers from their respective submodules: - * - * import {onCall} from "firebase-functions/v2/https"; - * import {onDocumentWritten} from "firebase-functions/v2/firestore"; - * - * See a full list of supported triggers at https://firebase.google.com/docs/functions - */ - -import {setGlobalOptions} from "firebase-functions"; -import {onRequest} from "firebase-functions/https"; +import { setGlobalOptions } from "firebase-functions"; import * as logger from "firebase-functions/logger"; +import { onRequest } from "firebase-functions/v2/https"; -// Start writing functions -// https://firebase.google.com/docs/functions/typescript +// Start writing functions: +// https://firebase.google.com/docs/functions/typescript -// For cost control, you can set the maximum number of containers that can be -// running at the same time. This helps mitigate the impact of unexpected -// traffic spikes by instead downgrading performance. This limit is a -// per-function limit. You can override the limit for each function using the -// `maxInstances` option in the function's options, e.g. -// `onRequest({ maxInstances: 5 }, (req, res) => { ... })`. // NOTE: setGlobalOptions does not apply to functions using the v1 API. V1 // functions should each use functions.runWith({ maxInstances: 10 }) instead. // In the v1 API, each function can only serve one request per container, so // this will be the maximum concurrent request count. -setGlobalOptions({ maxInstances: 10 }); +setGlobalOptions({ + // For cost control, you can set the maximum number of containers that can be + // running at the same time. This helps mitigate the impact of unexpected + // traffic spikes by instead downgrading performance. This limit is a + // per-function limit. You can override the limit for each function using the + // `maxInstances` option in the function's options, e.g. + // `onRequest({ maxInstances: 5 }, (req, res) => { ... })`. + maxInstances: 10, + // Tip: event-driven triggers must run in the same region as the Firebase + // services they listen to (Firestore, Storage, etc.). + region: "us-central1", +}); -// export const helloWorld = onRequest((request, response) => { -// logger.info("Hello logs!", {structuredData: true}); -// response.send("Hello from Firebase!"); -// }); +export const helloWorld = onRequest((_request, response) => { + logger.info("Hello from Firebase!", { structuredData: true }); + response.send("Hello from Firebase!"); +}); diff --git a/templates/init/functions/typescript/package.nolint.json b/templates/init/functions/typescript/package.json similarity index 62% rename from templates/init/functions/typescript/package.nolint.json rename to templates/init/functions/typescript/package.json index 066161c31cd..93c17aed2fd 100644 --- a/templates/init/functions/typescript/package.nolint.json +++ b/templates/init/functions/typescript/package.json @@ -1,25 +1,29 @@ { "name": "functions", + "type": "module", + "private": true, + "engines": { + "node": "{{RUNTIME}}" + }, + "main": "lib/index.js", "scripts": { "build": "tsc", "build:watch": "tsc --watch", + "lint": "biome lint .", + "format": "biome format --write .", "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": "{{RUNTIME}}" - }, - "main": "lib/index.js", "dependencies": { - "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1" + "firebase-admin": "^13.5.0", + "firebase-functions": "^6.4.0" }, "devDependencies": { - "typescript": "^5.7.3", - "firebase-functions-test": "^3.1.0" - }, - "private": true + "@biomejs/biome": "^2.2.5", + "firebase-functions-test": "^3.1.0", + "typescript": "^5.7.3" + } } diff --git a/templates/init/functions/typescript/package.lint.json b/templates/init/functions/typescript/package.lint.json deleted file mode 100644 index c2d4f5493e6..00000000000 --- a/templates/init/functions/typescript/package.lint.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "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": "{{RUNTIME}}" - }, - "main": "lib/index.js", - "dependencies": { - "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1" - }, - "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.1.0", - "typescript": "^5.7.3" - }, - "private": true -} diff --git a/templates/init/functions/typescript/tsconfig.dev.json b/templates/init/functions/typescript/tsconfig.dev.json deleted file mode 100644 index 7560eed4ca1..00000000000 --- a/templates/init/functions/typescript/tsconfig.dev.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "include": [ - ".eslintrc.js" - ] -} diff --git a/templates/init/functions/typescript/tsconfig.json b/templates/init/functions/typescript/tsconfig.json index 57b915f3cc9..a609faef355 100644 --- a/templates/init/functions/typescript/tsconfig.json +++ b/templates/init/functions/typescript/tsconfig.json @@ -1,16 +1,17 @@ { "compilerOptions": { - "module": "NodeNext", + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "verbatimModuleSyntax": true, "esModuleInterop": true, - "moduleResolution": "nodenext", "noImplicitReturns": true, "noUnusedLocals": true, "outDir": "lib", "sourceMap": true, - "strict": true, - "target": "es2017" + "skipLibCheck": true, + "strict": true }, - "compileOnSave": true, "include": [ "src" ] From 888bc258758f96927814968ec75149ab0fa8b4c9 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 8 Oct 2025 13:02:48 -0700 Subject: [PATCH 2/4] test: expect lint predeploy for ts init --- src/init/features/functions.spec.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/init/features/functions.spec.ts b/src/init/features/functions.spec.ts index d51f89daedf..58e2396b1c6 100644 --- a/src/init/features/functions.spec.ts +++ b/src/init/features/functions.spec.ts @@ -107,7 +107,10 @@ describe("functions", () => { source: TEST_SOURCE_DEFAULT, codebase: TEST_CODEBASE_DEFAULT, ignore: ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"], - predeploy: ['npm --prefix "$RESOURCE_DIR" run build'], + predeploy: [ + 'npm --prefix "$RESOURCE_DIR" run lint', + 'npm --prefix "$RESOURCE_DIR" run build', + ], }); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ `${TEST_SOURCE_DEFAULT}/package.json`, From 1ac7a8cd3b8ec13655bc5745055f2cda753db07f Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 8 Oct 2025 13:24:51 -0700 Subject: [PATCH 3/4] fix: expect lint hook for existing TS codebases --- src/init/features/functions.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init/features/functions.spec.ts b/src/init/features/functions.spec.ts index 58e2396b1c6..4bfc514fdde 100644 --- a/src/init/features/functions.spec.ts +++ b/src/init/features/functions.spec.ts @@ -150,7 +150,7 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: [], + predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], }, { source: "testsource2", @@ -196,7 +196,7 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: [], + predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], }, ]); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ From e4ab60ad5f4401b85846c6f3b82ce3096afa11f3 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 8 Oct 2025 15:18:48 -0700 Subject: [PATCH 4/4] fix: align reinit test and imports --- src/init/features/functions.spec.ts | 2 +- templates/init/functions/javascript/index.js | 2 +- templates/init/functions/typescript/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/init/features/functions.spec.ts b/src/init/features/functions.spec.ts index 4bfc514fdde..944b0f331f7 100644 --- a/src/init/features/functions.spec.ts +++ b/src/init/features/functions.spec.ts @@ -196,7 +196,7 @@ describe("functions", () => { "firebase-debug.*.log", "*.local", ], - predeploy: ['npm --prefix "$RESOURCE_DIR" run lint'], + predeploy: [], }, ]); expect(askWriteProjectFileStub.getCalls().map((call) => call.args[0])).to.deep.equal([ diff --git a/templates/init/functions/javascript/index.js b/templates/init/functions/javascript/index.js index bae0b216c75..e3ead0670bc 100644 --- a/templates/init/functions/javascript/index.js +++ b/templates/init/functions/javascript/index.js @@ -1,6 +1,6 @@ import { setGlobalOptions } from "firebase-functions"; import * as logger from "firebase-functions/logger"; -import { onRequest } from "firebase-functions/v2/https"; +import { onRequest } from "firebase-functions/https"; // Start writing functions: // https://firebase.google.com/docs/functions diff --git a/templates/init/functions/typescript/index.ts b/templates/init/functions/typescript/index.ts index e04f51e7468..a0e210e811d 100644 --- a/templates/init/functions/typescript/index.ts +++ b/templates/init/functions/typescript/index.ts @@ -1,6 +1,6 @@ import { setGlobalOptions } from "firebase-functions"; import * as logger from "firebase-functions/logger"; -import { onRequest } from "firebase-functions/v2/https"; +import { onRequest } from "firebase-functions/https"; // Start writing functions: // https://firebase.google.com/docs/functions/typescript