根据Firebase Functions with Yarn workspaces,我想使用Yarn Workspaces将monorepo部署到Firebase。我可以成功地将“web”方面部署到Firebase Hosting,它引用了一个共享的“核心”工作区。但是,尝试在Firebase Functions上的“functions”工作区执行相同操作会失败。
我使用的Yarn Workspaces具有以下文件夹结构:
packages/
core/ // name: firebase-monorepo-core: custom core package
functions/ // name: firebase-monorepo-functions: firebase functions package
web/ // name: firebase-monorepo-web: react package
已在根package.json
文件中配置了这些:
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/firebase-monorepo-core"
]
}
为了尝试在Firebase中启用Yarn工作区(并因此共享我的core
包),我使用nohoist
特性在functions
和web
中创建了指向core
工作区的符号链接,这与twiz的Stackoverflow answer相同。core
包也作为functions
和web
中的依赖项存在:
"dependencies": {
"firebase-monorepo-core": "*"
}
在本地运行时没有任何问题,事实上,将web
包部署到Firebase主机上运行得很好。但是,将functions
包部署到Firebase函数会引发一个错误:
我创建了一个Github存储库https://github.com/cjmyles/firebase-monorepo来演示这一点,生成的web
工作区可以在https://fir-monorepo.firebaseapp.com上查看。
如果我yarn pack
core
工作空间并将其作为tarball引用到package.json
文件中,我可以部署functions
包,但我真的不喜欢这个解决方案,自动化它需要更多的开销。
任何建议将不胜感激,以解决这个问题。
4条答案
按热度按时间ltqd579y1#
issue是
firebase-tools
假设函数使用的所有包都在npm中可用。一个快速的解决方案是使用firelink。
为您的函数package.json添加一个等价的部分,用于所有共享依赖项。
更改部署脚本以使用FireLink二进制
只是一个提示并不适用于“devDependencies”,但无论如何,您不应该在生产中需要它们。
更新firebase.json以运行predeploy目标。
最后删除工作区包中的所有本地
yarn.lock
文件。如果希望锁定依赖项,请将npm install
添加到预部署步骤中。如果有人有更好的解决方案,请告诉我。很不幸的是,yarn
不具备在工作区中按需生成锁文件的能力。o2gm4chl2#
一种可能的解决方案是使用Lerna。
然后,您可以将您的
core
包发布到一个私有的GitHub包,并使用Lerna创建一个指向core
包的符号链接,以便本地开发。5lhxktic3#
我得到了这个工作,但它是一个痛苦和hacky。到目前为止,它运行良好。我使用的是NPMWorkspaces,但是这个概念应该适用于任何将节点模块提升到根文件夹的项目。我还在为CI和TypeScript使用GitHub Workflows / Actions,所以所有这些都可以在这些环境中工作。
tsc
构建依赖包functions/src/domain
),以便通过Firebase CLI上传它们sed
来做,GitHub操作支持:在这个命令之前,我的package.json看起来像这样:
在该命令之后,它看起来像这样:
firebase deploy --only functions
不太好,但它是全自动的。😁
jpfvwuh44#
我已经制定了一个解决方案,并写了一篇关于这一点的文章,但似乎只有链接不欣赏这里,所以我会张贴一个摘录。这里是full article
Firebase的问题
当部署到Firebase时,它希望上传一个文件夹,就像传统的单个包存储库一样,包含源文件以及声明其外部依赖关系的清单文件。在其云部署管道中接收到文件后,它会检测包管理器并运行安装和构建。
在一个monorepo中,尤其是一个私有的,你的Firebase代码通常依赖于同一个仓库中的一个或多个共享包,你不想在任何地方发布它们。
一旦Firebase尝试在云中查找这些依赖项,就无法找到它们,部署就会失败。
杀出一条血路
使用bundler
为了解决这个问题,你可以尝试使用Webpack这样的打包器将Firebase代码与共享包代码结合起来,然后从发送到Firebase的package.json清单中删除这些包,这样它就不知道这些包的存在。
不幸的是,这种策略很快就成了问题。。
如果共享包本身没有在其输出中捆绑所有依赖项,Firebase将不知道共享代码依赖于什么,因为您没有包含或安装这些清单。
您可以尝试捆绑所有内容,但是如果您的共享包依赖于您的Firebase包也依赖的东西,那么您现在有一部分代码运行依赖项的内部捆绑副本,而另一部分则使用来自包管理器安装的不同位置的相同依赖项。
此外,有些库确实不喜欢捆绑,根据我的经验,包括Firebase和Google客户端库。你会很快发现自己试图通过bundler设置将事情外部化,以便让事情工作。
即使您设法完成了所有这些工作,您可能正在创建大型捆绑包,这可能会导致云功能的冷启动时间出现问题。
不完全是可靠或可扩展的解决方案。
打包和链接本地依赖
一种可以说是更优雅的方法涉及将本地依赖项打包到tarball中(类似于将包发布到NPM的方式),并将结果复制到构建输出,然后将其链接到更改的清单文件中。
这可以很好地工作,因为它基本上类似于如果从外部域安装这些包,Firebase代码将如何工作。
无论您是手动执行此操作,还是编写shell脚本来处理这些事情,对我来说仍然感觉非常繁琐和脆弱,但我认为如果您的本地依赖关系很简单,这是一个可行的解决方案。
然而,一旦您的共享包依赖于其他共享包,这种方法很快就会变得棘手,因为这样您就需要打包和调整多个级别的东西。
我的解决方案
我创建了isolate-package。这个名字是通用的,因为它不包含任何特定于Firebase的东西,尽管我目前不知道任何其他隔离输出的用例。
它采用了与前面在打包和链接依赖项中描述的方法类似的方法,但是采用了更复杂的方法。它被设计为处理不同的设置和包管理器,它完全隐藏了用户的复杂性。
它公开的隔离二进制文件可以简单地添加到Firebase predeploy钩子中,就是这样!
这还允许您从多个不同的包部署到Firebase,并保持配置位于同一位置,而不是分散在monorepo根目录中。
对于绝大多数用例来说,它应该是零配置的,并且被设计为与所有包管理器兼容。