Skip to content

Sharing of Global Variables simple in Plasmo, impossible in WXT! #1986

@gaurav21r

Description

@gaurav21r

Describe the bug

What we're trying to do

First off thanks for the excellent work. My team and I porting an internal extension from Plasmo. We've already ported 2 more without any hassles however we are stuck onthis one.

This extension adds some automation features to a Whiteboard SDK / website called tldraw.
The website exposes a global variable called editor with which we can do all sorts of things like editor.getSelectedShapes etc.

Reproduction

Simply copying the example from https://wxt.dev/guide/essentials/content-scripts.html#integrated and adding world: 'MAIN option

export default defineContentScript({
  matches: ["https://*.tldraw.com/*"],

  main(ctx) {
    const ui = createIntegratedUi(ctx, {
      position: 'inline',
      anchor: 'body',
      onMount: (container) => {
        // Create a root on the UI container and render a component
        const root = ReactDOM.createRoot(container);
        root.render(<App />);
        return root;
      },
      onRemove: (root) => {
        // Unmount the root when the UI is removed
        root.unmount();
      },
    });

    // Call mount to add the UI to the DOM
    ui.mount();
  },
  world: 'MAIN',
});

Results in an error

Argument of type '{ matches: string[]; main(ctx: any): void; world: "MAIN"; }' is not assignable to parameter of type 'ContentScriptDefinition'.

Also, we can't get the global variable even if we ignore the Typescript error. Its not a timing issue either, we POCed with lots of setTimeouts

I don't quite understand this, from the docs this is the INTEGRATED mode which runs in the same context as the host page.

We need world: 'MAIN' because the editor variable is a global object and not simply a case of sharing the DOM (We are okay with being Chromium only for now)

Trying injectScript

Again according to the docs, we tried inject script and passing round the editor variable through events. Since it is not a DOMSerialzable object, the event object received at our content script has been null

Where to go from here

I don't know if this is a niche use case or not, I think it might not be that far off, but I think the very idea of using world: 'MAIN' is for these use cases. In Plasmo this was a one liner and our content scripts / content script UIs all got access to the top level global variables on the home page.

I have a feeling we are doing somehting conceptually wrong, some guidance would be appreciated @aklinker1 otherwise we'd have to support both WXT & Plasmo internally and we all know the WXT dev exp is so much better :)

Steps to reproduce

No response

System Info

We are running chrome & Edge browsers

System:
    OS: macOS 14.2.1
    CPU: (8) arm64 Apple M1
    Memory: 63.95 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 24.2.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 11.5.2 - /opt/homebrew/bin/npm
    pnpm: 10.14.0 - /opt/homebrew/bin/pnpm
    Watchman: 2025.05.26.00 - /opt/homebrew/bin/watchman
  npmPackages:
    wxt: ^0.20.6 => 0.20.11

Used Package Manager

pnpm

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    pending-triageSomeone (usually a maintainer) needs to look into this to see if it's a bug

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions