Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including Async Function Within Firebase Cloud Functions (eslint "Parsing error: Unexpected token function")

Issue

How can an async helper method be added to a Cloud Functions' index.js file? An async function is required in order to use await when converting fs.writefile into a Promise as explained in this StackOverflow post: fs.writeFile in a promise, asynchronous-synchronous stuff. However, lint does not approve of adding an additional method outside of the exports functions to the index.js file.

Error

Line 84 refers to the helper function async function writeFile.

Users/adamhurwitz/coinverse/coinverse-cloud-functions/functions/index.js 84:7 error Parsing error: Unexpected token function

✖ 1 problem (1 error, 0 warnings)

npm ERR! code ELIFECYCLE

npm ERR! errno 1

npm ERR! functions@ lint: eslint .

npm ERR! Exit status 1

npm ERR!

npm ERR! Failed at the functions@ lint script.

npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

npm ERR! /Users/adamhurwitz/.npm/_logs/2018-12-12T01_47_50_684Z-debug.log

Error: functions predeploy error: Command terminated with non-zero exit code1

Setup

index.js

const path = require('path');
const os = require('os');
const fs = require('fs');
const fsPromises = require('fs').promises;
const util = require('util');
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const {Storage} = require('@google-cloud/storage');
const textToSpeech = require('@google-cloud/text-to-speech');

const storage = new Storage({
  projectId: 'project-id',
});
const client = new textToSpeech.TextToSpeechClient();

admin.initializeApp();

exports.getAudiocast = functions.https.onCall((data, context) => {
  const bucket = storage.bucket('gs://[bucket-name].appspot.com');
  var fileName;
  var tempFile;
  var filePath;

  return client.synthesizeSpeech({
    input: {text: data.text },
    voice: {languageCode: 'en-US', ssmlGender: 'NEUTRAL'},
    audioConfig: {audioEncoding: 'MP3'},
  })
  .then(responses => {
    var response = responses[0]; 
    fileName = data.id + '.mp3'
    tempFile = path.join(os.tmpdir(), fileName);  
    return writeFile(tempFile, response.audioContent)
  })
  .catch(err => {
    console.error("Synthesize Speech Error: " + err);
  })
  .then(() => {
     filePath = "filePath/" + fileName;
     return bucket.upload(tempFile, { destination: filePath })
  })
  .catch(err => {
     console.error("Write Temporary Audio File Error: " + err);
  })
  .then(() => {
   return { filePath: filePath }
  })
  .catch(err => {
     console.error('Upload Audio to GCS ERROR: ' + err);
  });
});

Helper method:

async function writeFile(tempFile, audioContent) {
    await fs.writeFile(tempFile, audioContent, 'binary');
}

Attempted Solution

Enabling Node.js 8 as recommended in the post Cloud Functions for Firebase Async Await style.

  1. Set Node.js version "engines": {"node": "8"}

  2. return await fs.writeFile(tempFile, audioContent, 'binary');

Lint does not like this solution.

like image 899
Adam Hurwitz Avatar asked Dec 12 '18 01:12

Adam Hurwitz


2 Answers

I tried all solutions above which did not work for me. It was due to bad syntax in my package.json :

"scripts": {
    "lint": "eslint ."
  },

changed to :

"scripts": {
    "lint": "eslint"
  },

Like said Burak in the comments, this dot is put by default when we create firebase functions

like image 148
Florian K Avatar answered Sep 21 '22 08:09

Florian K


Your eslint is not configured to understand ECMAScript 2017 syntax. The .eslint.json config file that's created by the Fireabse CLI by default includes this configuration:

"parserOptions": {
  // Required for certain syntax usages
  "ecmaVersion": 6
},

Change it like this to help it understand async/await:

  "ecmaVersion": 2017
like image 32
Doug Stevenson Avatar answered Sep 18 '22 08:09

Doug Stevenson