Further down the API checklist in the migration guide:
Are you currently using
chrome.tabs.executeScript({code: '...'})
,eval()
, ornew Function()
in background contexts or content scripts?
Of course not, because we had to quit doing that in Firefox ages ago to get listed on addons.mozilla.org. Getting an additional script to execute in the content window when requested via chrome.runtime.sendMessage
seems like a fine way to ease into background scripting, however, so let's do it. First, our baseline:
Here's our V2 manifest, which adds a background script and requests tab permission, so we can send messages and execute a content script:
{
"version": "0.0.104",
"name": "Baseline",
"description": "Manifest V2 Baseline",
"background": {
"scripts": ["js/background.js"]
},
"permissions": ["tabs", "*://*/*"],
"content_scripts": [
{
"js": ["js/content.js"],
"matches": ["*://*/*"]
}
],
"manifest_version": 2
}
Our content script writes a message to the console and asks the background for more:
console.log("Content script has loaded via Manifest V2.");
// send a message to the background requesting an additional script
chrome.runtime.sendMessage({
cmd: "runLogic"
});
Our background script listens for messages and responds to requests for our business logic:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log("Message received!");
console.log("request: ", request);
console.log("sender: ", sender);
if (request.cmd === "runLogic") {
chrome.tabs.executeScript(sender.tab.id, {
file: "js/logic.js"
});
}
});
Our business logic does nothing but let us know it's running:
console.log("A script has run from chrome.tabs.executeScript via Manifest V2.");
Drag ep_004/v2/
into chrome://extensions
. Note that we now have a background view to inspect; click to do so, and then switch to the console tab. Then open a fresh tab and load a page. In the background console you should see something like this:
Message received!
request: {cmd: "runLogic"}
sender: {id: "deadbeefdeadbeefdeadbeef", [other stuff here]}
Inspect the page you just opened. In the Console tab you should see something like this:
Content script has loaded via Manifest V3. content.js
A script has run from chrome.tabs.executeScript via Manifest V2. logic.js
Duplicating everything into /v3/
and changing the manifest version to 3 seems like the right first step but it will get you a gruesome pop-up error:
Failed to load extension
File ~/ep_004/v3/
Error The "background.scripts" key cannot be used with manifest_version 3. Use the "background.service_worker" key instead.
Could not load manifest.
Well, crap. Looks like we need to migrate to service workers sooner rather than later.
Changing our background
property in our manifest to service_worker
(being careful to make this a string and not an array!) looks like the right first thing to try:
{
"version": "0.0.104",
"name": "Test",
"description": "Manifest V3 Test",
"background": {
"service_worker": "js/background.js"
},
"permissions": ["tabs"],
"host_permissions": ["*://*/*"],
"content_scripts": [
{
"js": ["js/content.js"],
"matches": ["*://*/*"]
}
],
"manifest_version": 3
}
Everything else seems like it ought to be fine, right?
- When we load or reload the extension (by dragging
/ep_004/v3
intochrome://extensions
) we're not seeing an inspectable view under the extension. That's worrisome. - In the content tab we're seeing the message from
content.js
("Content script has loaded via Manifest V3") but nothing else. It feels like the background script isn't executing?
Per the docs:
Are you using background pages? Replace
background.page
orbackground.scripts
withbackground.service_worker
inmanifest.json
. Note that theservice_worker
field takes a string, not an array of strings.
Check.
Remove
background.persistent
frommanifest.json
.
Was never using this; check.
Update background scripts to adapt to the service worker execution context.
I feel like the docs ought to have a link here, or at least that How to Draw an Owl meme.
Purely by accident I had a Web inspector set to the Application tab on the V2 baseline background page when I dragged in the V3 test version, and saw a service worker install itself under Service Workers from Other Origins.
- Clicking the link to
background.js
gets me a new tab with the source of/js/background.js
inside. - I also see a little red X with the number 2 inside.
- Clicking the number -- which is linked and seems like it ought to be an error count -- does nothing.
- There are Update and Unregister links. Update does nothing; Unregister removes
background.js
from the list. - Clicking the reload button in chrome://extensions seems to register another copy of
background.js
to the service worker list. - Clicking the reload button multiple times registers more copies of
background.js
as service workers; unregistering each seems to remove them. - When unregistering and reloading I see a brief flash of "trying to install" with a tantalizing "inspect" link.
Found Service Workers: an Introduction
- It is not super clear to me whether I need to register my service worker or if the extension will do that for me? (Answer: no. The extension will do it for you.)
- When I open up
chrome://inspect/#service-workers
I can see my script. In console I notewindow
doesn't exist, so I suspectwindow.addEventListener('load')
isn't going to do anything. - Oh, wait:
chrome://inspect/#service-workers
does nothing if I don't first open upchrome://serviceworker-internals
and check the Open Devtools and Pause JavaScript checkbox first. - Workflow so far is:
- open chrome://serviceworker-internals and check the box
- open chrome://inspect/#service-workers
- reload the extension
devtools://devtools/bundled/worker_app.html
pops up withbackground.js
in the Console tab.serviceworker-internals
now shows my worker withNEW
installation status,STARTING
running status, and this in the Log box:Console: {"lineNumber":0,"message":"The path of the provided scope ('/') is not under the max scope allowed ('/js/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.","message_level":3,"sourceIdentifier":8,"sourceURL":""}
Begged for help on the Chrome developers' newsgroup, got a pointer to a service worker test that works on Manifest V2, tried it on Manifest V3, and it worked.
Stared at the error message and the example that worked until tiny drops of blood formed on my forehead and then finally got it: background.js
would not install as a service worker unless it was in the root of the extension.
- Background service workers will only load from the root of the extension.
- So
js/background.js
and/js/background.js
won't run, whilebackground.js
will.
- To get to an inspector, visit
chrome://serviceworker-internals
, reload your extension, look for your worker (should be on top) and click Inspect. - You'll also see console messages in the Log textarea. If you can't get your worker to start look here for clues.
- Your worker ought to be running right after you load your extension.
- If you've been away from the page a while and your worker isn't running, reload the page you're testing (or go interact with its context menus or other work you're doing in your extension) or click Start.
- I've asked for a direct link to the service worker console window from the extension card in
chrome://extensions
.
As long as we remember that service workers won't load from subdirectories? Seems good.