I’ve been trying to get the Dropzone upload to work in Safari, after many different attempts, I came to the conclusion that there seems to be an issue in the way the file object is passed to the extension. The implementation works in Chrome (including CORS).
The docs state the limitation:
At present, DropZone does not offer image upload preview capabilities. The use of object URLs directly in an image component is not possible due to the extension and host operating on separate domains.
Which makes sense, as the app extension is running with the null origin. However in our tests, the fetch call also cannot access the file object, this completely prevents the upload from working in Safari.
I always get the following error in the console:
Not allowed to load local resource: blob:null/994fe27e-2379-495d-a58c-750dbc1245cb
Cannot load blob:null/994fe27e-2379-495d-a58c-750dbc1245cb due to access control checks
I’ve tried many approaches, including:
- Uploading to Staged Media URL as suggested in this Guide. With the URL https://shopify-staged-uploads.storage.googleapis.com/ (passes CORS checks, but still gets the same error when the browser tries to read the file when passed to fetch)
- This comment form Shopify staff suggest using XHR. Which actually works during dev mode, but once the extension is published, XHR access is not supported.
- Many different variations of fetch calls (PUT with body, POST with FormData)
Here is a simplified extension that can be used to reproduce the issue:
import {BlockStack, DropZone, reactExtension, TextBlock, Banner, Image, useApi } from "@shopify/ui-extensions-react/customer-account";
import {useState} from 'react';
export default reactExtension(
"customer-account.order-status.block.render",
() => <CustomerUpload/>
);
function CustomerUpload() {
const {i18n} = useApi();
const [image, setImage] = useState(null);
return (
<Banner>
<BlockStack inlineAlignment="center">
<TextBlock>Basic Upload</TextBlock>
<DropZone
onInput={async ([file]) => {
// Uploading provided file to a server using fetch API
const formData = new FormData();
formData.append('file', new File([file], file.name));
try {
// WORKS with any api that has CORS enabled EXCEPT in Safari
// Access-Control-Allow-Origin: *
//
// To reproduce issue hardcoded incorrect URL
// CHROME: fetch throws a CORS error (expected)
// SAFARI: the browser already throws error on fetch (no cors is initiated)
const url = 'https://shopify.com/upload';
const uploadResponse = await fetch(url, {
method: 'POST',
body: formData
});
const uploadData = await uploadResponse.json();
console.debug('Upload response:', uploadResponse);
setImage(uploadData.url);
} catch (error) {
console.error('Upload failed:', error);
}
}}
></DropZone>
{image ? <Image source={image} /> : null}
</BlockStack>
</Banner>
);
}
Note: the example has a fixed URL that is expected to fail CORS checks, but the Safari issue already happens before CORS checks are applied. Valid CORS URLs work fine in Chrome, but not in Safari
Please if anyone at Shopify can take a look at this issue, I would really appreciate it!
