Efficiently integrating Firebase Functions with external sub path imports beyond the project's

I encountered an issue in my firebase functions project with typescript. The problem arises when I use types from outside the project with sub path imports, causing the build files to become distorted.

Instead of having main:lib/index.js, I have main:lib/functions/src/index.js.

This is the file structure:

petertoth@Peters-MBP-2 lib % tree .
.
├── functions
│   └── src
│       ├── index.js
│       ├── index.js.map
│       ├── journalLogs.type.js
│       ├── journalLogs.type.js.map
│       └── util
│           ├── audiFiles.js
│           ├── audiFiles.js.map
│           ├── db.js
│           ├── db.js.map
│           ├── getJournalSettings.js
│           ├── getJournalSettings.js.map
│           ├── prompt.js
│           ├── prompt.js.map
│           ├── storage.js
│           └── storage.js.map
└── types
    ├── firebase
    │   ├── CreateFullRecording.request.js
    │   ├── CreateFullRecording.request.js.map
    │   ├── generateJournal.requests.js
    │   └── generateJournal.requests.js.map
    ├── firestore
    │   ├── JournalSettingsDoc.js
    │   └── JournalSettingsDoc.js.map
    └── openai
        ├── language.js
        └── language.js.map

Here's a snippet from package.json:

{
  "name": "functions",
 ...
 "imports": {
    "#types/*": ["../types/*"]
  },
  "engines": {
    "node": "16"
  },
  "main": "lib/functions/src/index.js",
  "private": true
  ...
}

And this is tsconfig:

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017",
    "moduleResolution": "nodenext",
    "paths": {
      "#types/*": ["../types/*"]
    }
  },
  "baseUrl": ".",
  "compileOnSave": true,
  "include": [
    "src"
  ]
}

During the local development, everything works perfectly fine. However, when I attempt to deploy using firebase deploy --only functions, the following error occurs:

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run build

> build
> tsc

✔  functions: Finished running predeploy script.
i  functions: preparing codebase default for deployment
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
✔  functions: required API cloudfunctions.googleapis.com is enabled
✔  artifactregistry: required API artifactregistry.googleapis.com is enabled
✔  functions: required API cloudbuild.googleapis.com is enabled
i  functions: preparing ./functions/ directory for uploading...
i  functions: packaged XX (98.13 KB) for uploading
✔  functions: ./functions/ folder uploaded successfully
i  functions: updating Node.js 16 function generateJournal(europe-west1)...
i  functions: updating Node.js 16 function migrageJournal(europe-west1)...
i  functions: updating Node.js 16 function getCollectionNames(europe-west1)...
i  functions: updating Node.js 16 function createFullRecording(europe-west1)...
Build failed: > build
> tsc

src/index.ts(22,44): error TS2307: Cannot find module '#types/firebase/CreateFullRecording.request' or its corresponding type declarations.
src/index.ts(25,40): error TS2307: Cannot find module '#types/firebase/generateJournal.requests' or its corresponding type declarations.
src/util/getJournalSettings.ts(1,36): error TS2307: Cannot find module '#types/firestore/JournalSettingsDoc' or its corresponding type declarations.
src/util/prompt.ts(1,36): error TS2307: Cannot find module '#types/firestore/JournalSettingsDoc' or its corresponding type declarations.
src/util/prompt.ts(2,30): error TS2307: Cannot find module '#types/openai/language' or its corresponding type declarations.
src/util/prompt.ts(15,31): error TS18046: 'journalBullet' is of type 'unknown'.
src/util/prompt.ts(16,34): error TS18046: 'journalBullet' is of type 'unknown'.
src/util/prompt.ts(48,10): error TS7053: Element implicitly has an 'any' type because expression of type 'LanguageCode' can't be used to index type '{ en: string; da: string; sv: string; no: string; de: string; }'.; Error ID: 1a2262f3

I suspect that there might be an issue in the configuration related to packaging files for deployment. Unfortunately, I'm unsure how to further debug this problem.

Answer №1

Make sure your Firebase CLI is up to date: npm install -g firebase-tools

In the latest update, Google Cloud Functions now automatically runs npm run build during deployment. Unfortunately, this seems to be causing some issues.

However, take note that according to a comment by colerogers, the Firebase team has addressed this problem in firebase-tools v11.27.0 by disabling the mentioned feature.

