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

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

问题

如何将 async 辅助方法添加到 Cloud Functions 的 index.js 文件中?在将 fs.writefile 转换为 Promise 时,需要一个 async 函数才能使用 await,如本 Whosebug post 中所述:fs.writeFile in a promise, asynchronous-synchronous stuff。但是,lint 不赞成在 exports 函数之外向 index.js 文件添加额外的方法。

错误

84指的是辅助函数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

设置

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);
  });
});

辅助方法:

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

尝试的解决方案

按照 post .

中的建议启用 Node.js 8
  1. Set Node.js version "engines": {"node": "8"}

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

Lint 不喜欢这个解决方案。

Node.js 8 - 承诺

按照 post .

中的建议启用 Node.js 8
  1. Set Node.js version "engines": {"node": "8"}
  2. 使用promisify

    const writeFile = util.promisify(fs.writeFile);

    return writeFile(tempFile, response.audioContent, 'binary')

前 Node.js 8 - 手动转换

这是一种将回调转换为 Promises 的旧方法,如此 所概述的关于 Google 文本转语音 (TTS 的更具体问题).

const writeFilePromise = (file, data, option) => {
   return new Promise((resolve, reject) => {
       fs.writeFile(file, data, option, error => {
          if (error) reject(error);
          resolve("File created! Time for the next step!");
       });
   });
};

return writeFilePromise(tempFile, response.audioContent, 'binary');

您的 eslint 未配置为理解 ECMAScript 2017 语法。 .eslint.json 默认情况下由 Fireabse CLI 创建的配置文件包含此配置:

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

改成这样帮助它理解async/await:

  "ecmaVersion": 2017

更改 .eslintrc.json 中的 ecmaVersion

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

我尝试了上面所有的解决方案,但都不适合我。这是由于我的语法错误 package.json :

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

更改为:

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

就像 Burak 在评论中所说的那样,这个点是我们创建 firebase 函数时默认放置的

.eslint.json

“解析器选项”:{ // 对于某些语法用法是必需的 “ecma版本”:6 }, 像这样更改它以帮助它理解 async/await:

“ecma版本”:2017

package.json “脚本”:{ “lint”:“eslint。” }, 更改为:

“脚本”:{ “lint”:“eslint” },

裁判 Web 队长和 Doug Stevenson

问题 ES7 您必须将其更改为 ES8

  • 2016 年发布的 ES7 没有 async,await 和箭头函数
  • 2017年发布的ES8有async,await和arrow函数

你必须检查你的 .eslintrc 你至少有 es8 或 2017,这是相同的。

如果文件是 .eslintrc.json

“ecma版本”:2017 要么 “ecma版本”:8

如果文件是 .eslintrc.js

环境:{ es8:true, node:true }

对于某些人来说它是这样工作的

在我的例子中,它通过更改 package.json

解决了

“脚本”:{“lint”:“eslint。” },

更改为:

“脚本”:{“lint”:“eslint”},

正如乔纳森所说,但我想知道为什么?

然后我意识到我有两个名为

的文件
  • .eslintrc.js
  • .eslintrc.json

this is eslintrc.json

this is eslintrc.json

如您所见,两个同名文件中的 ecmaScript 版本不同,

  • "ecmaVersion": 2017 // 等于文件中的 es8: .eslintrc.json
  • es6: true, // 于 2015 年 6 月在文件中发布:.eslintrc.js

所以当我们 运行 : npm 运行 lint 它 运行s .eslintrc.js with es6:true 所以解决这个冲突只是 delete .eslintrc.js 因为它有错误的 ecmaScript.

如果您有 .eslint.js - 只需将 es6: true 更改为 es2017: true

例如:

  env: {
    es6: true,
    node: true,
  },

变为:

  env: {
    es2017: true,
    node: true,
  },

ESLint language options doc 中有更多详细信息。