Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Cloud Function deploy error: provided function is not a loadable module

I'm trying to build my GCF project with Typescript from the ground up. My goal with this project (and this question) is to understand how cloud functions work and to perform all the setup steps manually, so that's why I'm not copying any sample code or using an automated tool.

First, here's my src/index.ts file:

export const helloWorld = (req: any, res: any) => {
    res.send('Hello, world 4');
}

After I run typescript compiler, I get this dist/index.js file, which seems perfectly reasonable:

"use strict";
exports.__esModule = true;
exports.helloWorld = function (req, res) {
    res.send('Hello, world 4');
};

My package.json is set up to point to this file:

{
  "main": "dist/index.js",
  "scripts": {
    "start": "npx tsc-watch --onSuccess 'npx @google-cloud/functions-framework --target=helloWorld'",
    "deploy": "gcloud functions deploy helloWorld --runtime nodejs10 --trigger-http"
  },
  "dependencies": {
    "@google-cloud/functions-framework": "^1.1.2",
    "tsc-watch": "^2.2.1",
    "typescript": "^3.5.3"
  }
}

I wanted to setup local testing environment first, so I used functions framework. When I run it, it all works perfectly:

$ npx @google-cloud/functions-framework --target=helloWorld
Serving function...
Function: helloWorld
URL: http://localhost:8080/

However, when I try to deploy, I get this error:

$ gcloud functions deploy helloWorld --runtime nodejs10 --trigger-http
Created .gcloudignore file. See `gcloud topic gcloudignore` for details.
Deploying function (may take a while - up to 2 minutes)...failed.
ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Function failed on loading user code. Error message: Provided code is not a loadable module.
Could not load the function, shutting down.

Why does it say that my index.js is not a loadable module and how can I fix this error?


Update

Turns out the gcloud doesn't respect package.json's main field. When I specified that it should take dist folder explicitly with the --source flag, it deployed the file:

gcloud functions deploy helloWorld --source=dist/ --runtime nodejs10 --trigger-http

However, it still doesn't work because it seems to assume that everything, including package.json, is contained in this directory - so it doesn't link any of the library dependencies.

like image 458
Max Yankov Avatar asked Dec 13 '22 11:12

Max Yankov


2 Answers

Turns out, .gitignore by default is imported in GCF's .gcloudignore file, and since I ignore js files in my .gitignore, they never make it to GCF.

To fix it, just remove this line:

#!include:.gitignore

I have also created a small template project for using Typescript with GCF.

like image 58
Max Yankov Avatar answered Dec 21 '22 10:12

Max Yankov


Add !/dist after #!include:.gitignore in your .gcloudignore file.

In my opinion, it's better to leave the #!include:.gitnore line in your .gcloudignore file, so that when people add something to .gitignore, it will be automatically included in the .gcloudignore, too.

For files and directories where you want them to be ignored by git but not by gcloud, I would add them explicitly in the .gcloudignore file.

Let's take my example, where I have a TypeScript project. I don't want the output of tsc to be version-controlled, but I do want those files to include for gcloud for obvious reasons: the files in the built (or dist) folder is actually my function (app).

### .gitignore
node_modules
built

### .gcloudignore file's content
#!include:.gitignore
# Do not ignore built (or dist) folder for gcloud:
!/built
!/dist

I prefer this solution because, by default, the ignored files from git are also ignored by gcloud, so I don't need to worry that people forget that we have multiple ignore files.

like image 34
Vince Varga Avatar answered Dec 21 '22 10:12

Vince Varga