迁移 Angular Universal firebase 后,云函数抛出错误

Posted

技术标签:

【中文标题】迁移 Angular Universal firebase 后,云函数抛出错误【英文标题】:Cloud functions throws error after migrating Angular Universal firebase 【发布时间】:2020-04-19 22:19:29 【问题描述】:

我有一个托管在 Firebase 中的 SPA,我一直在使用 Firestore 来存储数据。我还利用云功能进行一些 https 操作和某些其他数据库读写。

最近我使用 Angular Universal 更新了从客户端到服务器端的渲染逻辑,这非常成功。这是我关注的链接:https://fireship.io/lessons/angular-universal-firebase/

基本上,我已经创建了一个 https 函数来在云函数中呈现 s-s-r。

const universal = require(`$process.cwd()/dist/server`).app;
exports.api = functions.https.onRequest(app); //Application related endpoint line makepayment, createorder etc.,
exports.s-s-r = functions.https.onRequest(universal);

现在,一旦我部署了这个功能,所有的api https 功能,我曾经访问过db.collectiondb.doc 开始抛出错误。以下是对db.doc 的相同调用。

db.doc("samplecollection/docid")
.get()
.then(function (doc) 
   console.log('doc.data', doc.data());
)
.catch(function (error) 
   console.log('Error in fetching samplecollection doc', error);
);

现在,当我尝试执行上述操作时,出现以下错误。

Error in autogenerated TypeError [ERR_INVALID_ARG_TYPE]: The "path"
 argument must be of type string. Received type object
      at validateString (internal/validators.js:125:11)
      at Object.basename (path.js:744:5)
      at GrpcClient.loadProto (sampleproject\functions\node_modules\google-gax\build\src\grpc.js:133:29)
      at new FirestoreClient (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\v1\firestore_client.js:121:32)
      at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory]
 (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\index.js:302:26)
      at ClientPool.acquire (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\pool.js:67:35)
      at ClientPool.run (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\pool.js:124:29)
      at Firestore.readStream (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\index.js:947:26)
      at Firestore.getAll_ (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\index.js:680:14)
      at initializeIfNeeded.then (sampleproject\functions\node_modules\@google-cloud\firestore\build\src\index.js:650:61)
      at ZoneDelegate.invoke (sampleproject\functions\dist\server.js:5715:30)
      at Zone.run (sampleproject\functions\dist\server.js:5472:47)
      at sampleproject\functions\dist\server.js:6213:38
      at ZoneDelegate.invokeTask (sampleproject\functions\dist\server.js:5750:35)
      at Zone.runTask (sampleproject\functions\dist\server.js:5517:51)
      at drainMicroTaskQueue (sampleproject\functions\dist\server.js:5930:39)
      at process._tickCallback (internal/process/next_tick.js:68:7)

我不太确定为什么错误说 “路径”参数必须是字符串类型。收到类型对象。我尝试将文档路径分配给变量并使用typeof 检查其类型,它仍然显示为string

要注意的关键点是 - 如果我删除复制到 functions 目录中的 s-s-r、函数和 dist 文件夹,则具有相同代码行的所有内容都可以正常工作。所以,我强烈怀疑,这与 s-s-r 有关。

我为此做了很多谷歌搜索,但没有一个人有这个 s-s-r 设置。 有人可以为我指出正确的方向,或者让我知道是否有人遇到过 Angular Universal s-s-r 的这个问题并找到了解决方案?


更新 - 1

我在webpack.server.config.js 文件中设置了以下选项。这会是个问题吗?

node: 
    __dirname: false
,

更新 - 2

这是为开发和生产环境配置的 firebase.json。


  "hosting": [
    
      "public": "dist/browser",
      "target": "staging",
      "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
      "rewrites": [
        
          "source": "**",
          "function": "s-s-r"
        
      ],
      "headers": [
        
          "source": "**/*.@(jpg|jpeg|gif|png|svg|js|css|css?*|eot|otf|ttf|ttc|woff|woff2)",
          "headers": [
            
              "key": "Access-Control-Allow-Origin",
              "value": "*"
            ,
            
              "key": "Cache-Control",
              "value": "max-age=31536000"
            
          ]
        ,
        
          "source": "404",
          "headers": [
            
              "key": "Cache-Control",
              "value": "max-age=7200"
            
          ]
        
      ]
    ,
    
      "public": "dist",
      "target": "production",
      "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
      "rewrites": [
        
          "source": "**",
          "destination": "/index.html"
        
      ]
    
  ],
  "functions": 
    "include": ["**/views/**"]
  

现在,我刚刚在staging 中配置了这个,即[开发环境] 进行测试,但是这个问题甚至会影响到生产环境,因为两者的云功能将保持不变。

更新 - 3

经过进一步调查,我注意到 firestore_client.js 存在于 functions 依赖项的 node_modules 中,在路径 node_modules/@google-cloud/firestore/build/src/v1 下有以下代码来识别它是浏览器还是不是。

const isBrowser = typeof window !== 'undefined';
if (isBrowser) 
    opts.fallback = true;

.....
.....
.....
// Load the applicable protos.
// For Node.js, pass the path to JSON proto file.
// For browsers, pass the JSON content.
const nodejsProtoPath = path.join(__dirname, '..', '..', 'protos', 'protos.json');
const protos = gaxGrpc.loadProto(opts.fallback ? require('../../protos/protos.json') : nodejsProtoPath);

所以firestore_client.js 通过检查typeof window !== undefined 是否可以识别这是否是浏览器。但是,在我的 SPA 的 server.ts 中,我从 domino 库中定义了 global['window'] = win。添加它是因为它会抛出 window is not defined ReferenceError.

