Firebase-tools: firebase serve --only functions not hot reloading

Created on 1 May 2018  ·  43Comments  ·  Source: firebase/firebase-tools

Version info

firebase --version
3.18.4

Platform Information

Ubuntu 18.04 x64

Steps to reproduce

  1. Firebase cloud functions project with TypeScript using yarn
  2. yarn build --watch
  3. View a HTTPS function in browser
  4. Update function response
  5. Refresh page in browser

Expected behavior

Browser displays updated content

Actual behavior

The page only updates after restarting the firebase serve command. I have confirmed that the output in lib has been updated.

> firebase serve --only functions --debug                                                                                                                                                             [17:29:27]
[2018-05-01T00:29:30.975Z] ----------------------------------------------------------------------
[2018-05-01T00:29:30.978Z] Command:       /home/shane/.nvm/versions/node/v6.11.5/bin/node /home/shane/.yarn/bin/firebase serve --only functions --debug
[2018-05-01T00:29:30.978Z] CLI Version:   3.18.4
[2018-05-01T00:29:30.979Z] Platform:      linux
[2018-05-01T00:29:30.979Z] Node Version:  v6.11.5
[2018-05-01T00:29:30.979Z] Time:          Mon Apr 30 2018 17:29:30 GMT-0700 (PDT)
[2018-05-01T00:29:30.979Z] ----------------------------------------------------------------------

