node.js - Kan inte använda import-sats utanför en modul, TypeScript NodeJS Firebase Functions-projekt


Jag satte nyligen upp ett Firebase Functions-projekt med TypeScript. Så vitt jag kan se använder jag samma uppsättning som jag har gjort tidigare. Den här gången, dock, när jag kör firebase emulators:start får jag följande fel:

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

Såvitt jag kan bedöma har jag inte ändrat något från tidigare projekt, där jag inte stötte på detta problem. Den enda potentiella skillnaden jag kan tänka mig är att jag uppdaterade mina Firebase-verktyg med npm install -g firebase-tools@latest. Nedan finns några av filerna från mitt projekt:

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"
    ]
  },
  ...
}

Min src/index.ts-importsyntax matchar det som Google beskrev i Firestore-dokumentationen: Importera de nödvändiga modulerna och initiera en app.

Jag har letat runt efter ett svar men har inte stött på något ännu. Här är några av de resurser jag har provat:

SyntaxError: Kan inte använda import-sats utanför en modul Firebase Functions

Node.js v13.14.0 Dokumentation

Typescript: Kan inte använda import-sats utanför en modul

Tack på förhand för hjälpen!

Svar #1

Det visar sig att problemet har en enkel lösning! Firebase-emulatorerna stöder inte TypeScript. För att köra funktioner i emulatorn måste du först kompilera till JS (se dokumentationen). Både npm run serve och firebase deploy kommer automatiskt att transpilerar din kod, firebase emulators:start gör INTE detta automatiskt. När du använder emulatorerna måste du först köra npm run build i din functions-mapp.

Observera också att i din package.json behöver ditt main-argument referera till den kompilerade JS-koden. Jag behövde uppdatera både min package.json och tsconfig.json. Nedan är de slutgiltiga versionerna:

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"
  ]
}

Svar #2

Du behöver använda const functions=require("firebase-functions"); istället för import functions=require("firebase-functions"); - samma gäller för den andra importen nedan. Nyckelordet 'import' kan endast användas med esmoduler, medan const/require-syntaxen används i commonjs.

Relaterade artiklar