Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

undici dependency breaks bundling with React Native (Expo) due to use of stream module #7849

Closed
arvl130 opened this issue Dec 11, 2023 · 12 comments

Comments

@arvl130
Copy link

arvl130 commented Dec 11, 2023

Operating System

Windows, Linux

Browser Version

Chrome, Firefox

Firebase SDK Version

10.7.1

Firebase SDK Product:

Auth

Describe your project's tooling

  • React Native with Expo SDK 49
  • Development client: enabled
  • Developing for: Web (where the issue appears), Android, iOS

Describe the problem

Initializing Firebase on Expo with the dev client enabled, and running onAuthStateChanged produces this bundling error:

Web Bundling failed 16275ms
Unable to resolve "stream/web" from "node_modules/undici/lib/core/util.js"
Web node_modules/expo-router/entry.js ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░ 85.6% (815/881)
Metro error: Unable to resolve module stream/web from /home/arvl/src/firebase-reactnative-broken-deps-repro/node_modules/undici/lib/core/util.js: stream/web could not be found within the project or in these directories:
  node_modules

  369 | function ReadableStreamFrom (iterable) {
  370 |   if (!ReadableStream) {
> 371 |     ReadableStream = require('stream/web').ReadableStream
      |                               ^
  372 |   }
  373 |
  374 |   if (ReadableStream.from) {

  117 |             const errorObject = JSON.parse(text);
  118 |             var ref;
> 119 |             throw new MetroNodeError((ref = (0, _ansi).stripAnsi(errorObject.message)) != null ? ref : errorObject.message, errorObject);
      |                   ^
  120 |         }
  121 |         throw new Error(`[${res.status}]: ${res.statusText}\n${text}`);
  122 |     }

Call Stack
  requireFileContentsWithMetro (node_modules/@expo/cli/build/src/start/server/getStaticRenderFunctions.js:119:19)
  process.processTicksAndRejections (node:internal/process/task_queues)
  async Object.getStaticRenderFunctions (node_modules/@expo/cli/build/src/start/server/getStaticRenderFunctions.js:139:28)
  async bundleStaticHtml (node_modules/@expo/cli/build/src/start/server/metro/MetroBundlerDevServer.js:170:43)
  async MetroBundlerDevServer.getStaticPageAsync (node_modules/@expo/cli/build/src/start/server/metro/MetroBundlerDevServer.js:179:41)
  async (node_modules/@expo/cli/build/src/start/server/metro/MetroBundlerDevServer.js:291:46)

Based on my understanding, this error is caused by Firebase's new dependency undici. The package uses the stream module under the hood, which is not supported by Metro currently.

The workaround for now is to downgrade to v10.6.0 which doesn't use undici, and thus has no use of the stream module.

I've read from another issue that the Firebase project is in the process of migrating from node-fetch to undici. I'm curious if there are any better workarounds—or perhaps fixes—that could be done here, as it does not seem like Metro is going to support the stream module anytime soon.

Steps and code to reproduce issue

You may check this GitHub repo for a reproduction of the issue: https://github.com/arvl130/firebase-reactnative-broken-deps-repro

@arvl130 arvl130 added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Dec 11, 2023
@jbalidiong jbalidiong added needs-attention and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Dec 11, 2023
@mikehardy
Copy link

I was curious about this @arvl130 as I work at the intersection of firebase-js-sdk and react-native-firebase so these "in-between" issues are always interesting

Have you tried pulling in the readable-streams userland streams library as a dependency on your project, then using metro resolver directives to map them in?

https://stackoverflow.com/a/66629901/9910298

@arvl130
Copy link
Author

arvl130 commented Dec 15, 2023

I tried installing the package you mentioned and added this to metro.config.js:

module.exports = {
  resolver: {
    extraNodeModules: {
      stream: require.resolve("readable-stream"),
    },
  },
}

For some reason, Metro is still not able to find the package. I also tried this:

const config = getDefaultConfig(__dirname, {
  // [Web-only]: Enables CSS support in Metro.
  isCSSEnabled: true,
})

config.resolver.extraNodeModules.stream = require.resolve("readable-stream")
module.exports = config

And got the same error.

EDIT: @mikehardy I misread the error. The resolver config actually works fine. The problem with mapping stream to readable-stream is that it doesn't export readable-stream/web, which causes the same error:

Metro error: Unable to resolve module stream/web from /home/arvl/src/expo-universal-google-signin-demo/node_modules/undici/lib/core/util.js: stream/web could not be found within the project or in these directories:
  node_modules
  
  /home/arvl/src/expo-universal-google-signin-demo/node_modules/readable-stream/lib/ours/index.js/web
  369 | function ReadableStreamFrom (iterable) {
  370 |   if (!ReadableStream) {
> 371 |     ReadableStream = require('stream/web').ReadableStream
      |                               ^
  372 |   }
  373 |
  374 |   if (ReadableStream.from) {

  117 |             const errorObject = JSON.parse(text);
  118 |             var ref;
> 119 |             throw new MetroNodeError((ref = (0, _ansi).stripAnsi(errorObject.message)) != null ? ref : errorObject.message, errorObject);
      |                   ^
  120 |         }
  121 |         throw new Error(`[${res.status}]: ${res.statusText}\n${text}`);
  122 |     }

