I'd like to send a File (from a <input type="file"> or drop event DataTransfer) to a newly opened window with postMessage:
const win = open(...);
win.postMessage({ file }, { transfer: [file] });
The HTML spec says this about postMessage:
Posts a message to the given window. Messages can be structured objects, e.g. nested objects and arrays, can contain JavaScript values (strings, numbers, Date objects, etc.), and can contain certain data objects such as
FileBlob,FileList, andArrayBufferobjects.
However this doesn't seem to work — it throws a DataCloneError in Chrome, Safari, and Firefox. I also tried sending the file to a new worker via new Worker(), and sending a file handle from showOpenFilePicker(), both with the same result. Is it possible to send a File to another window via postMessage?
This one seems to indicate that sending file handles should work:
File System Access API: how to send a fileHandle with postMessage?
This existing question is 6 years old and doesn't mention the transfer parameter:
How to pass a File object via postMessage or any similar function
This question is relevant, but was unanswered and is 8 years old and does not use the transfer parameter:
Transfer file to webworker: DataCloneError: The object could not be cloned
const workerSrc = `
console.log('hello from worker')
self.postMessage("worker initialized");
self.onmessage = (e) => {
self.postMessage("worker received file");
console.log('got message',e)
}
`;
const workerUrl = URL.createObjectURL(
new Blob([workerSrc], { type: "application/javascript" })
);
const worker = new Worker(workerUrl);
worker.onmessage = (e) => {
console.log("message from worker:", e.data);
};
const input = document.createElement("input");
// input.textContent = "Choose file"
input.setAttribute("type", "file");
document.body.appendChild(input);
input.addEventListener("change", () => {
// const handles = await showOpenFilePicker();
// const file = handles[0];
const file = input.files[0];
// console.log("file is", file);
try {
// const win = open("http://localhost:8080/");
// win.postMessage({ example: file }, "http://localhost:8080/", [file]);
worker.postMessage({ example: file }, { transfer: [file] });
console.log("transferred", file);
} catch (err) {
const div = document.createElement("div");
div.textContent = `${err.name}: ${err.toString()}`;
document.body.appendChild(div);
console.error(err.name, err);
}
});