Manifest v3
has been available since the release of
Chrome 88
earlier this year. If you're planning on building a Chrome extension or if you're currently building one, you should learn about this new version of the Chrome Extensions Manifest in order to
benefit from the new features and vision.
In this post, we'll go through a
brief overview of Manifest v3
, then we'll take a look at the
Migration Checklist
to learn everything we'll need to change to migrate our sample extension. Finally, we'll
apply the changes step by step
so at the end, our sample extension will be successfully migrated to Manifest v3!
Privacy
: The idea here seems to be to let the user know about the extension's activities and how their information is used. And also reduce the need for extensions to have access to user data persistently.
Security
: Extensions will be required to follow stricter protocols, and, for example, they won't be allowed to access scripts from outside the extension context.
Performance
: Keep good performance in all devices and avoid performance issues when extensions are installed.
They also state that they will preserve the
"webbiness"
of Chrome extensions to keep the barriers for developers low and benefit from the advances of the web.
Finally, they say the idea is to keep the platform
capable
, powerful, and feature-rich so developers can keep delivering value to users through it.
Much like background pages, service workers are scripts that run in the background and are independent of web pages. They don't need interaction with the website or a user.
ℹ️ Fun fact! Service workers were inspired by the background pages in Chrome Extensions.
This new API is focused on privacy. The request will still be able to be modified and blocked, but in a privacy-preserving way.
This API is an improvement from the old
webRequest
API that fixes privacy, performance, and compatibility issues.
This change came to improve security. Since all the code will be available in the extension package, extensions will be more reliably and efficiently reviewed before they are made available for the users.
The alternative recommended for extensions that require some feature to be handled remotely is using
remote configuration files
.
We can finally use promises in some of
chrome
APIs! 🎈 This was something I was really looking forward to.
Callbacks are still supported, so you don't need to refactor all your code right away.
The
browserAction
API and
pageAction
API are now unified in a single API called
action
.
The
Web-accessible resources
are no longer available to all websites, which allowed extensions to use fingerprinting to track users.
The method
executeScript()
was moved from the
tabs
API into a new
scripting
API and no longer allows string scripts. You must provide a script file path or a function.
Host permissions are specified separately from the
permissions
property in the
manifest.json
.
The
content_security_policy
used to be a string, now it's an object, and you must specify the extension pages (HTML files and service workers) covered by the policy.
When migrating our extension to manifest v3, the first thing we should do is check the
Manifest V3 migration checklist
. I'll mark each bullet with ✅ when the change applies to our extension or ❌ when it doesn't:
❌ Do you have host permissions in your manifest?
✅ Are you using background pages?
Replace background.page or background.scripts with background.service_worker in manifest.json. Note that the service_worker field takes a string, not an array of strings.
Remove
background.persistent
from
manifest.json
.
Update background scripts to adapt to the service worker execution context.
✅ Are you using the browser_action or page_action property in manifest.json?
Since these two APIs were unified into a single action API, we must replace these properties with action.
✅ Are you using chrome.browserAction or chrome.pageAction JavaScript API?
Migrate to the chrome.action API.
❌ Are you currently using the blocking version of chrome.webRequest?
❌ Are you using these scripting/CSS methods in chrome.tabs API?
❌ Are you executing remote code or arbitrary strings?
❌ Are you executing functions that expect an MV2 background context?
❌ Are you making CORS requests in content scripts?
❌ Are you using a custom content_security_policy in manifest.json?
Service workers are
terminated when inactive
and
restarted when they're needed
again.
Service workers
don't have access to the DOM
.
This won't be a problem for us since when I created our background script, I already knew this change was coming, and so I made sure to keep those 2 things in mind in the original design of my background script.
The first change we need to do is rename the
background.js
script to
service-worker.js
.
Now we'll set our new service worker in the
manifest.json
file. To do that, we must replace the old
background
property with the following:
Now, notice that the service_worker property is a string. So we can't declare more than one file there (as far as I know, I didn't find much about this issue in the docs). Because of this change, I couldn't add the other two scripts I needed: acho.js and page.service.js. So I found a new way to include them and call them from service-worker.js: Simply use the importScripts() method at the top of the service-worker.js script:
// service-worker.jsimportScripts('acho.js','page.service.js');/* More code */Enter fullscreen modeExit fullscreen mode
Since these two APIs were unified into a single action API, we must change the property browser_action to action in our manifest.json file: "action":{"default_popup":"popup.html","default_icon":{"16":"images/icon16.png","24":"images/icon24.png","32":"images/icon32.png"Enter fullscreen modeExit fullscreen mode
Similarly to the previous section, we must use the new unified action API.
In our sample extension, we had only used the browserAction API to set the badge color and text, so we'll replace those lines:
// acho.jsclassAcho{/* More code */growl=()=>{chrome.action.setBadgeBackgroundColor({color:'#F00'},()=>{chrome.action.setBadgeText({text:'grr'});quiet=()=>{chrome.action.setBadgeText({text:''});/* More code */Enter fullscreen modeExit fullscreen mode
Note: The text property is now required in the setBadge method, so we can no longer use chrome.action.setBadgeText({ }); to clear the badge text.
2.2.5. Specify an URL pattern for Web-accessible resources
This one wasn't in the Checklist, but I realized I needed to make a change because when I tried the extension, I got an error that said: "Invalid value for 'web_accessible_resources[0]'. Entry must be a dictionary value".
So, I figure out we must explicitly define which pages will have access to our resources. This is done via the matches property (similarly to content scripts). Here's how the new web_accessible_resources property looks like in the manifest.json: "web_accessible_resources":["matches":["<all_urls>"],"resources":["images/icon32.png"]Enter fullscreen modeExit fullscreen mode
This one wasn't in the Checklist either, and I also couldn't find anything related to this change in the docs, but I figure out the change through my own intuition 😂.
We used to have a command defined in our manifest.json called _execute_browser_action that automatically (without adding any extra code) will trigger our extension's popup (browser action).
After updating to Manifest v3, this command wasn't working, and I figured it was because of the merge between browserAction and pageAction into the new action API. So I changed _execute_browser_action to _execute_action, and it worked 🎉. "commands":{"_execute_action":{"suggested_key":{"default":"Alt+Shift+1"Enter fullscreen modeExit fullscreen mode
Finally, after everything else was working, I decided to refactor my code to use promises in the APIs that support them.
Here are some examples:
// Using callback:chrome.action.setBadgeBackgroundColor({color:'#F00'},()=>{chrome.action.setBadgeText({text:'grr'});// Using promises:awaitchrome.action.setBadgeBackgroundColor({color:'#F00'});awaitchrome.action.setBadgeText({text:'grr'});Enter fullscreen modeExit fullscreen mode
// Optional callback:chrome.tabs.create({url:ev.srcElement.href,active:false});// Using promises:awaitchrome.tabs.create({url:ev.target.href,active:false});Enter fullscreen modeExit fullscreen mode
Remember: You don't need to refactor your code to use promises right away. Callbacks are still supported in Manifest v3.
One thing to notice is that I couldn't make promises to work with the chrome.storage API. This may be one of the APIs that don't support promises yet, but I couldn't find more information on the subject in the docs.
Our sample extension was successfully migrated to Manifest v3.
thank you for your article.
When I inject a css file, that contains a rule to an asset : image or font (located in my extension archive), it is not intercepted and the server of the content page is called.
Any idea how to fix this ? I have listed my resource in web_accessible_ressources...
thank you for your replies
Built on Forem — the open source software that powers DEV and other inclusive communities.