When you upgrade to at least that version, you should no longer encounter this error. The issue will be resolved without any additional steps required.

Answer №2

In my experience, I have encountered a situation where the files under lib/functions/src/index.js seemed to be moving around, resulting in a confusing mix of the "src" folder with the build output. This usually happens when you reference imports from above the TypeScript build folder without using a "reference" to another TypeScript project. It appears that this occurs because TSC (TypeScript compiler) tries to find the root common path for all imports and ends up shifting the project folder upwards. As a consequence, the "src" folder is not considered special anymore but instead regarded as just a subfolder. Obviously, this is not an ideal outcome for your build - even if it seems to work locally.

To resolve this issue, you can add another tsconfig file in the "types" folder to treat it as its own TypeScript project. Then, include a project reference to this new tsconfig file in your main tsconfig:

  "references": [
    {
      "path": "../types"
    }
  ]

Additionally, adjust your TypeScript build command to use the --build flag in your package.json:

    "build": "tsc --build ",

By doing this, when you rebuild your project, the main project output will move back up two folders to where it should be in the lib directory, specifically in lib/index.js and lib/util/*, etc. (You may need to delete the existing lib folder first for a clean rebuild).

With these changes, it should fix the peculiar build issue that you encountered. However, there is still an important consideration when deploying your project: the lib/types folder will not be uploaded because, as Doug explains, they are no longer within the functions folder and are only referenced locally.

I have faced this problem before and found a solution without resorting to a private npm repository or other complex methods. Instead, I used a pre-deploy build script that packages the lib project into a GZ file and adds it as a file dependency to the main project.

In the package.json file of your "types" library project, include the name, version, and a build script:

{
  "name": "my-lib",
  "version": "1.0.0",
  "scripts": {
    "build": "npm pack"
  },

Running npm run build will generate a zipped up version of the library like: my-lib-1.0.0.gz.

You then need to copy this file from /lib to /functions/ (or any desired subfolder).

Finally, require the correct version in your main project's package.json file:

  "main": "lib/index.js",
  "dependencies": {
    "#types": "file:my-lib-1.0.0.tgz"
  },

When deploying the functions, the GZ file will be uploaded and resolved during the deployment build from the local file in the container.

I have written a bash script that handles these steps before deploying, which also includes an idiot-proof version check:

echo Packaging the latest my-lib and importing it to gcp/functions...
echo Note: the functions package.json must require the new version.
#read -p "Press any key..."

cd libs/my-lib;
# Detect the current version
LIB_VERSION=`node -pe "require('./package.json').version"`

echo Version \($LIB_VERSION\) detected OK?
read -p "Press any key..."

# Package the latest version
LIB_FILENAME=my-lib-${LIB_VERSION}.tgz
npm run build;
# Move it into the Cloud Function folder so the tarfile can be deployed.
mv $LIB_FILENAME ../../gcp/functions;
# Reinstall it locally too
cd ../../gcp/functions;
npm i $LIB_FILENAME
cd ..

Based on your question, I am uncertain how the accepted answer could have provided a resolution for your specific issue.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to build custom middleware with parameters in Node.js

I'm working on creating a middleware in nodejs for access levels, and I've written the following middleware: class AccessUser extends middlware { async AccessUser(access,req, res, next) { const getTokenFrom = (req) => { const autho ...

NEXT JS 13 experiencing an infinite loop when using State, encountering an error with Params, and facing issues with hook definition

Currently, I am in the process of developing a shopping cart using NEXT JS and encountering several issues within my code. To begin with, I have established a route [product]/[productitems] within the apps folder. In the page.tsx file of [productitems], I ...

Error in Node and Express: Unable to access route

Currently, I am in the process of developing an Express application and running into some obstacles with routing. While my '/' route is functioning perfectly fine, other routes are not working as expected. Despite researching similar questions fr ...

Is it possible to nest the newly added element beneath its sibling in Cheerio?

Currently, my implementation involves using cheerio to modify an XML file within a Node environment. Specifically, I am adding the <target> node/element after the <source> element by utilizing the insertAfter() method like so: oldEl.translation ...

Tips on automatically changing the background image every few seconds

As a newcomer to Angular and programming in general, I am facing an issue with changing the background image of my Page using the setInterval method. The intended behavior is for it to change every second, but for some reason, it changes much faster than t ...

What is the best way to extract the text from a class only when it is nested within a particular header tag?

const request = require ('request'); const cheerio = require('cheerio'); const fs = require ('fs'); request("http://kathmandupost.ekantipur.com/news/2018-08-31/bimstec-summit-multilateral-meet-underway.html", (error, response ...

Triggering event within the componentDidUpdate lifecycle method

Here is the code snippet that I am working with: handleValidate = (value: string, e: React.ChangeEvent<HTMLTextAreaElement>) => { const { onValueChange } = this.props; const errorMessage = this.validateJsonSchema(value); if (errorMessage == null ...

Establishing the parameters for a list that is not empty using a specific data type

Is it feasible to establish a non-empty list within TypeScript's type system? While I am aware that it is possible to define a list with a specific number of elements, similar to a Tuple: type TwoElementList = [number, number]; This approach is limi ...

Now that connect no longer utilizes the parseCookie method, what is the alternative method for accessing session data in express?

There are numerous examples in node.js and express showcasing how to access session data. Exploring Node.js and Socket.io Express and Socket.io Integration Understanding Socket.io and Session Management Upon visiting the third link, which leads to Stac ...

Poorly packaged library - Custom Angular library - Node Package Manager

Recently, I've been delving into the process of publishing a simple Angular library on NPM. Despite following various tutorials (like those found here, here, and here), I faced difficulties when attempting to use it in a test project. MY JOURNEY In s ...

What is the best way to store an audio Blob in the repository file system?

Currently, I have set up a system to record user audio through the device's microphone and can successfully download it on the same device. However, my goal now is to store this audio in my database by making an API call. How can I efficiently send th ...

ValueError: Unable to perform slicing operation on this data

When attempting a query in nodejs, I encounter this error: [2017-08-19 19:06:55.946] [ERROR] error - TypeError: val.slice is not a function at escapeString (/var/www/Bot/node_modules/sqlstring/lib/SqlString.js:183:23) at Object.escape (/var/www/Bo ...

React JS displayed the string of /static/media/~ instead of rendering its markdown content

When I looked at the material UI blog template, I created my own blog app. I imported a markdown file using import post1 from './blog-posts/blog-post.1.md'; Next, I passed these properties to this component like so: <Markdown className=" ...

Travis is experiencing issues with retrieving the API key after logging in with npm

Referencing the information found at , it is stated that an API key should be visible after executing npm login. However, upon performing npm login (or npm adduser) and checking with cat .npmrc, I am unable to locate any indication of an API key. I would ...

When executing `npm install` within a Docker container, the error message `cb() never called!` may be encountered

My project has a rather small package.json file: { "name": "chilldev-web", "version": "2.1.0-SNAPSHOT", "description": "Client-side build tool for a project.", "license": "UNLICENSED", "private": true, "dependencies": { "in ...

Fetching information from external API prior to displaying it

I am currently working on an application that is built using the React Starter Kit. Each page within the app includes a fetch function that retrieves data from an API during the componentDidMount lifecycle. My goal is to retrieve the data before renderin ...

Attempting to establish a basic socket connection utilizing socket.io

Encountering an issue that states: Port error: Could not establish connection. Receiving end does not exist. Struggling to find a solution, can anyone offer assistance? Below is the code snippet: Server (app.js) var app = require('express&apos ...

Encountering an error when attempting to connect a nodejs REST API to an HTTPS URL using port 844

Attempting to initiate an API call from Node.js to a Tomcat server using the http/https module. There are two options for the API URL: - Functioning correctly and receiving a response var options = { host: 'samleapiurl.com', port: ...

Dealing with a Nodejs/Express and Angular project - Handling the 404 error

Recently, I decided to dive into learning the MEAN stack and thought it would be a great idea to test my skills by building an application. My goal was simple: display a static variable ('hello') using Angular in the HTML. However, I ran into an ...

Node.js sessions cookies are not being generated properly as req.cookies['connect.sid'] is not being created, and req.sessionID is changing every time the page is refreshed

In my setup, I am working with express 4.13.3 and express-session 1.11.3. Below is the session configuration I have implemented: app.use( session({/*store: new redis_store,*/name: 'connect.sid', secret: 'azerty is qwerty', resave: fals ...