Blazor.BrowserExtension icon indicating copy to clipboard operation
Blazor.BrowserExtension copied to clipboard

Extension only works when I do a 'refresh'?

Open StefH opened this issue 5 months ago • 8 comments

When I restart my browser, sometimes, or almost all the time, the extension stops working.

  1. I sometimes get error that duplicate menu item is added.

  2. Sometimes I see menu item, but any logic does notwork anymore. Image

You can test it maybe with https://github.com/StefH/Blazor.BrowserExtension/tree/main/BrowserExtension3

StefH avatar Aug 01 '25 19:08 StefH

Based on the official Chrome sample, the ContextMenu.OnClicked.AddListener() is added in the BackgroundWorker Main method, this will make a difference because the extension background worker is shut down after a while and restarted when something wakes the extension like a restart. However, a restart does not invoked the onInstalled event which might explain the context menu not responding until a manual "reload" is performed.

mingyaulee avatar Aug 01 '25 23:08 mingyaulee

This makes sense. I did change this. However when opening a SidePanel, I got this error: sidePanel.open() may only be called in response to a user gesture.

I guess it has something to do with your BackGroundWorker, I tried several things suggested on the internet, however none worked in this solution.

This example works fine: https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/cookbook.sidepanel-open

So I did this:

[BackgroundWorkerMain]
public override void Main()
{
    WebExtensions.Runtime.OnInstalled.AddListener(OnInstalled);

    WebExtensions.Runtime.OnStartup.AddListener(OnStartup);

    WebExtensions.Action.OnClicked.AddListener(OnActionClicked);

    WebExtensions.Runtime.OnMessage.AddListener(OnMessage);
}

private async Task OnInstalled()
{
    // Context menu items should be created when the extension is installed or updated.
    CreateContextMenu();

    // Open the info page as a new tab when the extension is installed.
    _ = await OpenInfoPageAsTabAsync();

    AddOnContextMenuClickedListener();
}

private void OnStartup()
{
    AddOnContextMenuClickedListener();
}

private void AddOnContextMenuClickedListener()
{
    // Adding this is required in 2 places (OnInstalled & OnStartUp) to fix issue: "`sidePanel.open()` may only be called in response to a user gesture."
    WebExtensions.ContextMenus.OnClicked.AddListener(OnContextMenuClicked);
}

This workaround solved it.

StefH avatar Aug 02 '25 08:08 StefH

I believe just moving the OnClicked listener registration would suffice, instead of registering it in both OnInstalled and OnStartup, which may cause the listener to be duplicated if both the events are triggered at the same time.

[BackgroundWorkerMain]
public override void Main()
{
    WebExtensions.ContextMenus.OnClicked.AddListener(OnContextMenuClicked);

    WebExtensions.Action.OnClicked.AddListener(OnActionClicked);

    WebExtensions.Runtime.OnMessage.AddListener(OnMessage);
}

mingyaulee avatar Aug 04 '25 17:08 mingyaulee

1] Context Menu click to open a tab or do something else will work correct.

2] However, opening a side-panel generates this error:

Error: `sidePanel.open()` may only be called in response to a user gesture.

See https://github.com/StefH/Blazor.BrowserExtension/tree/main/BrowserExtension3

That's the reason I register it twice.

Note that a simple javascript service worker like this:

chrome.contextMenus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === 'openSidePanel') {
    // This will open the panel in all the pages on the current window.
    chrome.sidePanel.open({ windowId: tab.windowId });
  }
});

Does work correct!

StefH avatar Aug 04 '25 17:08 StefH

The reason for the difference is likely because when a C# delegate is registered to an event, the event would sometimes require the initialization of dotnet which is asynchronous. When the app is initialized, the user interaction is already in the past. I was considering if we should fully translate the whole BackgroundWorker class to JavaScript because of reasons like this, and also efficiency.

mingyaulee avatar Aug 04 '25 18:08 mingyaulee

Translating the whole Background worker to JavaScript is very difficult I guess.

Maybe add functionality to be able to insert custom javascript-code as the first code in the generated background.js ?

StefH avatar Aug 05 '25 06:08 StefH

If we were to define the JavaScript code in the C# background worker file, it would be difficult to design it well due to strong typing in C#. If we were to write JavaScript code, I think it would be better to do it without mixing it with C# code to keep it clean and readable. Currently I'm more inclined to either translate all, maybe with more custom attributes to opt out of translation for certain methods.

mingyaulee avatar Aug 05 '25 21:08 mingyaulee

Maybe add functionality to be able to insert custom javascript-code as the first code in the generated background.js ?

What I mean by this is just make it possible to write plain javascript in a .js file and insert this file in the generated background. I did not mean writing javascript code in C# and translate this.

StefH avatar Aug 06 '25 05:08 StefH