Firebase 托管 + 云功能

Firebase Hosting + Cloud Function

难以部署我的功能以及托管。

问题是,我已经让它们在单独的分支上独立工作,但是..当尝试集成托管和我的云功能时,我的云功能似乎没有部署。我的终端没有收到任何错误,当我在 firebase 控制台中单击 'functions' 时,它是默认屏幕,就好像没有部署任何功能一样。

这是我的 firebase.json 托管 + 功能部署。 托管在这里工作,但功能没有部署

{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      },
      {
        "source": "/api/v1/**",
        "function": "webApi"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint"
    ],
    "source": "functions"
  }
}

这是我的 firebase.json,只有功能,没有托管

{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "/api/v1/**",
        "function": "webApi"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint"
    ],
    "source": "functions"
  }
}

这是我的 functions/index.js

const functions = require('firebase-functions')
const admin = require('firebase-admin')
const serviceAccount = require('./serviceAccount.json')

const express = require('express')
const bodyParser = require('body-parser')

const _ = require('lodash')
const { getObjectValues } = require('./helper-functions.js')
const json2csv = require('json2csv').parse

admin.initializeApp({
  ...,
})
const db = admin.firestore()

const app = express()
const main = express()

main.use('/api/v1', app)
main.use(bodyParser.json())
exports.webApi = functions.https.onRequest(main)

app.get('/test', (request, response) => {
  response.send('API TEST')
})

app.get('/surveys', (request, response) => {
  const surveyCollection = db.collection('/surveys')
  return (
    surveyCollection
      .get()
      // eslint-disable-next-line promise/always-return
      .then(querySnapshot => {
        let surveyList = []
        querySnapshot.forEach(doc => {
          const survey = doc.data()
          surveyList.push(survey)
        })
        response.send(surveyList)
      })
  )
})

app.get('/surveys/:survey', (request, response) => {
  const surveyId = request.params.survey
  const userAnswers = db.collection(`/surveys/${surveyId}/submissions`)
  return (
    userAnswers
      .get()
      // eslint-disable-next-line promise/always-return
      .then(querySnapshot => {
        let surveySubmissions = []
        querySnapshot.forEach(doc => {
          const userSubmission = doc.data()
          surveySubmissions.push({
            ..._.mapValues(userSubmission.answers, getObjectValues), // format answers
            ...userSubmission.anonUser,
          })
        })
        response.setHeader('Content-disposition', 'attachment; filename=cna.json')
        response.set('Content-Type', 'application/json')
        response.status(200).send(surveySubmissions)
      })
      .catch(error => {
        console.log(error)
      })
  )
})

Hosting + functions 分支,我输入 'firebase deploy'

terminal output:

    i  deploying functions, hosting
Running command: npm --prefix "$RESOURCE_DIR" run lint

> functions@ lint \surveyplus-cna\functions
> eslint .

+  functions: Finished running predeploy script.
i  functions: ensuring necessary APIs are enabled...
+  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (82.32 KB) for uploading
+  functions: functions folder uploaded successfully
i  hosting[surveyplus-effd5]: beginning deploy...
i  hosting[surveyplus-effd5]: found 30 files in build
+  hosting[surveyplus-effd5]: file upload complete
i  functions: updating Node.js 8 function webApi(us-central1)...
+  functions[webApi(us-central1)]: Successful update operation.
i  hosting[surveyplus-effd5]: finalizing version...
+  hosting[surveyplus-effd5]: version finalized
i  hosting[surveyplus-effd5]: releasing new version...
+  hosting[surveyplus-effd5]: release complete

+  Deploy complete!

On cloud function only branch firebase deploy输出

=== Deploying to '...'...

i  deploying functions, hosting
Running command: npm --prefix "$RESOURCE_DIR" run lint

> functions@ lint \surveyplus-cna\functions
> eslint .

+  functions: Finished running predeploy script.
i  functions: ensuring necessary APIs are enabled...
+  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (82.33 KB) for uploading
+  functions: functions folder uploaded successfully
i  hosting[surveyplus-effd5]: beginning deploy...
i  hosting[surveyplus-effd5]: found 30 files in build
+  hosting[surveyplus-effd5]: file upload complete
i  functions: updating Node.js 8 function webApi(us-central1)...
+  functions[webApi(us-central1)]: Successful update operation.
i  hosting[surveyplus-effd5]: finalizing version...
+  hosting[surveyplus-effd5]: version finalized
i  hosting[surveyplus-effd5]: releasing new version...
+  hosting[surveyplus-effd5]: release complete

+  Deploy complete!

您的 Cloud Functions 已正确部署,因为我可以直接调用 /api/v1/test 路由(在撰写本文时)。

但是,在您的 firebase.json 文件中,重写的顺序不正确,如 docs 中突出显示的那样:

Important: Within the rewrites attribute, the Hosting response will obey the rule specified by the first source glob that captures the requested path.

{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "/api/v1/**",
        "function": "webApi"
      },
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint"
    ],
    "source": "functions"
  }
}

因此,它们没有发送 /api/v1/test 调用以供您的 Cloud Function 处理,而是错误地发送到您的 React 应用程序。调换顺序应该可以解决这个问题。

另外请注意,如果您打算将所有调用格式化和解析为 JSON,则应重新排序 main.use 调用。我还会使用 express Router 而不是完整的 express() 实例。

const main = express(); // full express instance
const app = express.Router(); // "child" express instance

main.use(bodyParser.json()) // parse body as json, then hand over to app
main.use('/api/v1', app)