node.js - ES Modül sistemi kullanarak TypeScript ile Firebase fonksiyonunu dağıtma sorunları


ES Modül sistemi kullanarak Typescript'ten derlenen bir Firebase fonksiyonunu dağıtırken bir sorun yaşıyorum.

index.ts

import * as functions from "firebase-functions";
import myGreeting from "./my-greeting";

export const helloWorld = functions.https.onRequest((request, response) => {
  response.send(myGreeting);
});

benim-karsilama.ts

export default "HELLO WORLD";

tsconfig.json

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

package.json

{
  "name": "functions",
  "scripts": {
    "build": "tsc",
    "build:watch": "tsc --watch",
    "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"
  },
  "type": "module",
  "engines": {
    "node": "16"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "^10.2.0",
    "firebase-functions": "^3.21.0"
  },
  "devDependencies": {
    "typescript": "^4.6.4"
  },
  "private": true
}

Bu gayet iyi bir şekilde derleniyor ama elbette TypeScript derleyicisi, ./lib/index.js çıkış dosyasındaki import ifadesine .js uzantılarını eklemiyor.

Sonra fonksiyonları dağıtmaya çalıştığımda aşağıdaki hatayı alıyorum:

Error: Failed to load function definition from source: Failed to generate manifest from function source: Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/my-project/functions/lib/my-greeting' imported from /my-project/functions-test/functions/lib/index.js 

TypeScript'ten derlenmiş ve .js uzantıları dahil edilmeden ES modüllerini kullanan bir npm kütüphanesini içe aktarabilmem gerekiyor (commonjs versiyonu yok). Fonksiyonlar için Node 16 çalışma zamanını kullandığımdan, ES2020 hedefli ES modüllerini çalıştırabileceğimi anlıyorum, ancak Firebase fonksiyonları çalışma zamanında --experimental-specifier-resolution=node bayrağını ayarlamanın bir yolu var mı?

Node 16 Firebase bulut çalışma zamanında fonksiyonu commonjs modülü olarak dağıtmadan nasıl çalıştırabilirim?

İşlemeyecek 2 çözüm ve nedenleri:

1. Yalnızca import ifadelerini değiştiremem

Yukarıdaki örnekte değiştirebilirdim

import myGreeting from "./my-greeting";

için

import myGreeting from "./my-greeting.js";

Bu gerçekten pratik olmayan bir iş akışı olurdu, ama bundan öte sorun şu ki bir ES Modül kütüphanesi kullanıyorum ve bu kütüphane TypeScript’ten derlenmiş, değiştirilmemiş import ifadelerine sahip, bu yüzden kesinlikle gidip tüm import ifadelerini .js uzantısını ekleyecek şekilde değiştirmek istemem.

2. tsconfig.json içinde "module": "CommonJS" kullanamıyorum

Yukarıdaki örneği, tsconfig.json içindeki compilerOptions'ı "module": "CommonJS" olarak değiştirir ve package.json içindeki "type": "module" kısmını kaldırırsam sorunsuz şekilde dağıtabilirim, ancak bu bir seçenek değil çünkü sadece bir ES modülü olarak mevcut olan bir kütüphane ile çalışmam gerekiyor, yayınlanmış bir CommonJS sürümü yok.

Cevap #1

Kaynağınızdaki (index.ts) içe aktarmayı şuradan değiştirmeniz gerekiyor

import myGreeting from "./my-greeting";

için

import myGreeting from "./my-greeting.js";

Bildiğim kadarıyla TSC import ifadelerini değiştirmeyecek.

Cevap #2

Uzun süredir aynı sorunu yaşıyordum. Ama nihayet bir çözüm buldum.

Esbuild ile İnşa Edin

(Matt Pocock'un talimatlarını takip edin https://www.totaltypescript.com/build-a-node-app-with-typescript-and-esbuild)

  1. Konfigürasyon Dosyalarımızı Eklemek

1.1 package.json dosyasında "type": "module". Daha sonra, package.json dosyasına "type": "module" ekleyin.

{
  // ...other properties
  "type": "module"
  // ...other properties
}

1.2 Bağımlılıklar Sonra, bağımlılıklarımızı yükleyelim:

pnpm add -D typescript esbuild @types/node npm-run-all

1.3 TypeScript Yapılandırması Projenin kök dizinine aşağıdaki yapılandırmaya sahip bir tsconfig.json dosyası ekleyin:

{
  "compilerOptions": {
    /* Base Options: */
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "es2022",
    "verbatimModuleSyntax": true,
    "allowJs": true,
    "resolveJsonModule": true,
    "moduleDetection": "force",
    /* Strictness */
    "strict": true,
    "noUncheckedIndexedAccess": true,
    /* If NOT transpiling with TypeScript: */
    "moduleResolution": "Bundler",
    "module": "ESNext",
    "noEmit": true,
    /* If your code doesn't run in the DOM: */
    "lib": ["es2022"]
  }
}
  1. Betiklerimizi Ekleme

2.1 build komut dosyası package.json dosyasına bir build komut dosyası ekleyin:

{
  // ...other properties
  "scripts": {
   "build": "esbuild src/index.ts --bundle --platform=node --outfile=lib/index.js --format=esm --external:./node_modules/*",
  }
  // ...other properties
}

2.2 geliştirme betiği

{
  // ...other properties
  "scripts": {
    "dev:tsc": "tsc --watch --preserveWatchOutput",
    "dev:node": "firebase emulators:start --only functions",
    "dev:esbuild": "pnpm run build --watch",
    "dev": "run-p dev:*",
  }
  // ...other properties
}

pnpm dev çalıştır

Ve sonunda Firebase işlevleri emülatörünüzü Typescript, ESM ve hatta izleme modu (watch benim için biraz yavaş çalışıyor, yeni kodu işlemesi 5-8 saniye sürüyor, ama yine de bunu otomatik olarak yapıyor🎉) ile çalıştırdınız

İlgili makaleler