This question already has an answer here:
How do I import scripts into a service worker using Chrome extension manifest version 3?
(1 answer)
Closed 1 year ago.
In Google Chrome extensions before manifest v3 I could divide background.js into multiple scripts. And to load all scripts to be visible in background.js I only need to to put them in array in manifest like this:
"background": {
"scripts": ["helpers/countHelper.js", "helpers/networkHelper.js", "background/main.js"],
}
With this above sintax, all scripts will be merged into one file.
Now in documentation how to use manifest v3, they wrote:
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 string.
Cause background in manifest can't take multiple scripts, how to divide background script into multiple scripts.
Also import syntax is not allowed as I know.
With this above sintax, all scripts will be merged into one file.
It is not true, but let's fly over...
You can use importScript but not in manifest.
Look at this template:
/* V3 manifest.json */
"background": {
"service_worker": "worker_wrapper.js"
},
/* worker_wrapper.js */
try {
importScripts("helpers/countHelper.js", "helpers/networkHelper.js", "background/main.js");
} catch (e) {
console.log(e);
}
Bear in mind that SW file must be placed in root folder, whereas other scripts could be placed in other folders
Related
I've been attempting to write a very simple Chrome extension (manifest v3) to automatically close those annoying tabs zoom leaves open after you join a meeting.
So far I have been able to get most pages to automatically close with my extension but it simply refuses to run on certain domains, including the one I actually need it to run on: https://company-name-here.zoom.us/. I ultimately would like to set the content script matchers to just zoom but for now I have expanded it to all sites in an effort to reduce sources of error.
It is not working no matter how I attempt to load the page, be it by clicking the redirect url on a google calendar event, reloading the page manually after it has already been opened, and even manually typing out the url and hitting enter. The zoom home page suffers from the same problem but other sites such as stack overflow show the "Content script loaded" console log and close in 5 seconds as I would expect.
Please find the entire source for the extension below:
manifest.json
{
"manifest_version": 3,
"name": "Zoom Auto Closer",
"version": "1.0",
"background": {
"service_worker": "src/background.js"
},
"content_scripts": [{
"run_at": "document_start",
"matches": ["<all_urls>"],
"js": ["src/content.js"]
}]
}
src/content.js
const closeDelay = 5_000;
const closeCurrentTab = () => chrome.runtime.sendMessage('close-tab');
const main = () => {
console.log('Content script loaded');
setTimeout(closeCurrentTab, closeDelay);
};
main();
src/background.js
const closeTab = tabId => chrome.tabs.remove(tabId);
const onMessage = (message, sender) => {
console.log('Received a message:', message);
switch (message) {
case 'close-tab': return closeTab(sender.tab.id);
}
}
const main = () => {
console.log('Service worker registered');
chrome.runtime.onMessage.addListener(onMessage);
}
main();
The issue might be with the usage of <all_urls>.
Google says on the matching patterns docs:
The special pattern <all_urls> matches any URL that starts with a
permitted scheme.
And the permitted schemes are http:, https:, and file:.
I am not too familiar with Zoom, but this article suggests that zoom uses the protocol zoommtg: to launch the the desktop program, so this falls outside of what <all_urls> covers.
Edit:
Now I see that you stated that the urls start with https:// so that might invalidate what I suggested. Still might be worth trying "*://*.zoom.us/*" instead of <all_urls>.
You could try using "*://*.zoom.us/*" instead. If that doesn't work you could try ditching the content script and handling everything in the background service worker.
In the background service worker, you could add a listener for chrome.tabs.onUpdated and check the url value to see if it matches the url for a Zoom tab and close it from there. You would also need to use the Alarms API for the delay.
This method wouldn't be as efficient because it is called on every tab update (not really worth worrying about), but it is a possible workaround if you can't get the content script method to work.
This question already has an answer here:
RequireJS: Set path to 'ignore'
(1 answer)
Closed 5 years ago.
requirejs parses JS files as text and builds a tree of all the requires...
It then injects includes into the head of an HTML file.
In a particular context I need to ignore a particular file so e.g. if it sees this it won't be added to the HTML file:
const { mixinService } = require("devtools/shared/mixinService");
I need to know how to do this because in one context I need the file but in another it will break all of my components.
Let me describe the different contexts: I work at Mozilla on the Firefox browser. Scripts can run in a privileged JS environment, where they have access to special APIs or they can run in content (like a regular webpage).
The mixinService uses some of those privileged APIs so it is incompatible with content scripts so the contexts are privileged and content. We need to ignore the require when running in the content process.
Turns out that you can use define for this so in my case it looks like this:
define("devtools/shared/mixinService", {
mixinService: {
mixins: []
}
});
require.config({
baseUrl: "resource://devtools-client-jsonview/",
paths: {
"devtools/client/shared": "resource://devtools-client-shared",
"devtools/shared": "resource://devtools/shared",
"devtools/client/shared/vendor/react":
JSONView.debug
? "resource://devtools-client-shared/vendor/react-dev"
: "resource://devtools-client-shared/vendor/react"
}
});
// Load the main panel module
requirejs(["json-viewer"]);
Easy when you know how.
I'm writing a Chrome Extension in Javascript and I want to get the current time for the playing video on youtube.com. I tried using the answer from question Getting Current YouTube Video Time , e.g.:
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
However I do get following error: "Uncaught TypeError: Cannot read property 'getCurrentTime' of null";
What I am doing wrong? I tried different values for the ElementId - movie_player, player....
Any help is appreciated. Thanks in advance.
Cheers.
edit:
Here is my manifest:
{
"manifest_version": 2,
"name": "",
"description": "",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "basic.html"
},
"permissions": [
"tabs",
"activeTab", "http://*/*", "https://*/*"
]
}
Another thing is:
If I execute this code:
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
In the Javascript console on a Youtube Page it works fine and returns the current time.
If, however I execute this value from the extension or the console of the extension, the first line return value null.
So, as Ben assumed below, the issue seems to be that my extension doesn't even access the Youtube page.
Any help is appreciated, so thanks in advance.
Cheers
Use the following code works for chrome extension:
video = document.getElementsByClassName('video-stream')[0];
console.log(video);
console.log(video.currentTime);
In 2020, it seems we should use: player.playerInfo.currentTime.
full code on codepen
As Ben correctly assumed, you're executing the code in the context of your background page, which is wrong.
To interact with other pages, you need to inject a content script in them. See overview of that here. You'll probably need to learn how Messaging works so you can gather data in a content script and communicate it to the background page.
To make a minimal example, you can have a file inject.js
// WARNING: This example is out of date
// For the current HTML5 player, see other answers' code snippets
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
And in your background page script, you can inject that into the current page as follows (when the button is clicked, for instance)
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript({
file: 'inject.js'
});
});
Then, you'll see the result of the execution in the console of the currently open page. To report the result back, you'll need to use chrome.runtime.sendMessage
you can only use getElementById when you´r referencing to the correct page. You´r using the right id. if you´r trying to access the play form another page you can use the jquery .load() function
---------EDIT----------
in the sample they do it like so:
function getCurrentTime() {
var currentTime = player.getCurrentTime();
return roundNumber(currentTime, 3);
}
I've been tasked with creating a Google Chrome extension. So far, everything works fine. However, I would like to be able to use multiple background scripts (what I mean is
"background" : {"scripts" : ["background.js"]}, if what I'm talking about is unclear) rather than creating multiple extensions. Is this possible?
Regards,
According to the documentation:
A background page will be generated by the extension system that includes each of the files listed in the scripts property.
So yes, it should work. Simply declare multiple scripts:
...
"background": {
"scripts": [
"background.js",
"backgroundone.js",
"backgroundtwo.js"
]
},
...
All of these scripts would work as if loaded into the same page; they will all share the same context.
In manifest version3:
---------manifest.json
"background": {
"service_worker": "bg-wrapper.js"
}
---------bg-wrapper.js
try {
importScripts('background.js');
} catch (error) {
console.error(error);
}
I have a google chrome extension that shares some code between it's content script and background process / popup. If it some easy and straightforward way for this code to check if it's executed as content script or not? (message passing behavior differs).
I can include additional "marker" javascript in manifest or call some chrome fnction unavailable from content script and check for exceptions - but these methods looks awkward to be. Maybe it's some easy and clean way to make this check?
To check whether or not your script is running as a content script, check if it is not being executed on a chrome-extension scheme.
if (location.protocol == 'chrome-extension:') {
// Running in the extension's process
// Background-specific code (actually, it could also be a popup/options page)
} else {
// Content script code
}
If you further want to know if you're running in a background page, use chrome.extension.getBackgroundPage()=== window. If it's true, the code is running in the background. If not, you're running in the context of a popup / options page / ...
(If you want to detect if the code is running in the context of an extension, ie not in the context of a regular web page, check if chrome.extension exists.)
Explanation of revised answer
Previously, my answer suggested to check whether background-specific APIs such as chrome.tabs were defined. Since Chrome 27 / Opera 15, this approach comes with an unwanted side-effect: Even if you don't use the method, the following error is logged to the console (at most once per page load per API):
chrome.tabs is not available: You do not have permission to access this API. Ensure that the required permission or manifest property is included in your manifest.json.
This doesn't affect your code (!!chrome.tabs will still be false), but users (developers) may get annoyed, and uninstall your extension.
The function chrome.extension.getBackgroundPage is not defined at all in content scripts, so alone it can be used to detect whether the code is running in a content script:
if (chrome.extension.getBackgroundPage) {
// background page, options page, popup, etc
} else {
// content script
}
There are more robust ways to detect each context separately in a module I wrote
function runningScript() {
// This function will return the currently running script of a Chrome extension
if (location.protocol == 'chrome-extension:') {
if (location.pathname == "/_generated_background_page.html")
return "background";
else
return location.pathname; // Will return "/popup.html" if that is the name of your popup
}
else
return "content";
}