@mikehardy
Copy link

Ok, now I'm really proposing ugly things, but I wonder if you could add "stream/web" in your extra resolution as well? No idea if the API shapes are the same, but...

Anyway, if this doesn't work at all and ends up costing you time I apologize - just brainstorming possible workarounds without testing

@medv
Copy link

medv commented Dec 15, 2023

relevant: nodejs/readable-stream#525

Thanks for pointing in a good direction @mikehardy will have to circle back to this when time permits, for now firebase stays on 10.6.0 unfortunately.

@DellaBitta
Copy link
Contributor

DellaBitta commented Dec 15, 2023

We've limited the use of undici to non browser-based targets (ie: node) so it shouldn't be included as a dependency when building for browser targets.

This problem seems to stem from metro using the main field in Firebase Auth's package.json instead of the browser field, despite the fact the project is building for a web target.

If you go into node_modules/@firebase/auth/package.json and copy the browser value of dist/esm2017/index.js and paste it over the main value of dist/node/index.js then your reproducible test case will pass.

I made (unfortunately fruitless) attempts to force the metro resolver to use browser by declaring a custom value for resolverMainFields to have a single value of browser instead of its default list which includes main, but I couldn't get the resolver to honor the customization. Perhaps you might have better luck than I did.

That being said, it shouldn't be required since the default value for resolverMainFields is ['react-native', 'browser', 'main'], with browser listed before main. I assume that this list is in precedence order, but perhaps it's not.

At any rate, it seems that there's something that's pushing the resolver to use main instead of browser for some reason. It might be worth opening an issue in the Metro GitHub issue forum to see if they have any insights as to why.

I hope this helps somewhat.

@arvl130
Copy link
Author

arvl130 commented Dec 16, 2023

I don't know enough about package.json module resolution to report over to the Metro GitHub, but hopefully someone else can explore this issue on that front.

@arvl130
Copy link
Author

arvl130 commented Dec 16, 2023

@mikehardy Adding this to metro.config.js:

config.resolver.extraNodeModules["stream/web"] = require.resolve("readable-stream")

unfortunately yields the same error as the one I initially reported:

Web Bundling failed 68062ms
Unable to resolve "stream/web" from "node_modules/undici/lib/core/util.js"
Web node_modules/expo-router/entry.js ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░ 85.7% (801/865)
Metro error: Unable to resolve module stream/web from /home/arvl/src/expo-universal-google-signin-demo/node_modules/undici/lib/core/util.js: stream/web could not be found within the project or in these directories:
  node_modules
  
  369 | function ReadableStreamFrom (iterable) {
  370 |   if (!ReadableStream) {
> 371 |     ReadableStream = require('stream/web').ReadableStream
      |                               ^
  372 |   }
  373 |
  374 |   if (ReadableStream.from) {

  117 |             const errorObject = JSON.parse(text);
  118 |             var ref;
> 119 |             throw new MetroNodeError((ref = (0, _ansi).stripAnsi(errorObject.message)) != null ? ref : errorObject.message, errorObject);
      |                   ^
  120 |         }
  121 |         throw new Error(`[${res.status}]: ${res.statusText}\n${text}`);
  122 |     }

Anyhow, thanks for the suggestions. For my current project, I'm actually trying to get firebase-js-sdk working on Web, and react-native-firebase on Android and iOS. That's how I encountered this issue.

It looks like, for now, pinning to 10.6.0 is the best resolution, until they can get it sorted out in the Metro side of things.

@google-oss-bot
Copy link
Contributor

Hey @arvl130. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

@google-oss-bot
Copy link
Contributor

Since there haven't been any recent updates here, I am going to close this issue.

@arvl130 if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.

@dandankarai
Copy link

dandankarai commented Jan 25, 2024

  node_modules
  369 | function ReadableStreamFrom (iterable) {
  370 |   if (!ReadableStream) {
> 371 |     ReadableStream = require('stream/web').ReadableStream
      |                               ^
  372 |   }
  373 |
  374 |   if (ReadableStream.from) {

  117 |             const errorObject = JSON.parse(text);
  118 |             var ref;
> 119 |             throw new MetroNodeError((ref = (0, _ansi).stripAnsi(errorObject.message)) != null ? ref : errorObject.message, errorObject);
      |                   ^
  120 |         }
  121 |         throw new Error(`[${res.status}]: ${res.statusText}\n${text}`);
  122 |     }

I have this same issue, someone can resolve this?

Expo 49
Node Version 19.0.,0

@Georg7
Copy link

Georg7 commented Jan 26, 2024

Same issue here.
Expo 50
Node 19.0.0

@DellaBitta
Copy link
Contributor

This appears to be a resolver issue with Expo. Have you contacted their support?

@firebase firebase locked and limited conversation to collaborators Jan 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants