Reputation: 2460
I am trying to migrate my chrome extension from manifest version 2 to 3. Now that background scripts are replaced by service workers in manifest v3, I can no longer use a html file and refer js
files in script tags.
Is there any way I can import my individual script files into the service_worker.js
file?
I search almost everything on internet and couldn't find any solution. Even the official docs here Register background scripts were not so helpful. Any help would be appreciated.
Upvotes: 86
Views: 46170
Reputation: 73506
First off, important warnings:
⚠️ Chrome can't register the service worker that throws an error when installing or reloading the extension, so wrap the code in try/catch
.
⚠️ Chrome 92 or older requires the worker file to be in the root path (bug).
⚠️ Don't import jQuery and other XMLHttpRequest-based libraries because there's no DOM in a service worker. Do it in the offscreen document or use fetch()
directly or find/write a library that's based on fetch
and doesn't use window
or document
.
Use a bundler like webpack.
Enabled by adding "type": "module"
to the declaration of background
in manifest.json.
./foo.js
, /foo/bar.mjs
import
statement can be used.import()
is not yet implemented (crbug/1198822).manifest.json:
"background": { "service_worker": "bg.js", "type": "module" },
"minimum_chrome_version": "92",
bg.js:
// files must start with a path and end with an extension!
import {foo} from '/path/file.js';
import './file2.js';
try {
chrome.runtime.onMessage.addListener(...........);
doSomething();
// .................
} catch (err) { console.error(err); }
Each imported module should also use try/catch inside. If it still doesn't help catch the error, restart chrome with --enable-logging=stderr --v=1 2>log.txt
command line and look in log.txt for messages with the id of your extension.
This built-in function synchronously fetches and runs the scripts so their global variables and functions become available immediately. It's much slower than the static import
in Chrome, which becomes noticeable when importing a lot of scripts.
manifest.json:
"background": { "service_worker": "bg-loader.js" },
bg-loader.js is just a try/catch wrapper for the actual code in separate files:
try {
importScripts('/path/file.js', '/path2/file2.js' /*, and so on */);
} catch (e) {
console.error(e);
}
If some file throws an error, no subsequent files will be imported. If you want to ignore such errors and continue importing, import this file separately in its own try-catch block.
Don't forget to specify a file extension, typically .js
or .mjs
.
importScripts
inside a listenerPer the specification, we must use a service worker's install
event and import all the scripts that we want to be able to import in an asynchronous event later (technically speaking, anything outside of the initial task of the JS event loop). This handler is called only when the extension is installed or updated or an unpacked extension is reloaded (because it's equal to an update).
It's this convoluted in MV3 because service workers were designed for the Web, where remote scripts may be unavailable offline. Hopefully, it'll be simplified in crbug/1198822.
See also: webpack-target-webextension plugin for WebPack.
const importedScripts = [];
function tryImport(...fileNames) {
try {
const toRun = new Set(fileNames.filter(f => !importedScripts.includes(f)));
if (toRun.size) {
importedScripts.push(...toRun);
importScripts(...toRun);
}
return true;
} catch (e) {
console.error(e);
}
}
self.oninstall = () => {
// The imported script shouldn't do anything, but only declare a global function
// (someComplexScriptAsyncHandler) or use an analog of require() to register a module
tryImport('/js/some-complex-script.js');
};
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'somethingComplex') {
if (tryImport('/js/some-complex-script.js')) {
// calling a global function from some-complex-script.js
someComplexScriptAsyncHandler(msg, sender, sendResponse);
return true;
}
}
});
Upvotes: 113
Reputation: 117
chrome-extension-cli
package solves this problem by installing and preconfiguring webpack. This allows you to import packages or modules easily
Get Started Immediately
You don’t need to install or configure Webpack.
Webpack comes in preconfigured, so that you can focus on the code.Just create a project, and you’re good to go.
Read More: https://github.com/dutiyesh/chrome-extension-cli
Upvotes: 1