enzo
enzo

Reputation: 11496

Can't use ES modules in Google Cloud Functions

I'm trying to deploy a very basic Google Cloud serverless application using Node.js, but it keeps showing the following error on Google Cloud Console:

Provided module can't be loaded.
Is there a syntax error in your code?
Detailed stack trace: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /workspace/index.js
require() of ES modules is not supported.
require() of /workspace/index.js from /layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/loader.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /workspace/package.json.
 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1080:13)
 at Module.load (internal/modules/cjs/loader.js:928:32)
 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
 at Module.require (internal/modules/cjs/loader.js:952:19)
 at require (internal/modules/cjs/helpers.js:88:18)
 at Object.getUserFunction (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/loader.js:29:32)
 at Object.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/index.js:77:32)
 at Module._compile (internal/modules/cjs/loader.js:1063:30)
 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
 at Module.load (internal/modules/cjs/loader.js:928:32)
Could not load the function, shutting down.

Here's my index.js file:

export function foobar(req, res) {
    res.status(200).send("Hello World!");
}

Here's my package.json file:

{
  ...
  "main": "index.js",
  "type": "module",
  ...
}

I'm running it using

gcloud functions deploy foobar --region europe-west1 --runtime nodejs14 --trigger-http --allow-unauthenticated

I've already tried the following:

  1. renaming index.js to index.mjs and change "main": "index.js" to "main": "index.mjs" in package.json (the error persists)

  2. solution 1 plus removing "type": "module" from package.json (the error persists)

  3. removing "type": "module" from package.json (raises a SyntaxError: Unexpected token 'export')

  4. renaming index.js to index.cjs and change "main": "index.js" to "main": "index.cjs" in package.json (raises a SyntaxError: Unexpected token 'export')

  5. solution 4 plus removing "type": "module" from package.json (raises a SyntaxError: Unexpected token 'export')

  6. adding the --experimental-modules flag in gcloud functions deploy (shows unrecognized arguments: --experimental-modules)

  7. solution 6 but replacing gcloud functions deploy with gcloud beta functions deploy (shows unrecognized arguments: --experimental-modules)

  8. uninstalling Google Cloud SDK completely and trying all above solutions again

The only solution that worked was solution 3 plus using

exports.foobar = (req, res) => {
    res.status(200).send("Hello World!");
}

However, I want to use it for a Telegram bot with the node-telegram-bot-api module, but because I removed "type": "module" from package.json, it raises "SyntaxError: Cannot use import statement outside a module" when I import the Telegram API.

The project structure was created using npm init, as shown below.

.
├── index.js
└── package.json

Any thoughts? My Node.js version is v14.17.0 and my Google Cloud SDK version is v342.0.0.

Upvotes: 5

Views: 6932

Answers (4)

saviski
saviski

Reputation: 39

If someone is struggling to run typescript with ts-node, try this configuration

{
  "type": "module",
  "scripts": {
    "start": "node --loader ts-node/esm node_modules/@google-cloud/functions-framework/build/src/main.js --target=default"
  },
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "@google-cloud/functions-framework": "^3.1.2",
    "@types/express": "^4.17.13",
    "ts-node": "^10.8.1"
  }
}

index.ts

import { Request, Response } from 'express'

export default async (req: Request, res: Response) => {
  // your code
}

Upvotes: 0

Daniel L
Daniel L

Reputation: 540

Google Cloud Functions (and therefore Firebase Functions) does not support ESM modules yet:

https://github.com/GoogleCloudPlatform/functions-framework-nodejs/issues/233 https://github.com/firebase/firebase-tools/issues/2994

Now I think you are conflating using and packaging ES modules. You don't have to package your functions code as an ES module in order to use node-telegram-bot-api module. Just import it using require syntax instead of using the import syntax.

Upvotes: 2

ManuelMB
ManuelMB

Reputation: 1375

Execute this code inside a Google Cloud Functions to know which version of Node.js is running.

console.log(`Hello Node.js v${process.versions.node}!`);

I think Google Cloud required: node: '12' (Same that Firebase)

With the release of Node version 15.3.0, ES modules can be used without an experimental flag.

Upvotes: 0

Sean Gonzalez
Sean Gonzalez

Reputation: 173

Try something like this:

const functions = require('firebase-functions');
   
exports.foobar= functions.https.onRequest((req, res) => {
  res.status(200).send("Hello World!");
});

Upvotes: 0

Related Questions