simondotm / nx-firebase

Firebase plugin for Nx Monorepos
https://www.npmjs.com/package/@simondotm/nx-firebase
MIT License
175 stars 31 forks source link

Firebase app raises error when using lib that imports npm package #105

Closed j1mmie closed 1 year ago

j1mmie commented 1 year ago

This is most likely not an issue, and instead a configuration problem or misunderstanding on my end, but any support would be appreciated ❤️

I've created a sample workspace called nx-workspace-test-apps (https://github.com/j1mmie/nx-workspace-test-apps), with the following structure:

├── apps
│   ├── functions
│   └── game
└── libs
    └── core

The library, core, has some helper methods that utilize the npm packages canonicalize and secp256k1

The intention is that my game app and my functions app can both use this helper methods and produce the same output.

The game app's startup sequence, and the endpoint helloWorld in the functions app, should both make use of core's helper methods and display similar output.

The problem is that the functions emulator will not successfully execute helloWorld, and instead raises an error.

When I run npx nx serve game, everything works fine. This is the output I see:

➜  nx-workspace-test-apps git:(main) ✗ npx nx serve game

> nx run game:serve

[ watch ] build succeeded, watching for changes...
Debugger listening on ws://localhost:9229/11a148fb-2c5a-45e4-863b-97a52a9b5591
Debugger listening on ws://localhost:9229/11a148fb-2c5a-45e4-863b-97a52a9b5591
For help, see: https://nodejs.org/en/docs/inspector
Hello World
user: Captain Jimmie Bo Bimmy, age 37 years. signature: r2NIiRworD6F6TCTNblADhtTuqGlklfB2GjoMsXR6uY0UnFvIV9jRC6Oj7s/kwoWZPJv8IHQkOx272W+KhNCSA==
user: Madame Ashley Bo Bashy, age 38 years. signature: IYmlYtSzkReK53sYUHGPaIadeg9ua5pwogc2EXjkZ+N/6u3w1i7U7FhOiZnNmM57u+3ha2IMXy5sjzPl2EU15w==

Those are the expected signatures, but that's irrelevant.

The problem:

When I run the firebase emulators, everything starts up fine. But when I request the helloWorld endpoint, I get the following:

i  functions: Beginning execution of "us-central1-helloWorld"
>  Hello World
⚠  functions: TypeError: (0 , canonicalize_1.default) is not a function
    at Signature.hash (/Users/jimmie/Experiments/nx-workspace-test-apps/dist/apps/functions/node_modules/@nx-workspace-test-apps/core/src/lib/signature/Signature.js:10:55)
    at Signature.sign (/Users/jimmie/Experiments/nx-workspace-test-apps/dist/apps/functions/node_modules/@nx-workspace-test-apps/core/src/lib/signature/Signature.js:16:27)
    at /Users/jimmie/Experiments/nx-workspace-test-apps/dist/apps/functions/src/index.js:16:35
    at cloudFunction (/Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-functions/lib/v1/providers/https.js:51:16)
    at /Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:532:16
    at runFunction (/Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:506:15)
    at runHTTPS (/Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:531:11)
    at /Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:690:27
    at Layer.handle [as handle_request] (/Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/jimmie/Experiments/nx-workspace-test-apps/node_modules/firebase-tools/node_modules/express/lib/router/route.js:144:13)
⚠  Your function was killed because it raised an unhandled error.
i  Request to function failed: Error: socket hang up

The canonicalize function that my game app is using just fine, is not a function in my functions app. I've logged its typeof in the functions app - it is undefined

This problem is not unique to the canonicalize library - it seems to happen with any package the core imports. For example, I've tried this with the WebSocketServer class from ws - same issue.

Additional notes:

When I run npx nx build functions, I get this output:

Compiling TypeScript files for project "functions"...
Done compiling TypeScript files for project "functions".
- Processing dependencies for firebase functions app 'functions':
 -  Added 'npm' dependency 'canonicalize'
 -  Added 'npm' dependency 'firebase-admin'
 -  Added 'npm' dependency 'firebase-functions'
 -  Added 'npm' dependency 'secp256k1'
 - Copied 'lib' dependency '@nx-workspace-test-apps/core'
- Updated firebase functions package.json

That seems great - the two npm dependencies from @nx-workspace-test-apps/core are accounted for.

Relevant package versions:

Also, I kept a log of everything I did to create this workspace, if that's helpful:

# 1. Create new workspace:
npx create-nx-workspace --preset=apps

# 2. Install @nrwl/node
npm install -D @nrwl/node

# 3. Generate game app:
npx nx generate @nrwl/node:application game

# 4. Generate core lib:
npx nx generate @nrwl/node:lib --buildable core

# 5. Create functions app:
npx nx g @simondotm/nx-firebase:app functions

# 6. Deleted unused files:
rm apps/functions/database.rules
rm apps/functions/storage.rules

# 7. Remove unused service keys from /firebase.json:
# database, hosting, storage, emulators/database, emulators/hosting
# emulators/pubsub, emulators/storage, emulators/eventarc

# 8. Set node version to `nodejs18` in /firebase.json

# 9. Set node version from " 16" to "18" in apps/functions/package.json

# 10. Log into firebase
npx firebase login

@ 11. Create .firebaserc
npx firebase use --add

I also removed the e2e folders for this demo repo.

Sorry for the wall of text. Any help with this would be greatly appreciated. Thanks

j1mmie commented 1 year ago

I may have figured it out. I've set esModuleInterop to true in my lib's tsconfig. Seems to be working. Going to try a few more things before I close this out.

FWIW, this is what my lib's tsconfig looks like now:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "../../dist/out-tsc",
    "declaration": true,
    "types": ["node"],
    "esModuleInterop": true,
  },
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
  "include": ["src/**/*.ts"]
}

AFAIK this is the default that @nrwl/js generates, just with the addition of esModuleInterop

simondotm commented 1 year ago

Hi @j1mmie , glad you resolved it. I've had this issue too in the past with some commonjs npm packages that export an interface rather than a default, and also solved it with esModuleInterop.

import * as canonicalize from 'canonicalize' might work also