Keptab Migrate to Manifest V3

Posed at 2023-06-22

Posted by mywaiting


Keptab has upgraded from Manifest V2 to Manifest V3, the newest version of the Chrome Extensions platform. To help you track your work, Chrome developer have provided a Chrome Offical Checklist summarizing the contents of these documents. You can access the content via the checklist and dive into the content.

Combining our own plugin upgrade process, let's talk about how to migrate to Manifest V3 in real action.

Keptab Screenshot

Keptab: manage tabs friendly and reduce tabs clutter

Update the manifest

The manifest.json file requires a slightly different format for Manifest V3 than for Manifest V2. For most projects, just do it like this


// Manifest V2
"manifest_version": 2

// Manifest V3
"manifest_version": 3

Migrate to a service worker

In Manifest V3, background pages are replaced by a service worker. The manifest changes are listed below.

  • Replace background.scripts with background.service_worker in the manifest.json. Note that the service_worker field takes a string, not an array of strings.
  • Remove background.persistent from the manifest.json.

// Manifest V2
{
  "background": {
    "scripts": [
      "backgroundContextMenus.js",
      "backgroundOauth.js"
    ],
    "persistent": false
  },
}

// Manifest V3
{
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  }
}

You will only need the type field if you use ES modules (using the import keyword). Its value will always be module.

Update your code

Replace Browser Actions and Page Actions with Actions

Browser actions and page actions were separate concepts in Manifest V2. Though they started with distinct roles, the differences between them decreased over time. In Manifest V3, these concepts are consolidated into the Action API. This requires changes in your manifest.json and extension code that is different from what you would have put in your Manifest V2 background script.

In the manifest.json replace the browser_action and page_action fields with the action field.


// Manifest V2
{
  "page_action": { ... },
  "browser_action": {
    "default_popup": "popup.html"
   }
}

// Manifest V3
{
  "action": {
    "default_popup": "popup.html"
  }
}

Where your Manifest V2 used the chrome.browserAction and chrome.pageAction APIs, you should now use the chrome.action API.


// Manifest V2
chrome.browserAction.onClicked.addListener(tab => { ... });
chrome.pageAction.onClicked.addListener(tab => { ... });

// Manifest V3
chrome.action.onClicked.addListener(tab => { ... });

Re-written code with service-worker

You'll need to make a few code adjustments to account for differences between the way background scripts and service workers function. To start with, the way a service worker is specified in the manifest file is different from how background scripts are specified. Additionally:

  • Because they can't access the DOM or the window interface, you'll need to move such calls to a different API or into an chrome.offscreen document.
  • Event listeners should not be registered in response to returned promises or inside event callbacks.
  • Since they're not backward compatible with XMLHttpRequest() you'll need to replace calls to this interface with calls to fetch().
  • Since they terminate when not in use, you'll need to persist application states rather than rely on global variables. Terminating service workers can also end timers before they have completed. You'll need to replace them with chrome.alarms.

Register Context Menus

Because of service-worker event lifecycle, the extension's chrome.runtime.onInstalled event, which is fired when the extension (not the service worker) is first installed, when the extension is updated to a new version, and when Chrome is updated to a new version. Use this event to set a state or for one-time initialization, such as chrome.contextMenus.


// service-worker.js
chrome.runtime.onInstalled.addListener((details) => {
  if(details.reason !== "install" && details.reason !== "update") return;
  chrome.contextMenus.create({
    "id": "sampleContextMenu",
    "title": "Sample Context Menu",
    "contexts": ["selection"]
  });
});

Browser startup and launch Extension

When a user profile starts, the chrome.runtime.onStartup event fires but no service worker events are invoked. You can add a callback to invoked this API, make your extension launch after browser startup.


// service-worker.js
chrome.runtime.onStartup.addListener(() => {
    // open your extension page here!
    openYourExtensionPageCodeHere()
})

Callback for Extension Launch

Extension service workers respond to both the standard service worker events and to events in extension namespaces. They are presented together because often one type follows another during an extension's use.

Your callback for extension launch will be run in service-worker IDLE work cycle.


// service-worker.js
const main() {
    // do init or any other things
}

// directly run here!
main()

The End

Unlike the words in the Chrome official document, It is not an easy thing to migrate from Manifest V2 to Manifest V3. The most importan thing, I think, is that you must read the ffff**k documents with any words.

If you have any questions about this topic, feel free to leave a message.