6

I am attempting to display an alarm that pops up in my browser from background.js in Manifest v3. However, using the code implementation that is described in the Manifest v3 page does not produce an alarm.

Manifest.js:

{
  "name": "Focus-Bot",
  "description": "A bot meant to help you focus",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/get_started16.png",
      "32": "/images/get_started32.png",
      "48": "/images/get_started48.png",
      "128": "/images/get_started128.png"
    }
  },
  "icons": {
    "16": "/images/get_started16.png",
    "32": "/images/get_started32.png",
    "48": "/images/get_started48.png",
    "128": "/images/get_started128.png"
  },
  "options_page": "options.html"
}

Background.js:

chrome.runtime.onInstalled.addListener(() => {
  chrome.scripting.executeScript({
    function: showAlert
  }) 
});

function showAlert(){
    alert('object input for later');
}

This version of background.js returns the following error

TypeError: Error in invocation of scripting.executeScript(scripting.ScriptInjection injection, optional function callback): Error at parameter 'injection': Missing required property 'target'.

The example code of a working Chrome Extension (the green background button) uses chrome.tabs in a popup.js file to get a target and inject javascript, but when background.js runs the same code like this:

Background.js (tabs):

chrome.runtime.onInstalled.addListener(() => {
  let [tab] = await chrome.tabs.query(queryOptions);
  console.log(tab)
  chrome.scripting.executeScript({
    function: showAlert
  }) 
});

function showAlert(){
    alert('object input for later');
}

Background.js seems to crash with "Service worker registration failed", with no error logs.

How do I display an alarm for the current active page from background.js?

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
RedRoach51
  • 103
  • 1
  • 3

1 Answers1

5
  1. As the error message says you need to add target to executeScript's parameters. Always look up the exact usage of API methods in the documentation.

  2. Your code uses await but the function isn't declared with async which is a syntax error that causes the service worker to fail the registration. Currently ManifestV3 is riddled with bugs so it doesn't even show the cause of the failure so you'll have to use try/catch manually.

try {
  chrome.runtime.onInstalled.addListener(async () => {
    const [tab] = await chrome.tabs.query(queryOptions);
    chrome.scripting.executeScript({
      target: {tabId: tab.id},
      function: showAlert,
    });
  });
} catch (e) {
  console.error(e);
}

An arguably better/cleaner approach would be to use two files: the main code in bg.js and the try-catch wrapper in bg-loader.js that imports bg.js, see this example.

Note that the active tab may be un-injectable e.g. a default start page or a chrome:// page (settings, bookmarks, etc.) or a chrome-extension:// page. Instead you can open a small new window:

alert({html: 'Foo <b>bar</b><ul><li>bla<li>bla</ul>'})
  .then(() => console.log('alert closed'));

async function alert({
  html,
  title = chrome.runtime.getManifest().name,
  width = 300,
  height = 150,
  left,
  top,
}) {
  const w = left == null && top == null && await chrome.windows.getCurrent();
  const w2 = await chrome.windows.create({
    url: `data:text/html,<title>${title}</title>${html}`.replace(/#/g, '%23'),
    type: 'popup',
    left: left ?? Math.floor(w.left + (w.width - width) / 2),
    top: top ?? Math.floor(w.top + (w.height - height) / 2),
    height,
    width,
  });
  return new Promise(resolve => {
    chrome.windows.onRemoved.addListener(onRemoved, {windowTypes: ['popup']});
    function onRemoved(id) {
      if (id === w2.id) {
        chrome.windows.onRemoved.removeListener(onRemoved);
        resolve();
      }
    }
  });
}
wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • 1
    Thank you @wOxxOm for this example, you just don't know how much time you have saved for me. It's unfortunate service workers doesn't support alert messages directly and we have to do circus just to display a message to end user. Your solution worked like a charm. Thank you. – bprasanna Feb 20 '22 at 16:34