Firebase deploy - Cannot find module of a local dependency
Asked Answered
F

4

17

I've got a submodule named shared which is located next to the backend folder (which is the cloud functions folder):

enter image description here

I've added the local dependency shared in backend/package.json like so:

"dependencies": {
    ...
    "shared": "file:../shared"
}

I ran npm install and made sure that node_modules/shared exists. Although, When I run the following code:

firebase deploy --only functions

I get the following error (by firebase):

Error: Error parsing triggers: Cannot find module 'shared/common'

Try running "npm install" in your functions directory before deploying.

This error is due to this line:

import { currentWeek } from 'shared/common';

If I change the directory to ../../../shared/common, firebase will compile without any errors.


shared/common/index.ts:

export { currentWeek } from './current-week';

shared/tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "target": "es5",
    "module": "commonjs",
    "declaration": true,
    "strict": true,
    "removeComments": true
  }
}

backend/tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "declaration": true,
    "outDir": "./dist",
    "module": "commonjs",
    "noImplicitAny": false,
    "removeComments": true,
    "noLib": false,
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "target": "es6",
    "moduleResolution": "node",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2015",
      "dom"
    ]
  },
  "include": [
    "./src/**/*",
    "../shared/**/*"
  ]
}

Why do I get this error if I DO have this module? Is there something I'm missing?

Footprint answered 21/2, 2019 at 22:6 Comment(3)
did you ever figure out a solution to this? Having the same problemMarcello
@Marcello no, I had to import it relatively (../../)Footprint
@Marcello I found a solution. Please see my answer below :)Design
D
3

While @jrasm91's answer explains the reason for this error well, I kind of miss the solution to the problem here.

Let's assume you have the following monorepo structure

- common
- firebase
  - functions

where common is a NodeJS module with common code, firebase is the root folder of your Firebase project and firebase/functions is the NodeJS project of your functions.

In firebase/functions/package.json you cannot include your common module like

"dependencies": {
    "common": "file:../../common"
}

because as @jrasm91 explained, the folder common is placed outside of the functions folder and thus won't be packaged and uploaded when running firebase deploy --only functions, which is also explained here.

The solution that worked for me is to additionally symlink the common folder into the functions folder

cd firebase/functions
ln -s ../../common common

and then update the package.json

"dependencies": {
    "common": "file:common"
}
Design answered 1/6, 2023 at 9:57 Comment(0)
A
2

In short:

  1. node_modules is ignored by default, while backend/dist is uploaded.
  2. npm run build happens locally and npm install happens in the cloud.
  3. npm install probably fails in the cloud because of missing shared folder or wrong path issues due to a different directory structure and/or a different "root" directory in the cloud environment.

Or, in more detail:

Functions has a predeploy step that builds (npm run build => tsc) the typescript project locally and then pushes the output to the cloud where the dependencies are installed (npm install).

When you include shared via a relative path (../../shared) the compiled code is output to the backend/dist folder after the project is built (locally) and thus is uploaded.

When you include shared via a local node modules dependency, the output is in the backend/node_modules folder after the dependencies are installed and thus it is not uploaded as node_modules is ignored by default.

The other issue you are seeing is why npm install can't install the local dependency in the cloud. This is likely due to either (1) not uploading shared alongside backend and/or the directory and relative path structure in the cloud environment is different from what it is locally.

firebase.json

{
  "functions": {
    "predeploy": ["npm --prefix \"$RESOURCE_DIR\" run lint", "npm --prefix \"$RESOURCE_DIR\" run build"],
    "source": "functions",
    "ignore": ["**/.env", "**/.runtimeconfig.js", "**/.log", "**/node_modules/**"]
  },
  ...
}
Anemone answered 13/9, 2021 at 17:45 Comment(0)
C
1

I think, you have to config module-resolution in for typescript compiler.

For your case:

{
  "compilerOptions": {
    "baseUrl": ".", // This must be specified if "paths" is.
    "paths": {
      "shared/*": ["../shared/*"] // This mapping is relative to "baseUrl".
    }
  }
}

You can named shared by another name.

{
      "compilerOptions": {
        "baseUrl": ".", // This must be specified if "paths" is.
        "paths": {
          "myLib/*": ["../shared/*"] // This mapping is relative to "baseUrl".
        }
      }
    }

Usage:

import { currentWeek } from "myLib/common";
Crannog answered 24/2, 2019 at 17:0 Comment(1)
If I add the shared folder to paths, then I'll have to add it to include too, which results in the same error. The only difference is that shared won't be in node_modules (which again leads to the question - why would firebase fail to find it? I assume it runs npm install externally which results in 404.Footprint
F
0

The answer from Sven was really useful, I figured out another posible solution: Using Firebase's predeploy script to handle this issue. Instead of creating a symlink, we could build and copy the necessary shared code into the functions folder prior to the deployment. Here is how it can be done:

In the firebase.json file:

  "functions": {
    "predeploy": [
      "npm --prefix ./shared run build",
      "cp -r ./shared/lib/* ./functions/shared/"
    ]
  }

and then update the package.json

"dependencies": {
    "shared": "file:shared"
}

This way, all required shared code gets moved into the functions directory before deployment, thus avoiding the issue of Firebase not being able to locate the shared module.

Flagging answered 16/6, 2023 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.