NativeScript / firebase

Modular Firebase 🔥 implementation for NativeScript. Supports both iOS & Android platforms for all Firebase services.
https://docs.nativescript.org/plugins/firebase-core.html
Apache License 2.0
52 stars 46 forks source link

`const admin = require('firebase-admin')` crashes with `TypeError: Cannot read properties of undefined (reading 'env')` #232

Closed dlcole closed 10 months ago

dlcole commented 10 months ago

Earlier this week I, like others, started receiving web pack errors such as

Module not found: Error: Can't resolve 'util' in '/Users/david/Documents/NativeScriptProjects/rrr/node_modules/@fastify/busboy/lib/utils'

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: { "util": require.resolve("util/") }'
    - install 'util'
If you don't want to include a polyfill, you can use an empty module like this:
    resolve.fallback: { "util": false }

I had over 200 such errors. After investigating for several hours, I edited my webpack.config.js file thusly:

const webpack = require("@nativescript/webpack");

module.exports = (env) => {

  // See https://stackoverflow.com/questions/70428159/nativescript-8-1-migration-adding-external-to-webpack-config-js
  env.appComponents = (env.appComponents || []).concat(['./foreground-service.android'])

  webpack.init(env);

    // Learn how to customize:
    // https://docs.nativescript.org/webpack

  webpack.Utils.addCopyRule('data/**')
  webpack.Utils.addCopyRule('files/**')
  webpack.Utils.addCopyRule('**/*.db')

  webpack.mergeWebpack({
    resolve: {
      fallback: {
        assert: require.resolve("assert/"),
        browserify: false,
        buffer: require.resolve("buffer/"),
        child_process: false, 
        crypto: require.resolve("crypto-browserify"), 
        dns: false,
        fs: false,
        http: require.resolve("stream-http"),
        https: require.resolve("https-browserify"),
        http2: false,
        net: false,
        os: require.resolve("os-browserify/browser"),
        path: require.resolve("path-browserify"),
        querystring: require.resolve("querystring-es3"),
        request: false,
        stream: require.resolve("stream-browserify"),
        tls: false,
        tty: require.resolve("tty-browserify"),
        url: require.resolve("url/"),
        util: require.resolve("util/"),
        zlib: require.resolve("browserify-zlib"),
      },
    },
  });

    return webpack.resolveConfig();
};

In short, I installed the packages suggested by the log file errors, such as util, and added the associated require.resolve, and set to false those items that did not have a suggested package. This resolved the build errors, but now I get a crash when I navigate to a page that requires firebase-admin (so as to send firebase messages):

  System.err: An uncaught Exception occurred on "main" thread.
  System.err: Calling js method onClick failed
  System.err: TypeError: Cannot read properties of undefined (reading 'env')
  System.err:
  System.err: StackTrace:
  System.err: ./node_modules/util/util.js(file: app/webpack:/rrr/node_modules/util/util.js:109:11)
  System.err:   at __webpack_require__(file: app/webpack:/rrr/webpack/bootstrap:24:0)

I have to think these two are related, but I’m at a loss as to how to proceed. Can anyone confirm whether this is the correct approach to handling the webpack 5 polyfill errors?

edusperoni commented 10 months ago

Most likely you need to polyfill global.process as it's undefined in NativeScript, and these libraries check for process.env.

That said, I'd strongly recommend against using firebase-admin in your app. From the package documentation:

Please also note that the Admin SDK should only be used in server-side/back-end environments controlled by the app developer. This includes most server and serverless platforms (both on-premise and in the cloud). It is not recommended to use the Admin SDK in client-side environments.

Using it in your app is most likely result in your firebase credentials leaking and being abused, as opening up APKs and IPAs is trivial.

dlcole commented 10 months ago

@edusperoni The only reason I was using firebase-admin is because that's the only example I saw in the @firebase-messaging doc. Should I be posting hhtp requests like I did with the older firebase plugin, but using the newer firebase API?

edusperoni commented 10 months ago

@dlcole the examples there are for the backend to send messages. In which case you need to have a backend with your credentials and expose an API that the user will call which in turn calls the admin SDK to post a message.

You'd usually need firebase messaging if you need to send messages to specific users (chat app, user send message to another user, you trigger a firebase message with the data), send messages independent of user action (ad campaign, etc), and similar things. If you need to display local notifications instantly or after a while you can use the local-notifications plugin