Introduction to Manifest V3

If you’re a web developer, you’re likely no stranger to the world of browser extensions. Google Chrome, in particular, has been a favorite among developers and users alike, thanks to its robust extension ecosystem. However, with the advent of Manifest V3, things have changed significantly. In this article, we’ll delve into the world of Manifest V3, exploring what it is, why it’s important, and most crucially, how to develop Chrome extensions using this new framework.

What is Manifest V3?

Manifest V3 is the latest iteration of the Chrome Extensions platform, designed to address issues related to security, performance, and user privacy. It introduces several key changes compared to its predecessor, Manifest V2.

  • Service Workers: One of the most significant changes is the replacement of background pages with service workers. Service workers run outside the main thread, reducing the impact on browser performance and memory usage.

  • Declarative Net Request: The new declarativeNetRequest API replaces the webRequest API, allowing extensions to block or modify network requests in a more efficient and secure manner. This approach shifts the processing of network requests from the extension to the browser engine, enhancing performance and privacy.

  • Enhanced Security: Manifest V3 improves security by disallowing remotely hosted code and the execution of arbitrary strings. It also enhances the content security policy to protect users from malicious scripts.

Migrating to Manifest V3

If you’re already familiar with Manifest V2, migrating to Manifest V3 involves several key steps.

Update the Manifest File

The first step is to update your manifest.json file to comply with the new version.

{
  "name": "My Extension",
  "version": "1.0",
  "manifest_version": 3,
  "description": "A brief description of my extension",
  "icons": {
    "16": "images/icon16.png",
    "48": "images/icon48.png",
    "128": "images/icon128.png"
  },
  "action": {
    "default_popup": "popup.html"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content-script.js"]
    }
  ],
  "web_accessible_resources": [
    {
      "resources": ["SIPml.js"],
      "matches": ["<all_urls>"]
    }
  ]
}

Migrate to Service Workers

Service workers replace the traditional background pages. Here’s an example of how you might set up a service worker in your background.js file:

// background.js
chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ key: 'value' });
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'doSomething') {
    // Perform some action
    sendResponse({ result: 'success' });
  }
});

Update API Calls

Several API calls have been updated or replaced in Manifest V3. For instance, the webRequest API is now replaced by the declarativeNetRequest API.

{
  "permissions": ["declarativeContent", "activeTab"],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules.json"
      }
    ]
  }
}

And here’s an example of a rules.json file:

[
  {
    "id": 1,
    "priority": 1,
    "action": { "type": "block" },
    "condition": { "urlFilter": "example.com", "resourceTypes": ["script"] }
  }
]

Including External Libraries

To include an external library like SIPml.js in your extension, you need to declare it as a web_accessible_resource in your manifest.json file.

{
  "web_accessible_resources": [
    {
      "resources": ["SIPml.js"],
      "matches": ["<all_urls>"]
    }
  ]
}

Then, you can include this library in your background.js file:

// background.js
importScripts('SIPml.js');

// Use the library as needed

Step-by-Step Guide to Creating a New Extension

Here’s a step-by-step guide to creating a new Chrome extension using Manifest V3.

Step 1: Create the Directory Structure

Create a directory for your extension and add the necessary files.

my-extension/
├── icons/
│   ├── icon16.png
│   ├── icon48.png
│   └── icon128.png
├── popup.html
├── popup.js
├── content-script.js
├── background.js
├── SIPml.js
├── rules.json
└── manifest.json

Step 2: Write the Manifest File

Create the manifest.json file with the necessary configurations.

{
  "name": "My Extension",
  "version": "1.0",
  "manifest_version": 3,
  "description": "A brief description of my extension",
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "action": {
    "default_popup": "popup.html"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content-script.js"]
    }
  ],
  "web_accessible_resources": [
    {
      "resources": ["SIPml.js"],
      "matches": ["<all_urls>"]
    }
  ],
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules.json"
      }
    ]
  }
}

Step 3: Implement the Service Worker

Write the background.js file to handle the service worker logic.

// background.js
chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ key: 'value' });
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'doSomething') {
    // Perform some action
    sendResponse({ result: 'success' });
  }
});

Step 4: Add Content Scripts and Popups

Create the content-script.js and popup.js files to handle interactions with web pages and the popup UI.

// content-script.js
chrome.runtime.sendMessage({ action: 'doSomething' }, (response) => {
  console.log(response.result);
});
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
  <title>My Extension</title>
  <script src="popup.js"></script>
</head>
<body>
  <h1>My Extension Popup</h1>
  <button id="myButton">Click Me</button>
</body>
</html>
// popup.js
document.getElementById('myButton').addEventListener('click', () => {
  chrome.runtime.sendMessage({ action: 'doSomething' }, (response) => {
    console.log(response.result);
  });
});

Flowchart for Migrating to Manifest V3

Here is a flowchart to help you visualize the migration process:

graph TD A("Start") --> B{Is Manifest V2?} B -->|Yes| C("Update Manifest to V3") B -->|No| D("Proceed with V3 Development") C --> E("Migrate to Service Workers") E --> F("Update API Calls") F --> G("Implement Declarative Net Request") G --> H("Test and Publish") D --> E H --> B("Done")

Conclusion

Developing Chrome extensions with Manifest V3 requires a bit of a learning curve, but the benefits in terms of security, performance, and user privacy are well worth the effort. By following the steps outlined above and understanding the new features and limitations of Manifest V3, you can create powerful and efficient extensions that enhance the browsing experience for users.

Remember, the key to successful migration is to take it one step at a time, ensuring each component of your extension is updated and tested thoroughly. Happy coding