Home > Enterprise >  Cannot use import statement outside a module, TypeScript NodeJS Firebase Functions project
Cannot use import statement outside a module, TypeScript NodeJS Firebase Functions project

Time:04-02

I recently set up a Firebase Functions project using TypeScript. As far as I can tell I am using the same setup I have before in the past. This time, however, when I run firebase emulators:start I receive the following error:

Error: Error occurred while parsing your function triggers.

<Local Computer Path>/firebase/functions/src/index.ts:3
import functions = require("firebase-functions");
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1031:15)
    at Module._compile (node:internal/modules/cjs/loader:1065:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at loadModule (/opt/homebrew/lib/node_modules/firebase-tools/lib/deploy/functions/runtimes/node/triggerParser.js:10:16)
    at /opt/homebrew/lib/node_modules/firebase-tools/lib/deploy/functions/runtimes/node/triggerParser.js:34:21

As far as I can tell I have not changed anything from past projects, where I did not come across this issue. The only potential difference I can think of is that I updated my firebase tools using npm install -g firebase-tools@latest. Below are some of the files from my project:

src/index.ts

/* eslint-disable max-len */
import functions = require("firebase-functions");
import admin = require("firebase-admin");

admin.initializeApp();

...

.eslintrc.js

module.exports = {
  root: true,
  env: {
    es6: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:import/typescript",
    "google",
    "plugin:@typescript-eslint/recommended",
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: ["tsconfig.json", "tsconfig.dev.json"],
    sourceType: "module",
    tsconfigRootDir: __dirname,
  },
  ignorePatterns: [
    "/lib/**/*", // Ignore built files.
  ],
  plugins: [
    "@typescript-eslint",
    "import",
  ],
  rules: {
    "indent": ["error", 2],
    "object-curly-spacing": ["error", "always"],
    "quotes": ["error", "double"],
    "import/no-unresolved": 0,
  },
};

package.json

{
  "name": "functions",
  "scripts": {
    "lint": "eslint --ext .js,.ts .",
    "build": "tsc",
    "serve": "npm run build && firebase emulators:start --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "16"
  },
  "main": "./src/index.ts",
  "dependencies": {
    "firebase-admin": "^10.0.2",
    "firebase-functions": "^3.18.0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.12.0",
    "@typescript-eslint/parser": "^5.12.0",
    "eslint": "^8.9.0",
    "eslint-config-google": "^0.14.0",
    "eslint-plugin-import": "^2.25.4",
    "firebase-functions-test": "^0.2.0",
    "typescript": "^4.5.4"
  },
  "private": true,
  "type": "module",
  "module": "ES2020"
}

package.dev.json

{
  "include": [
    ".eslintrc.js"
  ]
}

tsconfig.json

{
  "compilerOptions": {
    "module": "ES2020",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "ES2020"
  },
  "compileOnSave": true,
  "include": [
    "src"
  ]
}

firebase.json

{
  ...
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  },
  ...
}

My src/index.ts import syntax matches what Google outlined in the Firestore documentation: Import the required modules and initialize an app.

I have searched around for an answer but I have not come across one yet. Here are a few of the resources I have tried:

SyntaxError: Cannot use import statement outside a module Firebase Functions

Node.js v13.14.0 Documentation

Typescript: Cannot use import statement outside a module

Thanks in advance for the help!

CodePudding user response:

You need to use const functions = require("firebase-functions"); instead of import functions = require("firebase-functions"); - same for the 2nd import below it. The 'import' keyword can only be used with esmodules, while the const/require syntax is used in commonjs.

CodePudding user response:

Turns out the problem has a simple solution! The firebase emulators do not support typescript. To run functions in the emulator you first need to compile to JS (reference the docs docs). Both npm run serve and firebase deploy will automatically transpile your code, firebase emulators:start does NOT do this automatically. When using the emulators you must first run npm run build in your functions folder.

Also note, in your package.json you need your main argument to reference the compiled JS code. I needed to update both my package.json and tsconfig.json. Below are the final versions:

package.json

{
  "name": "functions",
  "scripts": {
    "lint": "eslint --ext .js,.ts .",
    "build": "tsc",
    "serve": "npm run build && firebase emulators:start --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "16"
  },
  "main": "./lib/index.js",
  "dependencies": {
    "firebase-admin": "^10.0.2",
    "firebase-functions": "^3.18.0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.12.0",
    "@typescript-eslint/parser": "^5.12.0",
    "eslint": "^8.9.0",
    "eslint-config-google": "^0.14.0",
    "eslint-plugin-import": "^2.25.4",
    "firebase-functions-test": "^0.2.0",
    "typescript": "^4.5.4"
  },
  "private": true
}

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017"
  },
  "compileOnSave": true,
  "include": [
    "src"
  ]
}
  • Related