wxt-dev / wxt-dev/wxt

MV3 dev dynamic content script registration drops matchOriginAsFallback

Open Beginner friendly
#2,335 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

contribution welcome good first issue
Dominant language
TypeScript
Stars
10.5k
Forks
564
PR merge metrics
No merged PRs in 30d

Description

Describe the bug

In MV3 development mode, WXT dynamically registers content scripts from the background service worker instead of putting them in manifest.content_scripts.

When a content script is defined with matchOriginAsFallback: true, the production manifest preserves the option as match_origin_as_fallback: true, but the dev-mode dynamic registration drops it. As a result, dev mode behaves differently from production for about:blank / about:srcdoc iframes that depend on origin fallback.

Reproduction

Define a content script like this:

export default defineContentScript({
  matches: ["*://*/*", "file:///*"],
  allFrames: true,
  matchAboutBlank: true,
  matchOriginAsFallback: true,
  async main() {
    // ...
  },
})

Run WXT in MV3 dev mode:

wxt -b edge

Then inspect the registered content scripts from the extension service worker:

await chrome.scripting.getRegisteredContentScripts()
Actual behavior

The dynamically registered content script has matchOriginAsFallback: false:

{
  "id": "wxt:content-scripts/node-trigger.js",
  "js": ["content-scripts/node-trigger.js"],
  "matches": ["*://*/*", "file:///*"],
  "allFrames": true,
  "matchOriginAsFallback": false,
  "runAt": "document_idle",
  "world": "ISOLATED"
}

This prevents the content script from running in a TinyMCE editor iframe whose document is about:srcdoc, even though that same script works in production.

Expected behavior

The dev-mode dynamic registration should preserve matchOriginAsFallback: true:

{
  "id": "wxt:content-scripts/node-trigger.js",
  "js": ["content-scripts/node-trigger.js"],
  "matches": ["*://*/*", "file:///*"],
  "allFrames": true,
  "matchOriginAsFallback": true,
  "runAt": "document_idle",
  "world": "ISOLATED"
}

Production build already emits the expected static manifest fields:

{
  "matches": ["*://*/*", "file:///*"],
  "all_frames": true,
  "match_about_blank": true,
  "js": ["content-scripts/node-trigger.js"],
  "match_origin_as_fallback": true
}
Likely cause

In mapWxtOptionsToContentScript, WXT maps:

match_origin_as_fallback: options.matchOriginAsFallback

But mapWxtOptionsToRegisteredContentScript does not map the equivalent dynamic registration field:

function mapWxtOptionsToRegisteredContentScript(options, js, css) {
  return {
    allFrames: options.allFrames,
    excludeMatches: options.excludeMatches,
    matches: options.matches,
    runAt: options.runAt,
    js,
    css,
    world: options.world
  };
}

Adding matchOriginAsFallback: options.matchOriginAsFallback to the dynamic registration payload fixes the dev-mode behavior in my testing.

Notes

In my Edge MV3 dev testing, chrome.scripting.registerContentScripts accepted matchOriginAsFallback, and that was enough for the about:srcdoc iframe case. Passing matchAboutBlank to dynamic registration appeared to make registration fail, so this report is specifically about preserving matchOriginAsFallback for dev-mode dynamic content script registration.

Environment
  • WXT: 0.20.25
  • Browser target: edge-mv3
  • Mode: development (wxt -b edge)
    *** End Patch

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Locate mapWxtOptionsToRegisteredContentScript and compare its fields with mapWxtOptionsToContentScript. Preserve matchOriginAsFallback in the dynamic registration payload, then verify that MV3 development registration retains true for the provided content-script configuration and does not regress production behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
build-system, tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.