new Worker(new URL("./worker.js", import.meta.url)) through the bundler default for a web target. The call emits a separate worker chunk at the root of dist/<browser>/, and the compiled call points at that chunk through chrome.runtime.getURL(). That part works.
The browser is what refuses. A worker script has to come from the same origin as the document that creates it. The document behind a content script is the host page, so both forms below fail.
What a content script actually gets
This content script compiles cleanly and fails at runtime:https://example.com, Chromium reports:
web_accessible_resources does not lift the restriction. It controls whether the page may load the file, not whether the file may become a worker for a foreign origin.
This was measured on Chromium with a content script on a public page. Firefox
and Safari were not measured, so treat the errors above as Chromium behavior.
Run the worker from a page that the extension owns
A popup, an options page, a side panel, and an offscreen document all load from thechrome-extension:// origin. A worker created there is same-origin, so both forms work with no extra setup:
The blob workaround, and its two conditions
When the work has to stay in the page, fetch the worker source and construct the worker from a blob URL. A blob inherits the page origin, so the browser accepts it:extension build does not add the worker chunk to web_accessible_resources, so declare the file yourself in manifest.json:
fetch fails with TypeError: Failed to fetch, and the request shows as chrome-extension://invalid/.
The host page CSP has to allow blob workers. A page that sends worker-src 'self' blocks the blob, and the failure is quiet. The constructor returns normally, then the worker fails through onerror with an empty message:
try/catch around new Worker never sees it. Attach an onerror handler and treat it as the real failure signal.
Choosing between the three
- An extension page needs no setup, and both forms work there.
- A content script with a blob needs a manifest entry and a permissive page CSP.
- A content script with an extension URL is refused, and nothing changes that.
What the build warns about
From 4.1.21, the build scans every content script and injected script for a worker that starts from an extension URL. Anew Worker(new URL("./worker.js", import.meta.url)) in either surface prints this warning, and the build goes on:
in an injected script in the first line. The one-line recipe in the warning is the blob workaround above, and it keeps the same two conditions: the worker file must be web accessible, and the host page CSP must allow blob workers. Prefer the extension page route when the work does not have to stay in the page.
Next steps
- Read Offscreen documents for background work without a visible page.
- Read Web accessible resources for the manifest entry.
- Read Content scripts for what else the page origin limits.

