Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update to chrome extension manifest version 2 -> 3 #8

Merged
merged 16 commits into from
May 26, 2024

Conversation

eric60
Copy link
Owner

@eric60 eric60 commented Mar 11, 2024

Changes

Testing

Problem

Issue: #7

For extensions publishers who still publish Manifest V2 extensions, we highly recommend completing migration to Manifest V3 before June 2024. We've published a migration guide covering everything you need to know to successfully migrate.Nov 16, 2023
https://developer.chrome.com/blog/resuming-the-transition-to-mv3#:~:text=For%20extensions%20publishers%20who%20still,to%20know%20to%20successfully%20migrate.

Notes

Search for Note in this PR

@eric60 eric60 changed the title chore: update to chrome extension manifest version 3 from 2 chore: update to chrome extension manifest version 2 -> 3 Mar 11, 2024
@eric60
Copy link
Owner Author

eric60 commented May 25, 2024

Note: https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
chrome.browserAction.setBadgeText({ text: badgeText });
chrome.browserAction.onClicked.addListener(handleActionClick);
});
This works with a persistent background page because the page is constantly running and never reinitialized. In Manifest V3, the service worker will be reinitialized when the event is dispatched. This means that when the event fires, the listeners will not be registered (since they are added asynchronously), and the event will be missed.

Instead, move the event listener registration to the top level of your script. This ensures that Chrome will be able to immediately find and invoke your action's click handler, even if your extension hasn't finished executing its startup logic.

@eric60
Copy link
Owner Author

eric60 commented May 25, 2024

Note: Error: service worker registration failed status code 15
https://groups.google.com/a/chromium.org/g/chromium-extensions/c/UoogwQudJZo

There are several problems.

chrome://extensions UI is misleading you by showing old errors without indicating they're old before you changed and fixed your background script. You'll have to account for this poor design and click the "Clear all" button every time you reload the extension.

The background script (the service worker) doesn't have document or window. This script is generally only necessary to process chrome events like chrome.tabs.onUpdated. In this case you don't need the background script at all, simply process DOM events in your visible page e.g. in the action popup.

ManifestV3 extensions can't use inline code in <script> element. You should use a separate popup.js file and load it as <script src="popup.js"></script>
The popup runs only when shown, so you'll just read the clipboard right away. The only way to do it inside the popup is by using the deprecated document.execCommand due to https://crbug.com/1337152.


Note: Using jQuery in service worker manifest V3
https://groups.google.com/a/chromium.org/g/chromium-extensions/c/jJ-9CqIY7mU

Correct. As you noted, document is not exposed in the service worker's global scope so that variable is undefined.

As I see it you have two basic options.

  1. Refactor your extension to remove the jQuery dependency.
  2. Continue using jQuery and shim the DOM APIs that it requires

Personally I'd lean towards removing the jQuery dependency, but depending on how heavily it's being used that may be a lot of work. If you go the shim route, try looking for resources that describe how to use jQuery inside non-document JavaScript contexts, like this blog post about using jQuery inside a WebWorker. Alternatively, you could try using a DOM library to shim the missing document object. I'd probably start by experimenting with linkedom, but note that that library doesn't come in a nicely packaged, single-file format.

Shim
In computer programming, a shim is a library that transparently intercepts API calls and changes the arguments passed, handles the operation itself or redirects the operation elsewhere. Shims can be used to support an old API in a newer environment, or a new API in an older environment.

===
The screenshot shows code that only makes sense for a visible page, so the fact you were using it inside the background page definitely looks like a mistake e.g. I've seen many people incorrectly loading their background script also in the popup [you should have had a SEPARATE popup.js].

  • If this code is for web scraping, then the jquery should be inside the content script.
  • If it's a part of your extension's UI, then the jquery should be inside the script for that page [popup.js] and NOT in the background script (service worker). You can use jQuery in both cases.

Removing the jQuery dependency might be too big a task.
From this conversation, i can see that we can use the jQuery inside the service worker using the offscreen document. However, I am not able to figure out how exactly i can do that, since i am new to this. Is there any example that i can refer to which can help me with this?

The offscreen document isn't visible so running jQuery there also doesn't make a lot of sense unless you want to use it to scrape a web site inside an iframe. As for an example see the folders with "offscreen" in https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note: Manifest V3 service worker registration failed
https://groups.google.com/a/chromium.org/g/chromium-extensions/c/lLb3EJzjw0o?pli=1

Even better, you can get the same result without changing your background script at all! To do this, create a wrapper script that imports your actual background script & surfaces the errors.

// manifest.json
{
"name": "Throw on Register!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background-worker.js"
}
}

// background-wrapper.js
try {
importScripts("background.js");
} catch (e) {
console.error(e);
}

// background.js
console.log("start");
throw new Error("lol");
console.log("end");

(also for the record I think the platform should just do this for you)

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

note: chrome extension how can service worker communicate with popup javascript
https://stackoverflow.com/questions/67362068/google-chrome-extension-messaging-service-worker-from-popup