基本上,这意味着firestore_client.js 能够通过server.js 确定window 对象,生成并保存在functions 文件夹中,因此它传递作为对象的protos.json 文件内容,而不是路径。看了上面写在上述文件中的cmets,感觉这里应该传递一个文件的路径,而不是nodejs环境的对象。

任何想法,我现在如何克服这个问题?

【问题讨论】:

我不知道如何解决这个特定的错误,但我尝试了使用 Firebase 云功能的 s-s-r 并得到了一些我无法解决的其他错误。如果您可以选择使用 appengine,那么我会选择它 (fireship.io/lessons/angular-universal-firebase) @michelepatrassi .. 不太确定,如果这是一个不错的选择。从来没有继续尝试过,也担心定价,因为我们的项目目前处于火焰计划中。这可能证明我们代价高昂。 您的firebase.json 看起来如何?您是否指定了 "source" 作为项目根目录? @Vojtech.. 更新了我的问题。如果有帮助,请告诉我。 我检查了我的配置,您似乎在functions 配置中没有source,请尝试添加"source": "folderName",其中文件夹名称将是您的云功能所在文件夹的名称相对于firebase.json 【参考方案1】:

不是您希望的答案,但还是发布它。

前段时间我尝试了基本相同的方法。我使用 Firebase 身份验证和实时数据库而不是 Firestore。另外,我使用了 AngularFire2。我不确定你是否也在使用它。构建很好,但是我总是会遇到运行时异常。

我发现多个声明声称 Firebase 身份验证和实时数据库无法与 s-s-r 一起使用,因为它依赖于某些浏览器功能。不幸的是,我现在找不到它们。不确定这是与 firebase 相关还是与 AngularFire 相关。

我搜索了多个关于 s-s-r 与实时数据库相结合的教程/帖子。除了一个,我什么也找不到。 This 指南解释了如何将 Firestore 与 s-s-r 一起使用。不同之处在于他们使用的是AngularFireLite 而不是 AngularFire。

【讨论】:

可能不是这样,因为这通常与 s-s-r 应用程序干扰云功能并让功能相信它们在浏览器而不是节点中运行有关。 感谢您向我介绍这个库 - AngularFireLite - 但请告诉我一件事,它是否得到维护?最后更新于 2019 年 7 月 16 日。它会支持 Angular 8 吗?我从提交中看到的最后一次更新是,它支持 Angular 6。那么,这可以信任吗? :) Tbh 我不知道。我也有同样的担忧。 s-s-r对be来说没什么大不了的,所以我没有尝试。 package.json 指的是 angular 8.1.1,所以我猜它与 angular 8 一起工作得很好。虽然它没有那么多的 cmets,但由 angular 团队维护的 AngularFire(注意不是 AngularFireLite)也没有。所以我想它并没有那么复杂。【参考方案2】:

所以我有 2 个选项我要扔在那里,希望其中一个能奏效。

    尝试旧版本: 卸载当前安装:
npm uninstall @angular/fire firebase --save

然后安装旧版本,我做了如下:

npm install @angular/fire@5.0.0 firebase@5.9.0 --save
    不确定你的 webpack.server.config 中是否有这个:
module.exports = 
...
 resolve: 
    alias: 
      ['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js')
    
  
...

【讨论】:

嗨@Shlomo,明天一定让我试试这个方法,然后告诉你。第二种方法看起来很有希望,因为我现在还没有。 不走运,伙计,我尝试了这两个步骤,但是对于其中任何一个,我都会遇到相同的错误。对于第一个当我安装旧版本时,当我运行 firebase serve - Warning: This is a browser-targeted Firebase bundle but it appears it is being > run in a Node environment. If running in a Node environment, make sure you > are using the bundle specified by the "main" field in package.json. 时它会抛出以下警告,并且使用第二种方法它仍然会抛出相同的错误。不知何故,它无法解决path.. :( 我更新了我的帖子。您是否从中得到任何想法,比如可能有什么问题? 也许如果你选择第一个选项。我发现有人在网上写了这篇文章:'我通过在用于服务器捆绑的 firebase 配置中将 firebase 依赖项设置为“外部”来解决了我的 s-s-r 设置问题。只需将:externals: [/^firebase/] 添加到您的 webpack 配置中,并确保所有依赖项都安装在函数文件夹(包)中。看起来它可以解决你的问题。 没问题兄弟..我不知何故明白了..感谢您的帮助..【参考方案3】:

因此,经过几天的调查,我不得不采用一种肮脏的方法让 SPA 在云功能中作为 s-s-r 应用程序工作。

正如我在上次更新帖子中提到的,对于所有情况,我都必须将 opts.fallback 设为 false。我这样做是为了确保@google-cloud 在我的应用程序中只存在于functions。现在它看起来像下面这样:

const isBrowser = typeof window !== 'undefined';
if (isBrowser) 
    opts.fallback = true;


opts.fallback = false; //Added this line.

现在,一切正常。但是,归根结底,这是最肮脏的方法。

我仍然对@google/cloud 下的某些内容感到困惑,因为我注意到还有 firestore_admin_client.js 文件并且不确定何时会调用它。另外,我担心这种方法将来是否会导致任何安全漏洞。

无论如何,如果我将来发现任何东西,我会在调试时继续发布。

好吧,当我将功能部署到云时,上述方法似乎失败了。这只能在本地使用firebase serve

【讨论】:

以上是关于迁移 Angular Universal firebase 后,云函数抛出错误的主要内容,如果未能解决你的问题,请参考以下文章

Angular Universal 学习笔记

Angular-universal - 生产问题

Angular 7 Universal Firebase 路由

如何修复:“@angular/fire”'没有导出成员 'AngularFireModule'.ts(2305) ionic、firebase、angular

如何在 Angular 4 Universal 中发出 http post 请求?

在 Angular 中需要 BrowserAnimationsModule 但在 Universal 中出现错误