1

I made a local npm package to handle write and read of a firestore database for both Angular and Firebase Functions (simple serverless functions from Google)

As dependency it has both firebase-admin and @angular/fire.

//package.json of my local package
{
  "name": "inqompass-repositories",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@angular/fire": "^7.4.1",
    "firebase-admin": "^9.12.0"
  }
}

I combine the 2 packages to create union types. So my package can be used for both Angular and Serverless functions :

//Example FirestoreRepository.ts

type CollectionReference<TDocumentData> = firebase.firestore.CollectionReference<TDocumentData> | admin.firestore.CollectionReference<TDocumentData> 
type Batch = firebase.firestore.WriteBatch | admin.firestore.WriteBatch

export class FirestoreRepository<TDocumentData> {

  protected readonly collection: CollectionReference<TDocumentData>
  constructor(
    collection: CollectionReference<TDocumentData>,
  ) {
    this.collection = collection
  }

  async add(documentData: TDocumentData, batch?: Batch) {
      const document = this.collection.doc()
      batch.set(document, documentData)
      return this.collection.add(documentData)
    }
  }

The problem is, firebase-admin require some nodejs core package that are apparently not available in browser (from what I understod). firestore-admin should be used only for servers.

So, when I try to build my angular project. I get such errors :

../shared/repositories/node_modules/teeny-request/build/src/index.js:26:17-34 - Error: Module not found: Error: Can't resolve 'stream' in '/home/ender/WGMM/InQompass/shared/repositories/node_modules/teeny-request/build/src'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

../shared/repositories/node_modules/teeny-request/build/src/index.js:83:15-37 - Error: Module not found: Error: Can't resolve 'querystring' in '/home/ender/WGMM/InQompass/shared/repositories/node_modules/teeny-request/build/src'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "querystring": require.resolve("querystring-es3") }'
        - install 'querystring-es3'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "querystring": false }

The clean solution I see, is to not load or build the firebase-admin dependency of my package when it's used for an Angular Project.

firebase-admin is only for server side, I am don't wish to use it for my angular projects. The reason it's in my package, is only for the case when my package is used in firebase-function run in servers.

The package can run perfectly fine with only one package loaded

So my question is :

How can I tell my Angular project, to not try to load or build firebase-admin dependency when using my local package ?

Additional information : The goal of this package is to centralize the codebase for the communication with the firestore database. Because write and read can be done from both the front-end and back-end. So users for example, are created the same way across my entire solution.

  • 1
    That error message contains the fix for shimming Node-only modules in the browser, the two lines telling you you can use `resolve.fallback: { some_module: false }`. Another option: you could use `optionalDependencies` for the Node-specific libraries and `npm i --omit=optional` for the browser build, but this would possibly break testing your union types. – Zac Anger Mar 26 '23 at 19:33
  • Yes, modifying the webpack with resolve.fallbacks does solve the build error, but since firebase-admin is still loaded, the application crash, because firebase-admin directly try to use the "os" package. Then the best solution is, as you suggested to directly remove firebase-admin all together when it's in browser environment. But as you said, it break the union types. – Martin Rabaud Mar 26 '23 at 21:53
  • Any core Node modules or modules that only work in Node need to be shimmed like that (fs, os, net, etc.). But you could use the same `resolve.fallbacks` for `firebase-admin` itself, negating the need to go through all those other modules. Depending on where you use your types (before or after a Webpack build), that might be the simplest solution. If you wind up needing to do all builtins in the Webpack config, you could do `resolve.fallback: require('node:module').builtinModules.reduce((p, c) => { p[c] = false; return p }, {})`. But this is brittle if you have deps that load their own shims. – Zac Anger Mar 26 '23 at 22:13

0 Answers0