I'm trying to port a Chrome Extension to a Firefox add-on using the WebExtensions API. I am using RequireJS to load JavaScript files.
The code below is working fine in my Chrome extension, but not in Firefox.
Anyone have any advice on this? Thanks.
manifest.json:
{
"name": "Firefox WebExtension",
"version": "0.0.5",
"manifest_version": 2,
"description": "First Firefox WebExtensions",
"icons": {
"16": "img/c-ext3.png",
"48": "img/c-ext3.png",
"128": "img/c-ext3.png"
},
"background": {
"scripts": [
"js/vendor/require.js", "js/config/loader.js", "js/config/requireInit.js"
]
},
"applications": {
"gecko": {
"id": "abc#mozilla.org",
"strict_min_version": "44.0",
"strict_max_version": "50.*"
}
},
"browser_action": {
"default_icon": "img/c-ext3.png",
"default_title": "Firefox WebExtension",
"default_popup": "src/browser_action/browser_action.html"
},
"permissions": [
"contextMenus",
"cookies",
"http://*/*", "https://*/*", "file://*/*",
"notifications",
"tabs",
"<all_urls>"
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"content_scripts": [{
"matches": ["http://*/*", "https://*/*"],
"js": ["js/vendor/require.js", "js/config/loader.js", "js/config/requireInit.js"]
}],
"web_accessible_resources": [
"js/*", "src/*", "css/*", "img/*"
]}
loader.js
require.load = function(context, moduleName, url) {
var xhr = new XMLHttpRequest(),
evalResponseText = function(xhr) {
eval(xhr.responseText);
context.completeLoad(moduleName);
};
xhr.open("GET", url, true);
xhr.onreadystatechange = function(e) {
if (xhr.readyState === 4 && xhr.status === 200) {
evalResponseText.call(window, xhr);
}
};
xhr.send(null);
};
requireInit.js:
var baseUrl=browser.extension.getURL("/");
requirejs.config({
config: {
text: {
useXhr: function (url, protocol, hostname, port) {
// allow cross-domain requests
// remote server allows CORS
return true;
}
}
},
skipDataMain: true,
baseUrl: baseUrl,
paths: {
"jquery": "js/vendor/jquery",
"underscore": "js/vendor/lodash",
"backbone": "js/vendor/backbone",
"marionette": "js/vendor/marionette",
"app": "js/app"
}
});
console.log("before loading files");//working
require(['jquery', 'app/csApp'], function ($, app) {
console.log("all js loaded");//not working
});
csApp.js
console.log("inside cs app");//working
define(function(require) {
'use strict';
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
Marionette = require('marionette'),
csApp = new Marionette.Application();
console.log("csApp");//not working
return csApp;
});
Edit: console.log() inside jQuery works. But, console.log() inside csApp.js is not working.
I found a source of the problem.
It's Lodash.
I was using lodash.js instead of underscore.js.
"underscore": "js/vendor/lodash",
Lodash is compatible for Firefox 45-46 and I am using latest firefox i.e. 47.0 . So i have replaced lodash with underscore and now my web extension is working fine.
Related
I am trying to convert from MV2 to MV3 and I am getting this error from the service worker error logs:
Service worker registration failed
Uncaught ReferenceError: Worker is not defined
Here is my MV3 settings:
`{
"manifest_version": 3,
"name": "Blah",
"description": "Blah",
"version": "1.0.0",
"minimum_chrome_version": "93",
"action": {
"default_icon": "logo.png",
"default_popup": "popup.html"
},
"background": {
"service_worker": "js/background.js"
},
"content_scripts": [
{
"matches": ["file://*/*", "http://*/*", "https://*/*"],
"js": ["js/content.js"],
"run_at": "document_start",
"all_frames": true
}
],
"icons": {
"16": "icon-16.png",
"48": "icon-48.png",
"128": "icon-128.png"
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; worker-src 'self'"
},
"permissions": [
"scripting",
"clipboardWrite",
"tabs",
"activeTab",
"notifications",
"webRequest",
"proxy",
"storage",
"unlimitedStorage",
"alarms"
],
"host_permissions": [
"http://*/",
"https://*/",
"<all_urls>"
],
"web_accessible_resources": [
{
"resources": ["js/injected.js"],
"matches": ["*://*/*"]
}
]
}`
And here is the backgound script:
import { browser } from "webextension-polyfill-ts";
import { Request } from "#src/types";
import Extension from "./extension";
const app: Extension = new Extension();
try {
app.initialize().then(async () => {
// eslint-disable-next-line #typescript-eslint/no-unused-vars
browser.runtime.onMessage.addListener(async (request: Request, _) => {
try {
const res = await app.handle(request);
return [null, res];
} catch (e: any) {
return [e.message, null];
}
});
} catch (error) {
console.log("Error in backgound!!1");
}
Is there any missing configs in the background script or the MV3 json file?
It is an old bug when using nested web-worker with chrome extensions which is not supported yet: https://bugs.chromium.org/p/chromium/issues/detail?id=31666
I found the solution here: https://stackoverflow.com/a/33991381/9058556
It was simply installing https://github.com/dmihal/Subworkers package and importing it in my background.js script at the top.
Thanks #norio-yamamoto for trying to help me with this.
I'm trying to load an HTML file from the file system of my Chrome extension. I've added "modal.html" as a web accessible resource in my manifest:
{
"name": "Test Extension",
"action": {},
"manifest_version": 3,
"version": "0.1",
"description": "Just learning for now",
"permissions": [
"activeTab",
"scripting",
],
"background": {
"service_worker": "background.js"
},
"web_accessible_resources": [
{
"resources": [ "modal.html" ],
"matches": [ "https://mypage.co.uk/*" ]
}
]
}
My background.js file tries to load modal.html with an xhr:
function initPage() {
let node = document.createElement("div");
node.setAttribute("id", "mySpecialId");
document.body.appendChild(node);
var xhr = new XMLHttpRequest();
xhr.open("GET", chrome.runtime.getURL('modal.html'), true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
document.getElementById("mySpecialId").innerText = xhr.responseText;
}
}
xhr.send();
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: initPage
});
});
I get the error:
Denying load of chrome-extension://lmdjgmkmficfccbahcpgnmaplajdljid/modal.html. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
I'm sure this is a really basic problem, but I just can't figure it out.
I got this working by adding the use_dynamic_url key in the web_accessible_resources declaration:
"web_accessible_resources": [
{
"resources": [ "modal.html" ],
"matches": [ "https://www.mypage.co.uk/*" ],
"use_dynamic_url": true
}
]
I don't yet understand why this worked though!
Edit: This was a bug in Chrome. The original code was correct and worked after a reboot.
this is a bit of my code that I have currently
Manifest
{
"name": "hidden",
"manifest_version": 2,
"content_security_policy": "script-src 'self'; object-src 'self'",
"permissions": [
"activeTab",
"storage"
],
"version": "hidden",
"icons": {hidden},
"description": "hidden",
"browser_action": {hidden},
"content_scripts": [
{
"matches": [hidden],
"run_at": "document_start",
"js": [ "injected.js", "content.js"]
}
],
"web_accessible_resources": ["injected.js"],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
Injected.js
if (new RegExp(allowedUrls.join("|")).test(this._url))
{
console.log('test') <- I can see this message in console
chrome.runtime.sendMessage({interception: true});
}
Background.js
console.log("Atleast reached background.js") <- I can see that
chrome.runtime.onMessage.addListener(function (message, sender) {
console.log('inside listener') <- I cannot see that which means it doesn't get fired on message sent
if (message.interception) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {interception: true});
});
}
});
Can someone help me and tell me why it isn't working? My goal is to intercept XHR request in one file (injected.js), then receive that message on background.js and send that to another content.js file and do some stuff base on the response.
I have a piece of code which works fine on chrome. I did the following step mentioned here.
I'm able to load it properly, but the code doesn't run properly.
In the background console only the url gets printed, no other consoles or alerts work.
Please any help will be appreciated ! Please
window.onload = function() {
console.log("blah1");
var port = browser.runtime.connect({name: "knockknock"});
port.postMessage({request: "sendData"});
port.onMessage.addListener(function(msg) {
console.log("blah2");
if(msg != null){
}
});
}
var sendData = null;
var url = null;
browser.webRequest.onBeforeRequest.addListener(function(details) {
if(details != null && sendData == null && details.url.includes("www")){
console.log(details.url);
sendData = details.url;
}
},
{urls: ["<all_urls>"]},
["blocking", "requestBody"]
);
browser.runtime.onConnect.addListener(function(port) {
console.log("inside addListener")
port.onMessage.addListener(function(msg) {
if (msg.request == "sendData"){
console.log("sendData : ", sendData);
port.postMessage(sendData);
}else if (msg.answer == null){
sendData = null;
}
});
});
My manifest file
{
"manifest_version": 2,
"name": "test",
"version": "1.0.0",
"author": "medha",
"icons": {
"48": "esso.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js"]
},
"permissions": [ "webRequest", "webRequestBlocking", "webNavigation", "tabs", "<all_urls>", "storage"],
"-ms-preload": {
"backgroundScript": "backgroundScriptsAPIBridge.js",
"contentScript": "contentScriptsAPIBridge.js"
}
}
I tested and found that if we remove window.onload then the extension will work well in Edge Legacy. It will print all the consoles.
You could set content.script run at document_idle. It's equal to window.onload and you do not need to listen for the window.onload event. For more detailed information, you could refer to this article.
My manifest.json is like below:
{
"manifest_version": 2,
"name": "test",
"version": "1.0.0",
"author": "medha",
"icons": {
"48": "esso.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"run_at": "document_idle",
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"permissions": [ "webRequest", "webRequestBlocking", "webNavigation", "tabs", "<all_urls>", "storage"],
"-ms-preload": {
"backgroundScript": "backgroundScriptsAPIBridge.js",
"contentScript": "contentScriptsAPIBridge.js"
}
}
I'm trying to create a chrome extension to learn front-end technologies, and got stuck on message passing between popup and content script.
The following is what I'm trying to do:
1. Let background page hold a global var.
2. When user clicking a button on the popup html, the global var is modified. Meanwhile, the popup sends the global var to the content scripts for all of the tabs.
In the background.js I have:
var settings = {
version: 1,
enabled: false
};
popup.js:
$(document).ready(function(){
$("#switcher").click(function( event ) {
event.preventDefault();
var bg = chrome.extension.getBackgroundPage();
var settings = bg.settings;
settings.enabled = !settings.enabled;
// send message to the content for all the tabs
chrome.tabs.query({active: true}, function (tabs) {
for (var i = 0; i < tabs.length; ++i) {
console.log("sending message to tab " + i);
chrome.runtime.sendMessage(tabs[i].id, {enabled: settings.enabled}, function(response) {
console.log(response);
});
}
});
});
});
Finally, the content.js:
$(document).ready(function(){
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
console.log("request is: " + request.enabled);
sendResponse("get it");
}
);
});
I tried to debug it, but I found the 'sendMessage' function never got returned back.. and the 'onMessage' never got triggered. Did I miss something?
My manifest file:
{
"name": "__MSG_appName__",
"version": "0.0.1",
"manifest_version": 2,
"description": "__MSG_appDescription__",
"icons": {
"16": "images/icon-16.png",
"128": "images/icon-128.png"
},
"default_locale": "en",
"permissions": [
"contextMenus", "storage", "tabs"
],
"background": {
"scripts": [
"scripts/background.js"
],
"persistent": true
},
"browser_action": {
"default_icon": {
"19": "images/icon-19.png",
"38": "images/icon-38.png"
},
"default_popup": "popup.html"
},
"content_scripts": [
{
"run_at":"document_start",
"all_frames":true,
"matches": ["*://*/*"],
"js": ["bower_components/jquery/dist/jquery.min.js", "scripts/content.js"]
}
],
"web_accessible_resources": ["bower_components/jquery/dist/jquery.min.map"]
}
You should be using chrome.tabs.sendMessage instead of chrome.runtime.sendMessage to send messages to content scripts in tabs.