Sending files to service worker through runtime.sendMessage()

48 views
Skip to first unread message

ComputerWhiz

unread,
Jan 19, 2022, 1:52:11 PM1/19/22
to Chromium Extensions
From my extension settings page, I'm trying to save a user-provided file to the extension's IndexedDB. To do so, I'm using the Runtime API to send the file to the extension service worker and then the service worker is using the IndexedDB API to save the file.

In the Javascript file for my options page, I have this function that's called when the user presses the upload button:

function uploadFile() {
    chrome.runtime.sendMessage({
        action: 'upload',
        file: document.getElementById('file-input').files[0]
    });
}

The service worker Javascript file then uses a message listener to run the following function:

function handleMessage(message, sender, sendResponse) {
    switch (message.action) {
        case 'upload':
            saveFile(message.file);
            break;
        ...
    }
}

The issue is that the file is not being sent through the messaging. Instead, an empty object is being sent to the service worker. I've debugged and can see there's no issues with the options file or the actual IndexedDB portion of the service worker. The issue seems to be a limitation of the runtime API.

The exact same code works fine in Firefox. I've checked both MV2 and MV3 in Google Chrome and neither seems to work.

Am I doing something wrong? Is there some other way to send a file to the service worker?

hrg...@gmail.com

unread,
Jan 19, 2022, 3:55:23 PM1/19/22
to Chromium Extensions, ComputerWhiz
You can save the file to IndexedDB directly from the settings page.

The  runtime.sendMessage function can only send JSONable data. A File object is not JSONable.

wOxxOm

unread,
Jan 20, 2022, 9:19:27 AM1/20/22
to Chromium Extensions, hrg...@gmail.com, ComputerWhiz
Use the native service worker messaging which is faster and supports more types than chrome.runtime.

async function uploadFile() {
  const swReg = await navigator.serviceWorker.ready;
  swReg.active.postMessage({
    file: document.getElementById('file-input').files[0],
  });
}

The listener in background.js:

self.onmessage = e => {
  console.log(e.data);
};

You can also use BroadcastChannel API.

wOxxOm

unread,
Jan 20, 2022, 9:22:29 AM1/20/22
to Chromium Extensions, wOxxOm, hrg...@gmail.com, ComputerWhiz
...although saving it directly to indexedDB does seem better, especially for a large file, because even native service worker messaging probably requires a lot of internal work to transfer the data to the different OS thread of the worker.
Reply all
Reply to author
Forward
0 new messages