From dce528372df64f73a4325711aedaf4c7525b838f Mon Sep 17 00:00:00 2001 From: bintangakbarRK Date: Tue, 4 Aug 2026 14:03:02 +0700 Subject: [PATCH 1/2] fix: remove dead promise polyfill import Since Hermes is the only supported JS engine and always provides a native Promise implementation, the `else` branch in polyfillPromise.js that imports the `promise` package via `../Promise` is dead code that can never execute (`hasPromise()` is always true). This dead import causes the bundler to include the entire `promise` package (~15KB) in every app's JS bundle despite it never being used. Remove the dead branch and the unused `polyfillGlobal` import. Fixes #57702 --- .../Libraries/Core/polyfillPromise.js | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/react-native/Libraries/Core/polyfillPromise.js b/packages/react-native/Libraries/Core/polyfillPromise.js index 5bfec271d1c5..14124d809dc5 100644 --- a/packages/react-native/Libraries/Core/polyfillPromise.js +++ b/packages/react-native/Libraries/Core/polyfillPromise.js @@ -10,29 +10,22 @@ 'use strict'; -const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); - /** - * Set up Promise. The native Promise implementation throws the following error: - * ERROR: Event loop not supported. + * Set up Promise. Hermes provides a native Promise implementation that + * satisfies all requirements of React Native. * * If you don't need these polyfills, don't use InitializeCore; just directly * require the modules you need from InitializeCore for setup. */ -// If global.Promise is provided by Hermes, we are confident that it can provide -// all the methods needed by React Native, so we can directly use it. -if (global?.HermesInternal?.hasPromise?.()) { - const HermesPromise = global.Promise; +// Hermes is the only supported JS engine and always provides Promise natively. +const HermesPromise = global.Promise; - if (__DEV__) { - if (typeof HermesPromise !== 'function') { - console.error('HermesPromise does not exist'); - } - global.HermesInternal?.enablePromiseRejectionTracker?.( - require('../promiseRejectionTrackingOptions').default, - ); +if (__DEV__) { + if (typeof HermesPromise !== 'function') { + console.error('HermesPromise does not exist'); } -} else { - polyfillGlobal('Promise', () => require('../Promise').default); + global.HermesInternal?.enablePromiseRejectionTracker?.( + require('../promiseRejectionTrackingOptions').default, + ); } From cef324678a1a9977c43df5a77a8e3aa61789d0c3 Mon Sep 17 00:00:00 2001 From: bintangakbarRK Date: Tue, 4 Aug 2026 14:21:37 +0700 Subject: [PATCH 2/2] fix(Image): support data: URIs in getSize/getSizeWithHeaders on Android After #56736 changed getSize() from fetchDecodedImage to fetchEncodedImage, data: URIs started throwing IllegalArgumentException because Fresco's encoded-image producer sequence does not support the 'data' URI scheme. Add a fast path (similar to the res:// fast path from #56944) that routes data: URIs through fetchDecodedImage, which supports data: URIs via DataFetchProducer. This restores the behavior from 0.84.x where Image.getSize() worked correctly with base64-encoded data: URIs. Fixes #57787 --- .../react/modules/image/ImageLoaderModule.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.kt index aaa6181d46c2..d807dc15f684 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/image/ImageLoaderModule.kt @@ -20,6 +20,7 @@ import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.fbreact.specs.NativeImageLoaderAndroidSpec import com.facebook.imagepipeline.common.RotationOptions import com.facebook.imagepipeline.core.ImagePipeline +import com.facebook.imagepipeline.image.CloseableImage import com.facebook.imagepipeline.image.EncodedImage import com.facebook.imagepipeline.request.ImageRequest import com.facebook.imagepipeline.request.ImageRequestBuilder @@ -93,6 +94,13 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL resolveResourceSize(uriString, promise) return } + // Fast path: data: URIs are not supported by fetchEncodedImage's producer + // sequence (throws IllegalArgumentException). Route them through the decoded + // image pipeline which handles data: URIs via DataFetchProducer. + if ("data" == source.uri.scheme) { + resolveDecodedImageSize(source, promise) + return + } val request: ImageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri) .setRotationOptions(RotationOptions.disableRotation()) @@ -122,6 +130,11 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL resolveResourceSize(uriString, promise) return } + // Fast path: data: URIs are self-contained; headers are not applicable. + if ("data" == source.uri.scheme) { + resolveDecodedImageSize(source, promise) + return + } val imageRequestBuilder: ImageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(source.uri) .setRotationOptions(RotationOptions.disableRotation()) @@ -217,6 +230,59 @@ internal class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventL ) } + /** + * Resolve the size of a data: URI (or any URI unsupported by the encoded-image pipeline) + * by decoding the image through Fresco's decoded-image pipeline, which routes through + * DataFetchProducer and supports data: URIs. + */ + private fun resolveDecodedImageSize(source: ImageSource, promise: Promise) { + val request: ImageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri).build() + val dataSource: DataSource> = + this.imagePipeline.fetchDecodedImage(request, this.callerContext) + dataSource.subscribe( + object : BaseDataSubscriber>() { + override fun onNewResultImpl( + dataSource: DataSource> + ) { + if (!dataSource.isFinished) { + return + } + val ref = dataSource.result + if (ref != null) { + try { + val image = ref.get() + val width = image.width + val height = image.height + if (width < 0 || height < 0) { + promise.reject(ERROR_GET_SIZE_FAILURE, "Failed to get the size of the image") + return + } + promise.resolve( + buildReadableMap { + put("width", width) + put("height", height) + }, + ) + } catch (e: Exception) { + promise.reject(ERROR_GET_SIZE_FAILURE, e) + } finally { + CloseableReference.closeSafely(ref) + } + } else { + promise.reject(ERROR_GET_SIZE_FAILURE, "Failed to get the size of the image") + } + } + + override fun onFailureImpl( + dataSource: DataSource> + ) { + promise.reject(ERROR_GET_SIZE_FAILURE, dataSource.failureCause) + } + }, + CallerThreadExecutor.getInstance(), + ) + } + /** * Prefetches the given image to the Fresco image disk cache. *