Chrome Extension Manifest V3 Libraries in Background
Asked Answered
M

2

8

I'm in the process of updating my chrome extension from manifest v2 to v3. Here's the old manifest:

Manifest V2:

{
"manifest_version": 2,
"name": "Legacy Search Assistant",
"version": "0.1.1",
"content_scripts": [
    {
        "matches": [
            "https://*.legacysite.io/*","*://*/api*"
        ],
        "js": ["jquery-3.6.0.min.js","content.js"]
    }
],
"options_page": "options.html",
"background": {
    "scripts": ["jsencrypt.min.js", "jquery-3.6.0.min.js", "background.js"]
},
"browser_action": {
    "default_icon":  "icon.png",
    "default_popup": "popup.html",
    "default_title": "Legacy Search"
},
"permissions": [
    "storage"
]
}

Since jsencrypt.min.js was already loaded in the manifest I was able to call it's functions in background.js, but now that I've gone to manifest v3 I am having problems getting the service worker to access this library.

For example, when I make this call in background.js:

importScripts("/scripts/jsencrypt.min.js");

It throws the following error:

Error handling response: Error: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'chrome-extension://<extension ID>/scripts/jsencrypt.min.js' failed to load.

If I click the link in the error it takes me directly to the library I want loaded.

I've already tried all of the fixes in this answer. Please help if you can.

Motile answered 14/1, 2022 at 19:59 Comment(3)
jsencrypt uses window which is absent in service worker so you should set it e.g. self.window = self before importing the script. If it doesn't help you should debug what happens: remove importScripts, reload the extension, open devtools for the background script, make a new snippet in Sources panel and paste the code of that library, save and run it.Waterhouse
@wOxxOm If I have a listener event waiting for a message from the content script, would I need to call self.window = self prior to importScripts(jsencrypt.min.js);? This didn't work but maybe I'm doing it all wrong.Motile
you could think to give a chance to "web crypto" api and its methods. It works in web\service worker. See here: developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encryptCategorize
M
0

The solution I ended up using was to move all usage of jsencrypt to the content.js. This allowed the module to function correctly and will not expose the public key in the environment we use our chrome extension in.

After creation and initializing of the jsencrypt object I pass it to the background script via a message.

Motile answered 7/9, 2022 at 21:42 Comment(0)
R
8

importScripts() is old way to load scripts in workers.

Now we can use more modern, ES modules instead.

Starting from Chrome 91, we can use JavaScript modules in service workers.

Just set type property to module in the manifest.

{
"manifest_version": 3,
"background": {
  "service_worker": "background.js",
  "type": "module"
}

This loads the service worker as an ES module, which lets you use the import keyword in the service worker to import other modules. Ex-

// background.js
import * as module from './scripts/jsencrypt.min.js';

But make sure that the script you are importing like ./scripts/jsencrypt.min.js in this case, has exported the required code that you want to use.

Learn about ES modules

Reginaldreginauld answered 26/1, 2022 at 16:54 Comment(3)
Would I place this at the top of the background.js or within the listener? I understand the service worker going to sleep can cause issues.Motile
Yes, you should use import at the top of the script (in the global scope). So, you can access the modules from everywhere (every scope) in the service worker (background.js).Reginaldreginauld
If I wanted to initialize an object from the module would I do something like this to initialize it for use ???: let RSAEncrypt = new module.JSEncrypt();Motile
M
0

The solution I ended up using was to move all usage of jsencrypt to the content.js. This allowed the module to function correctly and will not expose the public key in the environment we use our chrome extension in.

After creation and initializing of the jsencrypt object I pass it to the background script via a message.

Motile answered 7/9, 2022 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.