[2018-05-01T00:29:30.986Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[2018-05-01T00:29:30.986Z] > authorizing via signed-in user
[2018-05-01T00:29:30.988Z] >>> HTTP REQUEST GET https://admin.firebase.com/v1/projects/nativ-dev  

 Mon Apr 30 2018 17:29:30 GMT-0700 (PDT)
[2018-05-01T00:29:31.433Z] <<< HTTP RESPONSE 200 server=nginx, date=Tue, 01 May 2018 00:29:31 GMT, content-type=application/json; charset=utf-8, content-length=128, connection=close, x-content-type-options=nosniff, strict-transport-security=max-age=31536000; includeSubdomains, cache-control=no-cache, no-store
[2018-05-01T00:29:31.437Z] >>> HTTP REQUEST GET https://admin.firebase.com/v1/database/nativ-dev/tokens  

 Mon Apr 30 2018 17:29:31 GMT-0700 (PDT)
[2018-05-01T00:29:31.926Z] <<< HTTP RESPONSE 200 server=nginx, date=Tue, 01 May 2018 00:29:31 GMT, content-type=application/json; charset=utf-8, content-length=256, connection=close, x-content-type-options=nosniff, strict-transport-security=max-age=31536000; includeSubdomains, cache-control=no-cache, no-store
[2018-05-01T00:29:31.927Z] >>> HTTP REQUEST GET https://cloudresourcemanager.googleapis.com/v1/projects/nativ-dev  

 Mon Apr 30 2018 17:29:31 GMT-0700 (PDT)
[2018-05-01T00:29:32.335Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=UTF-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Tue, 01 May 2018 00:29:32 GMT, server=ESF, cache-control=private, x-xss-protection=1; mode=block, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, alt-svc=hq=":443"; ma=2592000; quic=51303433; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=":443"; ma=2592000; v="43,42,41,39,35", accept-ranges=none, connection=close

=== Serving from '/home/shane/source/firebase'...

i  functions: Preparing to emulate functions.
[2018-05-01T00:29:32.733Z] Fetching environment
[2018-05-01T00:29:32.736Z] >>> HTTP REQUEST GET https://mobilesdk-pa.googleapis.com/v1/projects/766196581577:getServerAppConfig

 Mon Apr 30 2018 17:29:32 GMT-0700 (PDT)
[2018-05-01T00:29:33.255Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=UTF-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Tue, 01 May 2018 00:29:33 GMT, server=ESF, cache-control=private, x-xss-protection=1; mode=block, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, alt-svc=hq=":443"; ma=2592000; quic=51303433; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=":443"; ma=2592000; v="43,42,41,39,35", accept-ranges=none, connection=close
[2018-05-01T00:29:33.256Z] Starting @google-cloud/functions-emulator
[2018-05-01T00:29:34.318Z] Parsing function triggers
i  functions: No HTTPS functions found. Use firebase functions:shell if you would like to emulate other types of functions.
i  functions: No HTTPS functions found. Use firebase functions:shell if you would like to emulate other types of functions.
✔  functions: createCustomerOnCall: http://localhost:5000/nativ-dev/us-central1/createCustomerOnCall
✔  functions: createCustomerHttps: http://localhost:5000/nativ-dev/us-central1/createCustomerHttps
info: User function triggered, starting execution
info: Execution took 19 ms, user function completed successfully
info: User function triggered, starting execution
info: Execution took 1 ms, user function completed successfully
functions bug

Most helpful comment

In case others end up here, here's actually how to set it up in functions/package.json so tsc -w runs separately from firebase serve:

{
  "name": "functions",
  "scripts": {
...
    "serve": "tsc -w | firebase serve --only functions",
...
  },

In other words, run tsc -w and pipe the output into firebase serve. I don't think the pipe actually sends anything; I think when the source changes, tsc re-runs, and firebase serve is watching tsc's output dir (lib) so it reloads. So the pipe is really just there for process management.

All 43 comments

I have just tried this on a different machine (Debian Stretch) with a fresh project (firebase init) and the same thing happened with the hello world function. I did notice that if I changed the source before sending a request to the function, but after the function was ready to serve, I could get it to hot reload once and then would stop working again.

I have tried creating a new project (firebase init) on a Mac and a Linux machine, It works on Mac and not on Linux.

I did some experimenting and I could get the hello world example in JavaScript to hot reload but not the TypeScript example. It seems that firebase serve only watches the index.js in the directory configured in `firebase.json.

To get my project reloading for TypeScript (and I assume more complex JavaScript layouts that have more than just index.js) I had to use Webpack to output a single file functions/lib/index.js and configure Firebase to look for my functions code in functions/list. This then makes hot reload work for both firebase functions:shell and firebase serve.

When I was using tsc (as per the firebase init template) the code would only reload if I modified the resulting index.js file. My current workflow is to run webpack --watch in one terminal with firebase serve --only functions in another. I now get hot reload. It would be good if I could go back to the default from firebase init.

Updated firebase.json

{    
  "functions": {
    "predeploy": "npm --prefix functions run build",
    "source": "functions/list"
  }
}

@safarmer What does your functions/package.json look like? Does it have a main field?

I had started using the default generated by firebase init

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc --project tsconfig.json",
    "serve": "yarn run build && firebase serve --only functions",
    "shell": "yarn run build && firebase functions:shell",
    "start": "yarn run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "main": "lib/index.js",
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
  },
  "private": true
}

The simplest way I have to replicate the issue:

  1. firebase init && cd functions && yarn
  2. Uncomment the helloWorld function
  3. mkdir src/handlers && mv src/index.ts src/handlers/helloworld.ts
  4. echo "export * from './handlers/helloworld';" > src/index.ts
  5. In terminal 1: yarn build --watch
  6. In terminal 2: firebase serve --only functions

Visiting the URL in a browser, you see the hello world message. If you change the string returned from the handler in handler.ts, the only way to get the result to change is to restart the firebase serve command.

Adding "source": "functions/lib" to firebase.json make the code hot reload if you change anything in functions/lib but lower lever directories do not trigger a reload. It is possible to run touch lib/injex.js to trigger a reload. For example, changing a handler in src/index.ts triggers reload, but changing src/handlers/helloworld.ts does not.

@laurenzlong the best I have so far is (taken from the default result of firebase init) is below. With this, I still need to run touch lib/index.js. Antoher issue with this is that firebase deploy no longer works.

firebase.json

{
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ],
    "source": "functions/lib"
  }
}

functions/package.json

{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "~5.12.0",
    "firebase-functions": "^1.0.1"
  },
  "devDependencies": {
    "tslint": "^5.8.0",
    "typescript": "^2.5.3"
  },
  "private": true
}

@laurenzlong I have a simple example you can clone to repro the issue on Linux:
https://github.com/safarmer/firebase-functions

Thanks for the repro! I'll take a look next week.

The same problem here :)
To me, it seems like firebase serve is not supporting Typescript for now...

I have compared the files you asked to with the ones @safarmer sent and I have the same configurations. Doesn't surprise me as this is the official configuration to use with TypeScript

I think the problem is that firebase serve is not listening for changes in the functions "source" directory and won't run the predeploy scripts, defined in the firebase.json.

Would be great if this would be added. :D

Ahh and would be great if I could define other predeploy scripts for firebase serve, so I won't have to run for example tslint in testing :)

@IchordeDionysos I don't think it just TypeScript. I tried to do the same thing as my example in JavaScript and it seemed to do the same thing. I think the issue is with the server only looking at the entrypoint and not the rest of the code. Hopefully the firebase team can shed some light on the issue soon.

@laurenzlong manually installing watchman seems to make things work (thanks @tstirrat for the suggestion)

Thanks for the detailed repro @safarmer , very helpful. I was able to track down the root of the issue and filed https://github.com/GoogleCloudPlatform/cloud-functions-emulator/issues/207. Please follow that issue.

For others coming here, install the watchman from source or Linuxbrew, not the npm package

@laurenzlong I can reproduce this issue in Windows and in particular index.ts change is not being detected. I'm having to manually run tsc. The change is then detected and the function is reloaded.
Should I open a separate issue?

quick notes: sometimes info: Worker for helloWorld closed due to file changes. is detected on the ts but lib isnt refreshed. other times its not detected at all. manually running tsc always reloads the function.

@tstirrat installing watchman on windows as per instructions doesnt seem to work

What errors are you specifically running into when installing watchman?

No errors when installing watchman. But serving functions doesn't hot
reload. I have to stop serving, build, and serve again after every change.

On Wed, Nov 21, 2018 at 1:01 AM Kevin Jian notifications@github.com wrote:

What errors are you specifically running into when installing watchman?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/758#issuecomment-440460196,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AHgHbeA_iECsIMH3V9P7NQypsmudF_IQks5uxInggaJpZM4Tta12
.

Reopening due to multiple reports of this still not working on Windows

Still not working on Ubuntu 18.04 with Node.js v10.15.0

Hi everyone, thanks for the detailed reports. @afuggini I get 404 when I click that link, are the permissions set correctly on that repo for public viewing? There is another issue similar to this one: https://github.com/firebase/firebase-tools/issues/1022. I hear that this issue is creating a pain point for local development with Typescript.

I've filed a bug in our internal tracker: 123266946. I cannot commit to when we can get around to this, but know that this is being tracked. PRs are most welcome!

I also encountered this error. I was unable to create any workaround so I have to restart server after every change. If you know a reliable workaround, please let me know.

@ondratra can you provide your current CLI version, OS platform, and let us know if you're working with anything other than npm (e.g. yarn)?

@bkendall I am on Debian(sid). Typescript source files are watched and compiled via tsc -w + functions are served via firebase --only functions serve. package.json contains correct path to
js output file {"main": "dist/src/index.js", ...}. I even tried to use tsc-watch package and explicitly touch index file, but with no success.

$ firebase --version
6.3.1

Guys, check my previous comment. The issue is related to the cloud-functions-emulator. It is using the fs watch feature, which has a known issue on linux. So don't expect a solution directly fromfirebase-tools.

@ribizli thx, the link you've shared surely explains the nature of the problem. But I still didn't find any workaround. Is there any possibility to watch files via custom script and forcing firebase to reload?

@ondratra fork @google-cloud/functions-emulator, add node-watch as I mentioned in my linked comment, npm link the package. Reinstall firebase-tools: it has @google-cloud/functions-emulator as optional dependency, so your linked version will be used.

And finally: you can make a PR to https://github.com/GoogleCloudPlatform/cloud-functions-emulator and hope they will accept and release soon. (I could live with my workaround, so I haven't contributed)

functions -> index.js after saving this file, how i can start "firebase serve" autorun

Workaround from https://github.com/GoogleCloudPlatform/cloud-functions-emulator/issues/196 (thanks @dirkjot):

This worked for me, here are full instructions and a fix for @ribizli's small typo:

  • Find your @google-cloud directory, probably in your node_modules (see below for Firebase)
  • cd functions-emulator
  • Add node-watch: npm install --save node-watch
  • Edit the file src/supervisor/worker.js
  • Around line 180, you will find fs.watch(localdir, {. Replace this with require('node-watch')(localdir, { .

Using Firebase with typescript, all I have to do is run tsc -w in a separate terminal (the watch variant of npm run build). I can now change my source code and the emulator will notice the changes.

If you installed firebase globally, you can find these files by navigating to cd $(npm root -g)/firebase-tools/node_modules/@google-cloud.

Hey folks -

This bug related to the legacy Cloud Functions emulator's hot-reloading ability. As of May '19 we no longer use google-cloud/functions-emulator in firebase-tools so this changes the nature of the bug (I believe the new nature is that it does not exist).

I appreciate everyone working hard and figuring out workarounds and finally our new emulator should allow for any transpiled languages to hot-reload as long as you're running your watcher (like tsc -w) separately from firebase serve.

With the new emulator backend we've resolved this issue and now all workarounds in this thread are out of date, so I'm going to close this thread to avoid confusion.

If you're still seeing any unintended behavior, please open a new bug.

Thanks again!

In case others end up here, here's actually how to set it up in functions/package.json so tsc -w runs separately from firebase serve:

{
  "name": "functions",
  "scripts": {
...
    "serve": "tsc -w | firebase serve --only functions",
...
  },

In other words, run tsc -w and pipe the output into firebase serve. I don't think the pipe actually sends anything; I think when the source changes, tsc re-runs, and firebase serve is watching tsc's output dir (lib) so it reloads. So the pipe is really just there for process management.

Installing concurrently worked for me:

"build:watch": "tsc -w && cp src/*.json lib",
"serve": "firebase serve --only functions",
"start": "concurrently \"npm run build:watch\" \"npm run serve\"",

For me on [email protected] hot reloading is not working out of the box. I modified the build in functions/package.json to be tsc -w as

{
  "name": "functions",
  "scripts": {
   ...
      "build": "tsc -w",
   ...
  },

This will keep the watch active for the functions when I run npm run build, then from another terminal I ran firebase emulators:start.

@rami-alloush that's the workflow I use as well. The emulators don't re-build your code but they do hot reload the built code.

another version

{
    "build": "tsc -w &>/dev/null &",
    "shell": "npm run build && firebase functions:shell",
}

this runs tsc in background and quiet, so you do not need another terminal.

Thanks for the repro! I'll take a look next week.

Is it?

Facing the same issue with typescript, hot-reloading not working.

same... hot reloading not working, and it is difficult to get the emulator to recognize changes at all...

@oluckyman solved issue. very nice

https://github.com/firebase/firebase-tools/issues/758#issuecomment-620096052

[UPDATED]

  • firebase-tools => 8.7.0

My solution:

package.json

...
 "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc -w --preserveWatchOutput",
    "serve": "tsc && firebase emulators:exec --ui --only functions,firestore 'yarn build'",
    "shell": "yarn run build && firebase functions:shell",
    "start": "yarn run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
...

Run yarn serve

Demo

Aug-06-2020 14-05-38

This works perfectly fine for me at the moment on firebase-tools version 8.8.1 using typescript. Thankyou for the tips guys @moifort @garyo @safarmer @abeisgoat :1st_place_medal: :

"scripts": {
    ...
    ...
    "serve": "yarn build | firebase emulators:start --only functions",
    "build": "./node_modules/.bin/tslint --project tsconfig.json && ./node_modules/.bin/tsc --watch --preserveWatchOutput"
  },
Was this page helpful?
0 / 5 - 0 ratings