TypeScript functions
A TypeScript codebase loads from what its compiler writes, not from your
sources: main in functions/package.json is lib/index.js. So the code
has to be compiled before it loads, and again after every save. With
--build, Firenook runs your codebase’s own compiler for you, in the same
terminal as the emulators. This page shows what it does, what a type error
looks like, and how it stops a test run.
A TypeScript project
Section titled “A TypeScript project”firenook init writes a TypeScript codebase by default, from the official
template. Without a terminal, --yes does the set-up too: it installs the
codebase’s packages and builds it once (--no-pin here leaves Firenook out
of the project’s package.json):
$ npx firenook init --language typescript --project demo-shop --yes --no-pinFirenook init: project demo-shop in ~/demo-shop wrote ~/demo-shop/firebase.json wrote ~/demo-shop/.firebaserc wrote ~/demo-shop/firestore.rules wrote ~/demo-shop/firestore.indexes.json wrote ~/demo-shop/storage.rules wrote ~/demo-shop/functions/package.json wrote ~/demo-shop/functions/tsconfig.json wrote ~/demo-shop/functions/src/index.ts wrote ~/demo-shop/functions/.gitignore wrote ~/demo-shop/.gitignore done Agents: .mcp.json for Claude Code (0.0 s) done Packages: npm install in functions/, 241 packages (2.3 s) done Build: tsc, into functions/lib (0.8 s)Next steps: npx firenook emulators:start --keep-data --buildIts scripts, in part of functions/package.json, are the ones --build
runs:
{ "main": "lib/index.js", "scripts": { "build": "tsc", "build:watch": "tsc --watch", "serve": "firenook emulators:start --only functions --build" }}firebase.json gets a predeploy that runs build, as a deploy needs.
Start a new project covers the rest of
init.
Compile as you save with –build
Section titled “Compile as you save with –build”npx firenook emulators:start --buildFor each Functions codebase, Firenook runs its build:watch script beside
the emulators, waits for the first compile, then loads the codebase. The
compiler keeps running: save src/index.ts, the compiler writes lib/, and
the codebase reloads. In the plain output:
Build: functions runs its build:watch script, and Firenook loads what it writes on every savebuild functions: compiled, no errorsfirenook: Starting emulators: auth, functions, firestore, pubsub, storageIn a terminal, the start-up card has a row for the compile:
│ Build ✓ 525 ms functions · build:watch │A save that changes Hello from Firebase! was answered with the new text
1.4 s later, with no restart:
19:35:24 ↻ reloaded 276 ms 1 function · defaultA codebase with a build script but no build:watch is built once, before
the start. Firenook compiles nothing itself: the scripts are your project’s,
the same ones a deploy’s predeploy runs, so what loads locally is what a
deploy builds.
Type errors
Section titled “Type errors”A compile with errors puts them in the log, with where they are and what the compiler said. On the terminal screen:
19:35:27 ✕ build 1 error · functions │ src/index.ts:6:9 Type 'string' is not assignable to type 'number'. 19:35:28 ↻ reloaded 195 ms 1 function · default 19:35:32 ✓ build no errors · functions 19:35:33 ↻ reloaded 179 ms 1 function · defaultand in the plain output:
build functions: src/index.ts:6:9 TS2322: Type 'string' is not assignable to type 'number'.build functions: 1 errortsc still writes lib/ when there are type errors, so the code it wrote
loads and answers, as the reloaded line after the error shows. The error is
a warning to read, not a stop. Once the next save compiles cleanly, the log
says no errors.
Run your tests on a fresh build
Section titled “Run your tests on a fresh build”emulators:exec --build runs each codebase’s build script once, before
the emulators start, and runs the tests only when it succeeds:
$ npx firenook emulators:exec --build "npm test"Build: functions runs its build script before the emulators startbuild functions: src/index.ts:6:9 TS2322: Type 'string' is not assignable to type 'number'.build functions: build failed (exit code 2)Firenook: the build in functions failed (npm run build); the tests did not runTrimmed to the build. The command exits with 1, so CI fails at the build, not at a test that ran stale code. When the build succeeds, the tests run as usual:
$ npx firenook emulators:exec --build "npm test"Build: functions runs its build script before the emulators startAll emulators ready✔ helloWorld answers (24.208875ms)ℹ tests 1ℹ pass 1ℹ fail 0Trimmed. Run your tests covers test runners and CI.
From the functions folder
Section titled “From the functions folder”The serve script init writes starts only Functions, with --build. Run
it from functions/: Firenook finds the project’s firebase.json in the
folder above, as the official CLI does.
$ cd functions && npm run serveBuild: functions runs its build:watch script, and Firenook loads what it writes on every savebuild functions: compiled, no errorsfirenook: Starting emulators: functionsTrimmed.
Running the compiler yourself
Section titled “Running the compiler yourself”Without --build, run the compiler in watch mode in another terminal,
npm run build:watch in functions/, and start the emulators as usual.
Firenook reloads the codebase whenever the compiler writes lib/, so a save
reaches your functions either way. --build adds three things:
- One terminal. The compiler starts and stops with the emulators.
- No stale start. The codebase loads after the first compile, not from
whatever
lib/held before. - Errors where you look. Type errors show in Firenook’s log and on its screen, next to the calls and reloads they affect.
- Debugging and reload on save: reloads, a debugger and each call’s logs.
- Cloud Functions: the triggers Firenook delivers.