Skip to content

Conversation

ion1
Copy link

@ion1 ion1 commented Aug 3, 2025

Note

The patch series in which each PR builds on top of the previous one: #1761, #1762, #1763, #1838 (you are here), #1765.

In case some of the changes are rejected, I will rebase the subsequent PRs on top of main.

Overview

injectScript now returns the created script element. It can be used to e.g. send messages to the script in the form of custom events. The script can add an event listener for them via document.currentScript. An example of bidirectional communication:

// entrypoints/example.content.ts
export default defineContentScript({
  matches: ['*://*/*'],
  async main() {
    const { script } = await injectScript('/example-main-world.js', {
      modifyScript(script) {
        // Add a listener before the injected script is loaded.
        script.addEventListener('from-injected-script', (event) => {
          if (event instanceof CustomEvent) {
            console.log(`${event.type}:`, event.detail);
          }
        });
      },
    });

    // Send an event after the injected script is loaded.
    script.dispatchEvent(
      new CustomEvent('from-content-script', {
        detail: 'General Kenobi',
      }),
    );
  },
});
// entrypoints/example-main-world.ts
export default defineUnlistedScript(() => {
  const script = document.currentScript;

  script?.addEventListener('from-content-script', (event) => {
    if (event instanceof CustomEvent) {
      console.log(`${event.type}:`, event.detail);
    }
  });

  script?.dispatchEvent(
    new CustomEvent('from-injected-script', {
      detail: 'Hello there',
    }),
  );
});

I made injectScript return an object ({ script }) for future extensibility, in particular for returning the result value of the script.

Manual Testing

Create the files in the example above, add the following to wxt.config.ts, observe the event being logged in the console.

export default defineConfig({
  manifest: {
    web_accessible_resources: [
      {
        resources: ['example-main-world.js;],
        matches: ['*://*/*'],
      },
    ],
  },
});

Related Issue

N/A

Everything seems to work: the script is executed; onload, onerror
handlers do the right thing; document.currentScript invoked by the
script returns the detached script element.
@ion1 ion1 requested review from aklinker1 and Timeraa as code owners August 3, 2025 15:35
Copy link

netlify bot commented Aug 3, 2025

Deploy Preview for creative-fairy-df92c4 ready!

Name Link
🔨 Latest commit 4533614
🔍 Latest deploy log https://app.netlify.com/projects/creative-fairy-df92c4/deploys/688fcd6b722428000886bc61
😎 Deploy Preview https://deploy-preview-1838--creative-fairy-df92c4.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

ion1 added 2 commits August 3, 2025 23:10
It enables the modification of the script element just before it is
added to the DOM.

It can be used to e.g.  modify `script.async`/`script.defer`, add event
listeners to the element, or pass data to the script via
`script.dataset` (which can be accessed by the script via
`document.currentScript`).
The documentation states:

> `injectScript` returns a promise, that when resolved, means the script
> has been evaluated by the browser and you can start communicating with
> it.

However, currently `injectScript` returns as soon as the `script`
element has been added to the DOM.

Make `injectScript` behave according to the documentation.
@ion1 ion1 force-pushed the inject-script-return-script branch 2 times, most recently from 64ffeb3 to 1162b61 Compare August 3, 2025 20:22
It can be used to e.g. send messages to the script in the form of custom
events. The script can add an event listener for them via
`document.currentScript`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant