Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Functions with Yarn workspaces

We're starting to adopt a monorepo setup using yarn workspaces and we'd like to have our firebase functions inside it. The repo structure is something like:

repo
    node_modules <- all dependencies
    packages
        core
        commom
        functions <- firebase functions

So, I have 2 problems with this setup:

  1. The dependencies of the functions don't live on the same folder as the entry file from functions
  2. The functions depends on other packages such as core and commom that are in the repo so yarn symlinks from node_modules to the packages in the repo.

Is there anyway I can handle this?

like image 533
Thiago Nascimento Avatar asked Apr 21 '19 15:04

Thiago Nascimento


People also ask

How do I add a workspace to my yarn?

Once we have created our new React project, we need to tell Yarn to treat that project as a workspace. To do that, we simply need to add “client” (the name we used earlier) inside the “workspaces” list in the root package. json. Be sure to use the same name you used when running the create-react-app command.

What does yarn workspace do?

Yarn Workspaces is a feature that allows users to install dependencies from multiple package. json files in subfolders of a single root package. json file, all in one go. Yarn can also create symlinks between Workspaces that depend on each other, and will ensure the consistency and correctness of all directories.

When should I use Firebase functions?

You should use Cloud Functions for Firebase if you're a developer building a mobile app or mobile web app. Firebase gives mobile developers access to a complete range of fully managed mobile-centric services including analytics, authentication and Realtime Database.


2 Answers

With Yarn 2 node_modules aren't fetched and placed into in the respective functions directory (as it would be the case with calling npm i in the functions directory). So when calling firebase deploy --project default --only function the node_modules folder is missing and firebase will complain about this and abort the deployment process with the following error (or similar):

Error parsing triggers: Cannot find module [...]
Try running "npm install" in your functions directory before deploying.

There are two github issues that are tracking this issue at the moment:

  • Support mono-repos in deployment
  • Functions deployment fails when firebase-functions has been hoisted by a monorepo manager like yarn/workspaces or lerna

In the two issues above, several clever workarounds are presented by firebase users, e.g. using webpack to create a build that contains all the local packages in the release or using rsync or other tools that rewire the packages before release.

Another solution is not hoisting your project packages, if that is possible. You can do this, be adding the following two directives to your .yarnrc.yml file.

# yarnrc.yml

# disables yarn's plugnplay style and uses node_modules instead
nodeLinker: node-modules
# makes sure the node_modules are not hoisted to the (monorepo) project root
nmHoistingLimits: "dependencies"

The two directives above are explained in the yarnrc configuration docs as follows:

nmHoistingLimits Defines the highest point where packages can be hoisted. One of workspaces (don't hoist packages past the workspace that depends on them), dependencies (packages aren't hoisted past the direct dependencies for each workspace), or none (the default, packages are hoisted as much as possible). This setting can be overriden per-workspace through the installConfig.hoistingLimits field.

nodeLinker Defines what linker should be used for installing Node packages (useful to enable the node-modules plugin), one of: pnp, node-modules.

like image 77
B12Toaster Avatar answered Oct 04 '22 03:10

B12Toaster


The solution I found for this is Yarn's nohoist option in your root package.json file.

By default Yarn hoists dependencies to the root directory so they can be shared between your packages. Unfortunately this will not work with Firebase. This means you need to tell Yarn not to hoist the dependencies used by your Firebase functions.

The documentation for nohoist is less than ideal, but here is an official blog post about it here: https://yarnpkg.com/blog/2018/02/15/nohoist/

You probably want something like this:

{
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "functions/core",
      "functions/common",
      "functions/**"
    ]
  }
}

Keep in mind that this uses the name field used in the package.json files of each workspace package. So in this example, it is assume that the functions directory has a package.json with "functions" as it's name.

functions/** tells yarn not to hoist any of the dependencies specified in packages/functions/package.json. This doesn't work for your shared yarn packages though, so functions/core and functions/common need to be specified separately.

You also need to include your workspaces as dependencies in your functions project, so add them to your package.json:

{
  "name": "functions",
  "dependencies": {
    "core": "*",
    "common": "*",
  }
}

Once you have added all that, you should delete your packages/functions/node_modules directory and run yarn install. After doing this, you should see all your dependencies included in packages/functions/node_modules (not symlinks).

like image 43
twiz Avatar answered Oct 04 '22 04:10

twiz