-
Notifications
You must be signed in to change notification settings - Fork 135
Description
Introduction
I recently started using React Native for an application initiative at current job. During some web-based front end work, I created some internal libraries to standardize our data access. These libraries make use of axios to send requests and thus far have presented no issues when working with sending & slicing Blob
instances from browsers. I know this logic is good because it's currently deployed and we receive files from web browsers running it daily.
Given that React Native - after a fashion - builds on top of the JS ecosystem, this seemed like a great opportunity to reuse our data access library as we begin work building our app! 🎉
The Core of It
Unfortunately, one of our internal libraries which makes direct use of axios to send binary data to signed S3 bucket URIs failed on React Native. Here's the salient bit from our internal library:
const partBytes = data.slice(start, start + size);
if (!partBytes.size) {
throw new Error(`Upload of ${upload.id} failed, empty chunk encountered ${index}.`);
}
const request = axios.put(presignedUploadUri, partBytes, {
onUploadProgress: (progressEvent: any) => {
upload.parts[index].progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
this.reportProgress(upload, callbacks);
},
headers: {
"content-type": "binary/octet-stream",
},
});
You can see in the example above that I'm using the standard Blob API to slice up the file and am then passing the result to axios to ship to S3. Unfortunately, when the blob being sent to the library originates from React Native, instead of sending bytes to the destination, I end up sending a string body that looks like this:
{
"_data": {
"blobId": "9fe44032-4518-4eba-9373-c759ce8daa06",
"offset": 0,
"size": 30548
}
}
For people familiar with React Native internals, this is probably enough of a description, I have some suspicions about what's going on here. It mostly pertains to "blobs" being predicated on originating from fetch
and only ever being sent back to fetch
, resulting in a cloistered implementation.
That said, I have taken the time to put together a demonstration repository so as to avoid any concern over nuance.
This is an issue for me because I now have to duplicate my binary upload routine inside of my React Native project. I presume because I need a specialized fetch
implementation to recognize these specialized pseudo-blob instances. This also concerns me as pure JS libraries (maybe also native libraries) won't be able to depend on a standard Blob implementation for byte-level manipulations.
Discussion Points
- Implementing blobs properly - such that they can be used between libraries
- Checks & balances during React Native development to ensure that any bias towards fast paced or high profile items doesn't drown out slow moving concerns like web standards support
- How did base64 strings get a pass for a platform that targets power and performance sensitive devices?
Bonus Meta Discussion Point
I've opened this discussion as per a kind response I received during a recent AUA.
I first want to say, thank you so much for the invitation, it made me feel comfortable enough to raise this issue one more time. 😄
As a knock-on though, I would like to be serious for just a bit and point out that I was pretty much ready to throw in the towel on this issue.
Communication and triage around this topic has not been the greatest. Despite me attempting multiple times in multiple channels to raise the topic on top of the fact that I'm a newcomer to React Native. There's no documentation that clearly outlines the ability to obtain references to files on-device as blobs. I actually had to make two posts about it during the AUA because the first one got glossed over, very much in the same form as all my other attempts to raise awareness. I even tried on the reactiflux discord.
I've seen a lot of chatter about community involvement. But in this paragraph, I have mentioned github, twitter, reddit and discord as the platforms I've attempted to reach out on. Each time, to no response.
The tldr; of this next paragraph is that I'm quite certain a loose initial description from me way back when I first encountered the problem should have been enough for someone on the React Native team to go "oh yeap, I think I see the issue you're having".
I think the React Native team needs to graduate from the more performative and cuddly aspects of communication and transparency and now start looking at what it will take to be proactive and qualitative about the initiative. You'll need a cohesive strategy for both identifying and prioritizing the deeper issues that can sometimes arise in the realm of platform work. Most of all though, you can't possibly expect all of your users who encounter real issues to go to the numerous extents I have here.
I've spent the whole day collating this information and preparing a demo repository - not because this issue isn't easily intuited by React Native maintainers - but to simply put it in such incontrovertible terms that it's more difficult to wave off.
Someone already did the legwork to spot an issue and that wasn't enough to indicate internally that there might be some problematic design choices made in the blob implementation.
Quips about how hard it is to be a maintainer aside: It's just too much if this is what it takes for your users to get noticed!
I would finally like to add that I wholly recognize and appreciate the effort of the maintainers, Facebook and pretty much everything along the way to the software engineering marvel that is React Native.
Seriously, much love. ❤️
(I reserve the right to edit this or add entire missing paragraphs, I'm exhausted!)