如何实现Firebase Functions(TypeScript)在React应用/模拟器中保存自动转译
问题描述
我有一个基于create-react-app的React应用,已集成Firebase及Firebase Functions。此前Functions使用普通JavaScript,近期已迁移至TypeScript,React应用本身也采用TypeScript开发。
此前修改Functions代码后,运行命令firebase emulators:start --import ./firestore --export-on-exit --inspect-functions的终端会自动检测到变更并注册新函数。
迁移至TypeScript后遇到以下问题:
- 新的Functions TypeScript文件无法在保存时自动编译;
- 需打开Functions文件夹并执行
npm run build将TypeScript转译为JavaScript后才能正常运行; - 在Functions文件夹执行
npm run build时会抛出node_module错误。
我希望在主项目中编辑Functions的.ts文件并保存后,能自动完成转译,从而实现模拟器的热重载效果。
当前文件夹结构
|-functions |---src |------index.ts |---lib |------functions/src/index.js |---tsconfig.json |---package.json |-src |-tsconfig.json |-package.json
相关配置文件
functions/tsconfig.json
{ "compilerOptions": { "module": "commonjs", "noImplicitReturns": true, "noUnusedLocals": true, "outDir": "lib", "sourceMap": true, "strict": true, "target": "es2017", "typeRoots": ["node_modules/@types"] }, "compileOnSave": true, "include": [ "src" ] }
functions/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/functions/src/index.js", "dependencies": { "@sendinblue/client": "^3.3.1", "firebase-admin": "^11.8.0", "firebase-functions": "^4.3.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": "^4.9.0" }, "private": true }
根目录tsconfig.json
{ "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "target": "ESNext", "removeComments": true, "allowSyntheticDefaultImports": true, "jsx": "react", "allowJs": true, "baseUrl": "src", "esModuleInterop": true, "resolveJsonModule": true, "downlevelIteration": true, "outDir": "build", "paths": { "*": ["src/*"] }, "lib": ["esnext", "dom", "dom.iterable"], "sourceMap": true, "noImplicitAny": false }, "exclude": ["node_modules", "build"], "include": [ "./src", "webpack.config.ts", "public/firebase-messaging-sw.js", "declarations.d.ts" ] }
根目录package.json
{ ... "scripts": { "start": "GENERATE_SOURCEMAP=false react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "ts-coverage": "typescript-coverage-report" }, ... "devDependencies": { "@firebase/rules-unit-testing": "^2.0.4", "@types/jest": "^28.1.2", "@types/node": "^18.0.0", "@types/react": "^18.0.14", "@types/react-dom": "^18.0.5", "@typescript-eslint/eslint-plugin": "^5.59.6", "@typescript-eslint/parser": "^5.59.6", "fs": "^0.0.1-security", "http": "^0.0.1-security", "typescript": "^4.9.5", "typescript-coverage-report": "^0.6.4" } }
我曾尝试使用tsconfig的extends和includes配置来恢复原有功能,但未成功,恳请针对上述问题提供指导。
解决方案
1. 实现自动编译与模拟器热重载
要实现修改.ts文件后自动编译并触发模拟器重载,需要同时启动TypeScript监听编译和Firebase模拟器两个进程,有两种方式:
方式一:多终端分开启动
- 打开第一个终端,进入functions目录,执行:
该命令启动npm run build:watchtsc --watch,会监听src目录下的.ts文件变更,自动编译到lib目录。 - 打开第二个终端,在项目根目录执行原有模拟器命令:
模拟器会监听lib目录的编译产物变化,自动重载函数。firebase emulators:start --import ./firestore --export-on-exit --inspect-functions
方式二:用并发工具一键启动(推荐)
先在根目录安装并发命令工具concurrently:
npm install concurrently --save-dev
然后在根目录package.json的scripts中新增脚本:
"emulators:start": "concurrently \"cd functions && npm run build:watch\" \"firebase emulators:start --import ./firestore --export-on-exit --inspect-functions\""
之后直接在根目录执行:
npm run emulators:start
即可同时启动编译监听和模拟器,实现修改.ts文件后的自动编译+热重载。
2. 解决npm run build时的node_modules错误
这个问题通常由依赖未正确安装或版本冲突导致:
- 删除functions目录下的
node_modules和package-lock.json(或yarn.lock),进入functions目录执行:npm install - 统一根目录与functions目录的TypeScript版本(比如都改为4.9.5),避免跨目录版本冲突引发编译错误。
3. 优化tsconfig配置(可选)
保持根目录与functions目录的tsconfig独立更清晰,无需用根目录配置管理functions编译:
- 确保functions的tsconfig中
outDir正确指向lib目录,include仅包含src下的.ts文件; - 根目录tsconfig专注于React应用编译,无需引入functions目录。
内容的提问来源于stack exchange,提问作者Jed Grant
相关产品推荐
相关产品推荐