You're sending a message to the tab but there's nothing that listens to it. You need a content script with onMessage listener. Note that there's no essential difference between MV2 and MV3 so you can learn MV2 and then read the migration article without paying any attention to the mostly irrelevant promotion of service workers as they're essentially the same as the non-persistent background scripts minus DOM and a few other features. See also this.

My comment above assumed you want to send a message directly to the content script because this is what
chrome.tabs.sendMessage does (you don't even need the background worker for this task). If you want to send to the background worker then use chrome.runtime.sendMessage, see message passing for more info.

@wOxxOm A step in the right direction! No more errors when I try and send a message from the popup, but no console logs are being reported? However I still have the issue with the "Service worker registration failed" warning? It seems strange that Google's example has that warning out of the box?!

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note: chrome.runtime API
Send data from a content script to the service worker
https://developer.chrome.com/docs/extensions/reference/api/runtime#example-content-msg

Its common for an extension's content scripts to need data managed by another part of the extension, like the service worker. Much like two browser windows opened to the same web page, these two contexts cannot directly access each other's values. Instead, the extension can use message passing to coordinate across these different contexts.

In this example, the content script needs some data from the extension's service worker to initialize its UI. To get this data, it passes the developer-defined get-user-data message to the service worker, and it responds with a copy of the user's information.

image

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note: You are trying to use chrome.tabs.create in a content script. This API is only available for background scripts. Instead, use window.open to create new tabs from within a content script.
https://stackoverflow.com/a/49192949/9882969

// Regular webpage; works
window.open("https://google.com");
// Privileged URL; is redirected to about:blank
window.open("chrome-extension://kgllckjehjabihppilipeagjojdmlfch/options.html");

For the options page, this does not work since it uses the chrome-extension protocol, which Firefox does not support using window.open.

This is the way I open my options page in a background script:

chrome.runtime.openOptionsPage();

If you need to call it in a content script, use messaging: https://developer.chrome.com/apps/messaging

Example:

background.js

chrome.runtime.onMessage.addListener(function(message) {
    switch (message.action) {
        case "openOptionsPage":
            openOptionsPage();
            break;
        default:
            break;
    }
});

function openOptionsPage(){
    chrome.runtime.openOptionsPage();
}

content_script.js
chrome.runtime.sendMessage({"action": "openOptionsPage"});

eric60 added 3 commits May 26, 2024 15:22
* added messaging in popup.js for service_worker to receive for chrome APIs that only service_worker can use
…ng value

* everything working for key setup, hardToDeactivate clicks
* did not test youtube blocking yet
@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note: other notes used

https://stackoverflow.com/questions/49192636/how-can-i-open-my-options-html-currently-i-get-cannot-read-property-create-of/49192949#49192949
Content scripts can't use chrome.tabs API. See documentation for chrome.runtime.openOptionsPage instead


@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note:

  • initial error from calling youtube data rest api
  • Solution: seemed to be intermittent one-time issue, did not occur again on subsequent tests
// 20240526154050
// https://www.googleapis.com/youtube/v3/videos?part=snippet&id=lRrOLTHu-ew&key=AIzaSyA5JFptzkrMDka_3W93nPCTtdFD-CRRJVQ&fields=items(snippet(categoryId

{
  "error": {
    "code": 400,
    "message": "Invalid FieldMask 'items(snippet(categoryId'. Cannot find matching ')' for all '('.",
    "errors": [
      {
        "message": "Invalid FieldMask 'items(snippet(categoryId'. Cannot find matching ')' for all '('.",
        "domain": "global",
        "reason": "invalidParameter",
        "location": "fields",
        "locationType": "parameter"
      }
    ],
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "items(snippet(categoryId",
            "description": "Error processing the 'fields' param value 'items(snippet(categoryId': Invalid FieldMask 'items(snippet(categoryId'. Cannot find matching ')' for all '('."
          }
        ]
      }
    ]
  }
}

https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}&key=${USER_API_KEY}&fields=items(snippet(categoryId))

bad
https://www.googleapis.com/youtube/v3/videos?part=snippet&id=lRrOLTHu-ew&key=AIzaSyA5JFptzkrMDka_3W93nPCTtdFD-CRRJVQ&fields=items(snippet(categoryId))

good
https://www.googleapis.com/youtube/v3/videos?part=snippet&id=lRrOLTHu-ew&key=AIzaSyA5JFptzkrMDka_3W93nPCTtdFD-CRRJVQ&fields=items(snippet(categoryId))

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

Note: Question: Can you send notifications through contentScript?
NO

https://stackoverflow.com/questions/3536621/desktop-notifications-from-content-scripts
You can't show notifications directly through a content script. But, you can show them through the background page.

@eric60
Copy link
Owner Author

eric60 commented May 26, 2024

YouTube Blocker Options Image 1

@eric60 eric60 merged commit 5e34537 into master May 26, 2024
@eric60 eric60 mentioned this pull request Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant