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

fix: fallback when fetch does not supports URL scheme "data" #410

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

pecoram
Copy link
Contributor

@pecoram pecoram commented Oct 8, 2024

This PR implements a fallback for cases where createImageBitmap is supported but the fetch fails because does not supports URL scheme "data" (for example when using a polyfill).

const response = await fetch(src);
blob = await response.blob();
} catch (error) {
const base64data = base64DataFromSrc(src);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very unsafe:

  • There can be many errors caught here,
  • It seems to be blindly trying to parse src as a data URL, while this seem like a very specific case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like this is better?

@pecoram pecoram requested a review from elsassph October 8, 2024 16:19
Copy link
Contributor

@wouterlucas wouterlucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I don't think we should do fallback when we can predetermine that the createImageBitmap won't work.

In such case we should just rely on Image() and turn off the path that involves createImageBitmap.

const response = await fetch(src);
const blob = await response.blob();
let blob;
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if fetch is a promise, why wrap it in a try/catch block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's idiomatic nowadays to try { await } catch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it? that doesn't automatically mean its a good idea 🙃

const response = await fetch(src);
blob = await response.blob();
} catch (error) {
if (src.startsWith('data:')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it make more sense to do the src.startsWith('data:') check up top before or just after we do fetch? Sounds expensive to always make the fetch fail first, deal with the error chain and then try to parse a data blob.

If its only an error case you're worried about, why not:

const response = await fetch(src).catch( e => { /* .... handle error */ });

if (!response && src.startWith('data:')) {
  /* ... do alternate parsing here */
}

If this if this is a 1 in 10 or 1 in 100 time case, going through the try/catch error chain to then figure out its a data: and do an alternative path is very expensive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly think this is a bad idea, rather keep things straight and neat instead of trying to fallback and make it work. If the feature is not available, we shouldn't try to make it work. It will cause confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a specific case where createImageBitmap exists but fetch("data:..") is not compatible.
I detected it using createImageBitmap polyfill.
I don't know in advance if the device supports it or not and the fetch only returns me a message without an errorcode or type: Fetch API cannot load data:image/png;base64,iVB... URL scheme "data" is not supported.

Copy link
Contributor Author

@pecoram pecoram Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What can I do is using a function like this:

async function supportsDataURLFetch() {
  try {
    await fetch('data:text/plain,Test');
    return true;
  } catch (error) {
    return false;
  }
}

or

function supportsDataURLFetch() {
  return fetch('data:text/plain,Test')
    .then(() => true)
    .catch(() => false);
}

and check it at startup

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two questions:

  • Does polyfilling it actually helps over just turning createImageBitmap support off?
  • What polyfill are you using, as this seems like limitations of the polyfill?

Copy link
Contributor Author

@pecoram pecoram Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the polyfill (https://gist.github.com/pseudosavant/a6d970b945ae85ef4dbc43200da94faf) because the images were not taking the correct size, but with polyfill it was giving me that exception. Then I realised that by removing width and height from the new Image everything worked correctly and then I could remove the polyfill. I added the fallback in the PR to avoid potential problems like this.

}

mimeType = mimeType ?? 'image/png';
base64Content = base64Content ?? src;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it didn't match, it would still return src and then fail down below in the base64toBlob?
I think we should handle the error case more strictly if we can figure it is not Base64 and bail out gracefully.

@pecoram
Copy link
Contributor Author

pecoram commented Oct 14, 2024

OK - I'm opening the PR with just the change we need, then we'll consider whether to go ahead with this

@pecoram pecoram changed the title fix: loadImage on a device without creteImageBitmap fix: fallback when fetch does not supports URL scheme "data" Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants