Skip to content

Instantly share code, notes, and snippets.

@Kamshak Kamshak/README.md
Last active Jun 20, 2018

Embed
What would you like to do?
Serve firebase functions efficiently through express. Doesn't make the PC die as the cloud functions emulator does but is less accurate.

Replacement for firebase functions:serve

Serve firebase functions efficiently through express. Doesn't make the PC die as the cloud functions emulator does but is a bit less closer to the real env they run in. Useful for dev.

This uses a simple express server to serve your functions. It's nice for developing as the restarting is much faster and it doesn't use as much of your CPU/Ram as the cloud functions emulator does.

Setup

  1. Make sure your firebase service account is saved to your functions config under the serviceacc key.
  2. Install dependencies
yarn add express firebase-admin firebase-functions body-parser winston@next json-stringify-safe
yarn global add ts-node typescript nodemon
  1. Download runtime config for emulation
firebase functions:config:get > .runtimeconfig.json

Running it

ts-node emulate-no-bs.ts

To get quick auto restarts on changes use nodemon

nodemon
import * as express from 'express';
import * as fs from 'fs';
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as bodyParser from 'body-parser';
import * as _winston from 'winston'
const { format } = require('logform')
const winston = _winston as any;
import * as stringify from 'json-stringify-safe';
const fnConfig = require('./.runtimeconfig.json');
const firebaseConf = {
credential: admin.credential.cert(fnConfig.serviceacc),
databaseURL: `https://${fnConfig.serviceacc.project_id}.firebaseio.com`
};
process.env.CLOUD_RUNTIME_CONFIG = JSON.stringify({ ...require('./.runtimeconfig.json'), firebase: firebaseConf });
admin.initializeApp(firebaseConf);
const index = require('./functions/src/index');
const extractTriggers = require('firebase-tools/lib/extractTriggers');
const triggers = [];
extractTriggers(index, triggers);
const httpsTriggers = triggers
.filter(trigger => trigger.httpsTrigger);
const app = express();
const prefix = '/' + fnConfig.serviceacc.project_id + '/us-central1';
const prefixApp = express();
prefixApp.get('/', (req, res) => res.send('hello'));
httpsTriggers.map(({ name, entryPoint }) => {
console.log(`\u2713 functions: ${name}: http://localhost:5000${prefix}/${name}`);
const subApp = express();
subApp.use(bodyParser.json());
subApp.all('*', index[entryPoint]);
prefixApp.use('/' + name, subApp);
});
app.use(prefix, prefixApp);
app.use(function errorHandler(err, req, res, next) {
if (err) {
logger.error(err, { err, url: req.url, body: req.body, query: req.query });
}
});
app.listen(5000);
function getFullErrorStack(ex: any) {
var ret = ex.stack || ex.toString()
if (ex.cause && typeof ex.cause === 'function') {
var cex = ex.cause()
if (cex) {
ret += '\nCaused by: ' + getFullErrorStack(cex);
}
}
return ret;
}
const alignedWithColorsAndTime = format.combine(
format.colorize(),
format.timestamp(),
format.printf((info: any) => {
let errStr = ''
if (info.err) {
errStr = `${getFullErrorStack(info.err)}`
}
const toPrint = Object.assign({}, info, {
level: undefined,
message: undefined
})
if (toPrint['err']) {
toPrint['err'] = `${info.err.name}: ${info.err.message}`
}
const json = stringify(toPrint, null, 2)
return `${info.timestamp} ${info.level}: ${info.message} ${json} ${errStr}`
})
);
var logger: _winston.Winston = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
});
logger.add(
new winston.transports.Console({
format: alignedWithColorsAndTime,
level: process.env.LOG_LEVEL || 'silly',
colorize: true
})
);
{
"watch": [
"functions/src",
"emulate-no-bs.ts",
".runtimeconfig.json"
],
"ext": "ts,json",
"exec": "ts-node emulate-no-bs.ts",
"delay": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.